GitHub Actionsの作り方【Node.js編】

この記事は、[GitHub Actions Advent Calendar 2023](https://qiita.com/advent-calendar/2023/github-actions) の25日目です。

この記事では、Node.jsを使用してGitHub Actionsを作成する方法を解説します。

# 準備
### リポジトリを作成
名前に制約はありません。
作成したら、`npm init` しておきましょう。

### `action.yaml` を作成
拡張子は `.yml` でも `.yaml` でも構いません。リポジトリのルートに置いておく必要があります。

```yaml
name: 'Sample Action'  # Actionの名前
description: 'This is sample.'  # Actionの説明

runs:
  using: 'node16'  # どのNode.jsを使用するか指定
  main: 'dist/index.js'  # Actionのメインファイル。このファイルは後で自動生成させるのでこのままで大丈夫です。

branding:  # Marketplaceでの表示を指定
  icon: 'check-square'
  color: 'green'
```

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

### READMEを作成
Marketplaceで表示されます。
使い方はここに書くかドキュメントへのリンクを貼りましょう。
※勿論最後に書いても問題ありません

# 作成
カタカタと書き進めていきます。リポジトリの構造は基本的に自由ですが、ソースは `src` ディレクトリにまとめておいた方が良いでしょう。

### パッケージをインストール
`@actions/core`: ほぼ必須と言っても過言ではありません。Inputの取得や終了ステータス・ログの設定などを行います。
`@actions/github`: 同じくほぼ必須。Actionがどのような状態で実行されたのかであったり、リポジトリの基本的な情報を取得するのに必要です。

`@vercel/ncc`: Actionのファイルを生成するのに使います。開発でしか使用しないので `devDependencies` にしておきましょう。このパッケージが必要な理由については後述します。

# ビルド
GitHub Actionsでは、それがNode.jsで作られたものであっても外部のパッケージ (`node_modules`に入るもの) を自動的にダウンロードしてくれたりはしません。リポジトリ内のファイルのみで動かします。
`node_modules` をリポジトリに入れるという方法もなくはないですが、避けるべきでしょう。
ここで先ほどのnccの登場です。これを使うことで、依存しているパッケージも1つのファイルに含めてくれます。いちいち手打ちするのも面倒ですし、`package.json` に登録してしまいましょう。

```json:package.json
{
  "scripts": {
    "build": "ncc build ./src/index.js --license license.txt -o dist"
  }
}
```

`./src/index.js` の部分は自分の環境に合わせてください。
他のパッケージのファイルも含めているのでライセンス一覧を生成しています。ライセンスには細心の注意を払いましょう。
`ncc build` にオプションとして `-o dist` を渡しています。これで `dist` ディレクトリにファイルが生成されます。

## GitHub Actionsにビルドを任せよう
```yaml:.github/workflows/build.yaml
name: Build
on:
  workflow_dispatch:
    inputs:
      release:
        description: 'Create a release build'
        required: false
        type: boolean

  push:
    branches:
      - 'main'
    paths:
      - '.github/workflows/**'
      - 'src/**'
      - 'action.yaml'
      - 'package-lock.json'

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Cache node_modules
        uses: actions/cache@v3
        with:
          path: 'node_modules'
          key: node-${{ hashFiles('package-lock.json') }}
          restore-keys: node-

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '16.x'
      - name: Create release build
        if: ${{ inputs.release }}
        run: |
          npm install
          npm run build
      - name: Create debug build
        if: ${{ !inputs.release }}
        run: |
          git config --global user.email "action@github.com"
          git config --global user.name "Github Actions"
          git fetch origin build
          git switch build
          git merge main
          npm install
          npm run build
      - name: Push to GitHub
        uses: EndBug/add-and-commit@v9.1.1
        with:
          add: '-f ./dist'
          author_name: 'GitHub Actions'
          author_email: 'action@github.com'
          message: 'build: Build action'
```

デバッグビルドとリリースビルドで分けています。
デバッグビルドはpush毎に実行し、`build` ブランチに成果物を送っています。
リリースビルドは下の画像のように `workflow_dispatch` で行うようにしています。

![dispatch_action.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1402976/c9e79ed1-5778-9fc6-8234-71b3c71d8790.png)

# リリース
タグを付けてpushし、GitHubのリリースページからリリースを作成します。
GitHub Actionのリポジトリでリリースを作成するときは、作成画面に `Publish this Action to the GitHub Marketplace` とチェックボックスがあるのでチェックを入れます。
これを公開して完了です。