Open17

GitHub Actions の JavaScript Action

hankei6kmhankei6km

Container と JavaScript が選べるが軽く調べた感じだと JavaScript Action で大丈夫そうだったので JavaScript で試す。
だめだったら Container にする。

hankei6kmhankei6km

リポジトリ内でコードのファイルがそろっていれば良さそうなのとTypeScript でコードを記述したかったので rollup.js を使ってみたらエラーになる。

エラー
./src/index.ts → ./dist/index.js...
(!) Circular dependencies
node_modules/@actions/core/lib/core.js -> node_modules/@actions/core/lib/oidc-utils.js -> node_modules/@actions/core/lib/core.js
node_modules/@actions/core/lib/core.js -> node_modules/@actions/core/lib/oidc-utils.js -> /home/node/tmp/collect-labels-from-release-note/node_modules/@actions/core/lib/core.js?commonjs-proxy -> node_modules/@actions/core/lib/core.js

[!] Error: 'default' is not exported by node_modules/node-fetch/node_modules/tr46/lib/mappingTable.json, imported by /home/node/tmp/collect-labels-from-release-note/node_modules/node-fetch/node_modules/tr46/lib/mappingTable.json?commonjs-proxy
https://rollupjs.org/guide/en/#error-name-is-not-exported-by-module
/home/node/tmp/collect-labels-from-release-note/node_modules/node-fetch/node_modules/tr46/lib/mappingTable.json?commonjs-proxy (1:8)

ドキュメントでは '@vercel/ncc` を使っていたので今回はそれに従う。

node_modules ディレクトリをチェックインすると、問題が発生する可能性があります。 別の方法として、@vercel/ncc というツールを使用して、コードとモジュールを配布に使用する 1 つのファイルにコンパイルできます。

https://docs.github.com/ja/actions/creating-actions/creating-a-javascript-action#commit-tag-and-push-your-action-to-github

いちおう動くようになった。

hankei6kmhankei6km

ビルドしたものもリポジトリに含める必要がある。

できれば含めたくないのだけど無理そうかな。

hankei6kmhankei6km

Action は ESM でも動いた。

Node.js の 16.x を指定して動かすからそうだと言われればそうかと。

ncc でのビルド時に 以下の定義のみのdist/package.jsonが作成される。

package.json
{
  "type": "module"
}
hankei6kmhankei6km

テストの書き方。

モジュールに切り出している部分は普通にユニットテストでできる。

action.ymlmain に設定している部分はビルドされたファイルを Node.js のスクリプトとして実行する。
入力(with)については環境変数(process.env)で INPUT_入力名を大文字 を設定することでわたせる。

この場合の問題はモックが使えない(と思う)。よって octokit での通信などはテストできない(こともないが、後述のワークフローでのテストにまかせた方が環境に左右されにくい)

メイン部分の処理をモジュールにしておくことで対応できるが、
サンプルを見た感じでは「実際に Node.js のスクリプトとして動作している状況」でテストすることが主題に感じる。

https://github.com/actions/javascript-action/blob/main/index.test.js

よって、自分用に作るものはモックを必要としない部分のみのテストに限定する。

通信などが必要な部分は実際にワークフローを使ってのテストを記述する。

hankei6kmhankei6km

上記対応や top-level await などで tsconfig.json は以下のような感じなっている。

この辺は、おそらく Action としての要件はなく、using に指定している Node.js に依存すると思う。

tsconfig.json
{
  "compilerOptions": {
    "target": "es2020",
    "module": "es2022",
    "lib": ["ESNext"],
    "moduleResolution": "node",
    "strict": true,
    "skipLibCheck": true,
    "declaration": true,
    "pretty": true,
    "newLine": "lf",
    "outDir": "build",
    "esModuleInterop": true,
    "allowJs": true
  },
  "exclude": ["node_modules", "src/**/*.test.ts"],
  "include": ["src/**/*.ts", "test/**/*.ts"]
}
hankei6kmhankei6km

inputrequired を付けているものをフローで指定しない場合でもとくにエラーにならない。
値としてはブランクを渡されているもよう。

default の値が影響しているのかと思い default を外してみたけど変わらず。

コード側でチェックしていからよいけど、使い方間違えている?

action.yml
inputs:
  repository:
    description: 'Repository name(owner/name)'
    required: true
    default: ''
hankei6kmhankei6km

その後、Google Drive 用の Action などを作ってみたところ、いくつか追記したいところが出てきたので reopen。

ビルドとタグ

リポジトリにビルドしたコードを含むのは避けたいと考えていた。また、Action を特定するためのタグはメジャーバージョン、マイナーバージョンのものが欲しくなった。

その辺の対応は公式のドキュメントに記述があった。

https://docs.github.com/en/actions/creating-actions/releasing-and-maintaining-actions#setting-up-github-actions-workflows

具体的にはこのワークフロー を参考にJasonEtco/build-and-tag-action を使うと解決できる。

この Action では以下のことを実施してくれる。

  • バンドルされた dist/index.js(package.jsonmain で指定したファイル)と action.yml のみのコミットを作成
  • 上記コミットに対して v1 v1.1 v1.1.1 のようなタグを付ける

便利なのだが、Action の作り方によっては少し対応が必要。

hankei6kmhankei6km

nativeESM

モジュールとして packge.json を設定していた場合、ncc は最低限必要な dist/package.json作成する。しかし JasonEtco/build-and-tag-action では dist/package.json をコミットに含めない。

これは dist/index.jsdist/index.mjsmv することで対応。

hankei6kmhankei6km

licenses.txt

JavaScript Action 作成の手順では licenses.txt を作成してリポジトリに含めるようになっている

しかし、このファイルもタグ付けされたコミットには含まれない。

バンドルしたファイルのライセンス表示は含めたいので暫定的に以下のように対応。

  • licenses.txt をリリースの assets へアップロード
  • dist/index.mjs にライセンスバナーを追加しその中にリンクを含める
      - name: Make licenses.zip file
        run: zip "./licenses.zip" dist/licenses.txt

      - name: Upload licenses.zip file to release Asset
        id: upload-release-asset
        uses: shogo82148/actions-upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ github.event.release.upload_url }}
          asset_path: ./licenses.zip
          asset_name: licenses.zip
          asset_content_type: application/zip

      - name: Prepend license banner into dist/index.mjs
        run: |
          bash scripts/license-banner.sh "${DOWNLOAD_URL}" | cat - dist/index.mjs > tmp.txt
          mv tmp.txt dist/index.mjs
        env:
          DOWNLOAD_URL: ${{ steps.upload-release-asset.outputs.browser_download_url }}

構文を考慮しないで実行コードを書き換えているのでできれば避けたいところだけど。。。

あとは直接関係ないけれど、actions/upload-release-asset が Archived になっていたので、shogo82148/actions-upload-release-asset を利用させていただく。

とはいっても inputs はそのままで動作したので uses を変更しただけ。

hankei6kmhankei6km

README.md の自動生成

Action の README は大まかにフォーマットが提示されていて、内容的には action.yml からコピペでだいたい記述できる。

https://docs.github.com/ja/actions/creating-actions/creating-a-javascript-action#creating-a-readme

が、inputs が増えてくると非常に手間がかかるので、以下を利用させていただく。

https://github.com/npalm/action-docs

Action 版もあるのだけど、手元で確認しながら実行したかったので通常版(?) を利用。

また、README.md 全体生成するようになっているのだけど、action.yml にはない情報(利用する環境変数など)を手動で追記したかったので、別途テンプレートを作成して合成するようにしてある。

hankei6kmhankei6km

README.md をビルドしてリポジトリに含める」ことになるので「ビルド漏れ」が生じる可能性がある(というか、実際に結構忘れて頭をかかえた)。

テスト用のワークフローに以下を追加した。

      - name: Diff built files
        run: |
          git diff --exit-code --quiet README.md

ビルドを忘れているとテストが落ちる。

hankei6kmhankei6km

Marketplace への公開

基本的には以下の手順通り。

https://docs.github.com/ja/actions/creating-actions/publishing-actions-in-github-marketplace

少しハマったところなど。

同意

Select Publish this action to the GitHub Marketplace. If you can't select the Publish this action to the GitHub Marketplace checkbox, you'll need to read and accept the GitHub Marketplace agreement first.

手順通りの流れで全文を表示させると小さいポップアップで表示されるので、
事前に「GitHubマーケットプレイス契約」などで検索して見ておいた方がよい。

branding

action.ymlbranding も事前に記述してコミットしておいた方が楽。

https://docs.github.com/ja/actions/creating-actions/metadata-syntax-for-github-actions#branding

tag を push するだけ

あらかじめリリースを作成してしまうとその tag は使えないので、公開するときは tag を push するだけにする。

バージョンを上げるときの手順は見当たらない。実際に上げるときに要確認。

hankei6kmhankei6km

Markplace で更新

公開してある Action を更新してみた。

  1. 更新時はリポジトリで普通にリリースを作成
  2. ウェブ UI でリリースの編集画面を開く
  3. Publish this Action to the GitHub Marketplace にチェック付いていることを確認し
  4. Update Release をクリック

これで Markerplace の方に新しいリリースが反映される(リポジトリのリリースにも Marketplace のラベルのようなものが表示される)。