LoginSignup
29
13

More than 3 years have passed since last update.

GitHubコメントを実行してあらゆることを自動化するGitHub Actions

Last updated at Posted at 2020-03-09

やりたいこと

GitHubのissueやプルリクエストのコメントに任意のスクリプトを書いてGitHub Actionsで実行したいです。

これができると色々と自動化できます。

例えば、

  • プルリクをマージした時のプレビュー
  • npmのパッケージをアップデートして自動でプルリク
  • SSHでGitHub Actions内に入ってデバッグ
  • Python/Ruby/Go/Deno/Scala .... 任意言語の実行
  • LGTMの画像をコメント
  • ... などなどアイデア次第でGitHubコメントする手軽さであらゆることを自動化できます。 npmでもaptでもpipでもgitでも色々コメントからGitHub完結で実行できます。

できたもの

comment-runと呼んでます。
GitHub: https://github.com/nwtgck/actions-comment-run
上記のREADMEにここで紹介するいくつかの実行可能なコメントを載せています。コピペしたい時に便利です。

自分のリポジトリにcomment-runを導入する

.github/workflows/comment-run.ymlとして以下を設置するだけです。

.github/workflows/comment-run.yml

name: "Comment run"
on:
  issue_comment:
    types: [created, edited]

jobs:
  comment-run:
    runs-on: ubuntu-18.04
    steps:
    - uses: actions/checkout@v2
      with:
        # 0 indicates all history
        fetch-depth: 0
    - uses: nwtgck/actions-comment-run@v1.0
      with:
        github-token: ${{ secrets.GITHUB_TOKEN }}
        allowed-associations: '["OWNER"]' 

以下でコマンドをリポジトリのルートで叩けば一発で導入できます。

mkdir -p .github/workflows/ && cd .github/workflows/ && wget https://gist.githubusercontent.com/nwtgck/a9b291f6869db42ecc3d9e30d0a0494c/raw/comment-run.yml && cd -

pushすれば自動導入されます。GitHub側で設定することは特にないです。

comment-runを使ってみる

まず新しくissueを立てます。(既存のissueでもOKです。)
その中で以下のようにコメントしてみます。

以下はコピペ用です。書き始めを@github-actions runにします。```jsのコードブロック内が実行できます。

@github-actions run

```js
console.log("hello, world");
```

つぎに以下のActionsタブを開いて、
image.png

以下のように"hello, world"が出ているのがわかります。

image.png

LGTM画像をコメントしよう

もう少し使えそうな使用例の紹介です。
以下のコメントでLGTM.in/gからランダムで画像がコメントされます。
image.png
実際のコメント:https://github.com/nwtgck/actions-comment-run/pull/1#issuecomment-596302174
コメント内でdetailsタグを使えばすっきりと自動化のコメントを投稿できます。

よく使うコメントをGitHubに覚えさせる

GitHubにはSaved repliesという機能があり(@peaceiris氏に教えてもらいました)、
これでcomment-run用のコメントを覚えさせると自動化が捗ります。

Saved repliesの記憶のさせ方は、
まず以下のSettingsに行きます。
image.png

そして、Saved repliesを選んで記憶させたいものを記入できます。
image.png

覚えさせたコメントを使いたいときは、
以下のコメント投稿欄の右上にある「↖️」アイコンを押すと選べます。
image.png

npmパッケージを更新して自動でプルリクを作る

使用例です。
Dependabotは便利ですが、大量に更新があるときにまとめて更新してくれると助かることがあります。更新の自動プルリク作成がGitHub完結で行えます。
以下のマークダウンのコメントを投稿するだけです。



@github-actions run

```js
function exec(cmd) {
  console.log(execSync(cmd).toString());
}

// Config
const baseBranchName = context.payload.repository.default_branch;
const gitUserEmail = "github-actions[bot]@users.noreply.github.com";
const gitUserName = "github-actions[bot]";
const prBranchName = "comment-run/npm-update";

exec(`git config --global user.email "${gitUserEmail}"`);
exec(`git config --global user.name "${gitUserName}"`);
exec(`git fetch --all`);
exec(`git checkout ${baseBranchName}`);
exec(`git checkout -b ${prBranchName}`);

const pakcageJson = JSON.parse(require('fs').readFileSync('package.json'));
const depStr = Object.keys(pakcageJson.dependencies || {}).join(' ');
const devDepStr = Object.keys(pakcageJson.devDependencies || {}).join(' ');
exec(`npm i ${depStr} ${devDepStr}`);

exec("git status");
exec("git add package*json");
exec(`git commit -m "chore(deps): update npm dependencies"`);
exec(`git push -fu origin ${prBranchName}`);

(async () => {
  await githubClient.pulls.create({
    base: baseBranchName,
    head: prBranchName,
    owner: context.repo.owner,
    repo: context.repo.repo,
    title: "chore(deps): update npm dependencies",
    body: "update npm dependencies",
  });
})();
```

以下のように自動でプルリクを作ってくれます。
image.png
上記のコードをちょっと変えればコミットメッセージやプルリクのタイトルを日本語にしたりできます。

この自動プルリクの可能性は、npmに限らずあらゆるパッケージマネージャや自動化ツールと連携してローカル環境に行かずに自動でプルリクエストできるところだと思います。
具体的には上記のコードのexec(`npm i ${depStr} ${devDepStr}`)の部分を他のコマンドに変えれば良いでしょう。例えばVue CLIを使っている人ならvue upgradeしたやつをプルリクしてくれるのは便利かなと思います。

プルリクをマージした時のプレビュー用のブランチを作る

comment-runの使用例です。
GitHub Actionsはセキュリティ上Secretsをforkした人が作ったプルリクには渡さないようにしています。(トークンとかがメンテナ以外が見れたりすると危険ですからね。)
それだとSecretsなしのGitHub Actionsしか実行できず機能的に制限されてしまいます。これが、それを解決するための一つの方法になります。
メンテナがプルリクエストのコードを見て問題ないときは以下の@github-actions run ...を実行するとマージした時のブランチを適当な名前でpushしてくれます。そのpushされたブランチへのURLが自動でコメントされます。
そのpushされたブランチではSecretsが引き渡された他のGitHub Actionsが動いてくれたりします。

image.png
実際のコメント: https://github.com/nwtgck/actions-comment-run/pull/2#issuecomment-596354791
コードがほしいときは「実際のコメント」に飛んで取得できます。

comment-runのセキュリティ的な話

コメントしたリポジトリにadmin/write権限のあるユーザーのみが実行できるようになっています。

それに加え、デフォルトでは@github-actions runでコメントを実行できるのはOWNERだけになっています。
例えば、最初の設定のYAMLでallowed-associations: '["OWNER", "MEMBER"]'に変更すればMEMBERも@github-actions runも実行できるようになります。
organizationに参加している人はMEMBERだったりします。

他には以下の値を取りうるはずです。

  • COLLABORATOR
  • CONTRIBUTOR
  • FIRST_TIMER
  • FIRST_TIME_CONTRIBUTOR
  • MEMBER
  • NONE
  • OWNER

(参考: https://developer.github.com/v4/enum/commentauthorassociation/)

comment-runの環境は通常のGitHub Actionsの実行環境と同じだけの能力があります。つまりGitHub Actionsを書くときと同じように@github-actions runコメントを注意して書く必要があります。GitHub Actions用のGitHubのトークンが使えるのでそのリポジトリに対してのwrite権限があります。GitHub Actions用の秘密にすべき環境変数を設定している場合は表示しないように気をつけましょう。

SSHしてGitHub Actions内に入る

comment-runの使用例に戻ります。
頑張ってSSHする方法は色々あると思います。ここでは @Cryolite氏提案の「Piping Server を介した双方向パイプによる,任意のネットワークコネクションの確立 - Qiita」で紹介されていた方法を使います。

コメントを実行すると"New SSH session"というコメントが自動で投稿されそこに書かれているコマンドを別々のターミナルで実行するとSSHできます。
image.png
コードがほしいときは、実際のコメント: https://github.com/nwtgck/actions-comment-run/pull/2#issuecomment-596020242

SSHで入った様子は以下のような感じです。

SSHデバッグ専用のGitHub Actionsならhttps://github.com/mxschmitt/action-tmateが有名だと思います。
上記のcomment-runも改良すればtmateを使った方法にできると思います。専用のActionsを使わずにcomment-runを一つ導入するだけで色々できるところが魅力です。

comment-runは複数のコードブロック、任意の言語が実行できる

例えばGitHub Actionsの環境でpipが使えます。
以下のようにpipでnumpyをインストールしてPythonが実行できます。

重要なことは「comment-runはJavaScriptとshebang(#!から始まるやつ)に対応している」ということです。JavaScript以外には一つずつ言語に対応せずにshebangに対応するだけでシンプルさを保っています。shebangに対応するあらゆる言語などを実行できます。もう少し色んな言語を動かす例を見ていきます。

Denoを動かす

以下がDenoを動かす例です。

実際のコメント: https://github.com/nwtgck/actions-comment-run/pull/1#issuecomment-596170740
npmと違ってライブラリをURLでimportできるところがcomment-runとの相性が良さそうなところです。

Goを動かす

以下でGo言語が動きます。

実際のコメント: https://github.com/nwtgck/actions-comment-run/pull/1#issuecomment-596176678
残念ながらgo runはshebangに対応しておらずgorunを使います。

Haskellを動かす

以下でHaskellが動きます。

実際のコメント: https://github.com/nwtgck/actions-comment-run/pull/1#issuecomment-596176131

Scalaを動かす

以下でAmmoniteを使ってScalaを動かします。Denoと同じでbuild.sbtなどを使うのと違い他のライブラリを一つのファイルでimportしやすくcomment-runと相性が良いと思います。

実際のコメント: https://github.com/nwtgck/actions-comment-run/pull/1#issuecomment-596180626

comment-runはコードブロックをシーケンシャルに実行する

comment-runの仕様の話です。
comment-runは```jsのコードブロックと shebang(#!のやつ) があるコードブロックを上から下へシーケンシャルに一つずつ実行します。

内部的には```jsはJavaScript Actionの環境でeval()します。そのためcomment-runのJavaScript Actionの環境にある変数が利用できます。(利用できることを保証している変数に関してはのちに追記したいと思います)
shebangが付いているものは一時ファイルとして保存して、実行権限をつけて実行します。

ソースコードとしてGistやGitHubで管理したい

いろんな言語が動くというcomment-runの可能性を提示しましたが、JavaScriptを使うのが一番comment-runと相性がいいです。GitHubにコメントしたりtokenが使えるのはJavaScriptの環境だからです(環境変数やファイル経由で他の言語に引き渡す手はあると思います)。

そこで、
だんだんとロジックが複雑になるとソースコードとしてちゃんと管理したくなります。そこで簡単にGistで管理するTIPSです。

単純にGistに保存してそれをfetch()してeval()で実行するだけです。GitHubでもRawを押してコードのURLを使えばGitHubでもこの方法を使うことができます。
image.png
Gist: https://gist.githubusercontent.com/nwtgck/c8accac2bcd9939a6604a3500247012d/raw/comment-run-merge-preview.js

既存のnpmパッケージ利用とTypeScript利用したいしちゃんとコード管理したい

だいぶ欲張りですが全部叶えたいです。

まず既存のnpmパッケージを利用したいです。例えば以下のようにnpm i -S ...好きにパッケージを入れられます。
image.png

この方法は短い実行コメントの時や初期だと良いと思います。実行コメントが育ってきてだいぶ使ってきて動作が安定してきたら、ちゃんと依存関係を固定したり毎回npm iが走る時間を削減したくなってきます。
また、実行コメントが成長してくると、複雑なロジックやAPIなどの変化に強くするためにも型が欲しくなってきてTypeScriptで書きたくなってきます。
なおかつ、ソースコードを管理して他の人や再利用や改善がしやすい方法の紹介です。

仕組みとしてはTypeScriptで書いてnccでbundleしてできた.jsをGitHub Pagesにホストします。

利用する時は以下のようにGitHub Pagesからfetch()して使います。



@github-actions run

```js
(async () => {
  const url = "https://nwtgck.github.io/comment-run-scripts/hello-world-comment.js";
  const js = await (await fetch(url)).text();
  eval(js);
})();
```

peaceiris/actions-gh-pagesでビルド後の.jsをGitHub Pagesにホストすることで、通常のTypeScript Actionのようにビルド結果をGit管理する必要がなくなることも利点です。

ソースコードはここにhttps://github.com/nwtgck/comment-run-scriptsあります。同じ用途でも個人でカスタマイズしたい場合やセキュリティ的な関係で自分の管理下のGitHub Pagesにしたい場合などは利用者はforkして運用するのがいいかなと思っています。

ディレクトリ構成は./hello-world-commentや./merge-previewなどがリポジトリ直下にあり、それらは独立したnpmパッケージなっています。各ディレクトリに入って好きにnpm i することができます。

comment-runで利用可能なことを保証しているJavaScriptの変数

以下のREADMEにまとめました。
https://github.com/nwtgck/actions-comment-run/tree/6bea6fb49b8a3e2253f5e2e9ebfded12caf17113#available-variables-in-the-js-comment-context

29
13
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
13