Skip to main content

ランナーでの GitHub CLI の使用

継続的インテグレーション (CI) のために高度な GitHub Actions 機能を使用する方法。

注: GitHub ホステッド ランナーは、現在 GitHub Enterprise Server でサポートされていません。 GitHub public roadmap で、今後の計画的なサポートの詳細を確認できます。

サンプルの概要

この記事では、ワークフローの例を使って、GitHub Actions の主な CI 機能の一部を示します。このワークフローがトリガーされると、GitHub Docs サイトに壊れたリンクがあるかどうかを確認するスクリプトが自動的に実行されます。 壊れたリンクが見つかった場合、ワークフローで詳しい情報を含む GitHub のイシューが GitHub CLI を使用して作成されます。

次の図は、ワークフローの手順とジョブ内でそれを実行する方法の概要を示したものです。

ワークフローのステップの概要図

この例で使用されている機能

このワークフロー例は、GitHub Actions の次の機能を示しています。

機能実装
定期的にワークフローを実行する:schedule

ワークフローの例

次のワークフローは、GitHub ドキュメント エンジニアリング チームによって作成されました。 github/docs リポジトリ内でこのファイルの最新バージョンを確認するには、次を参照してください。 check-all-english-links.yml

: このワークフローの各行については、次のセクションの「例の説明」に説明があります。

YAML
name: Check all English links

# **What it does**: This script once a day checks all English links and reports in issues.
# **Why we have it**: We want to know if any links break.
# **Who does it impact**: Docs content.

on:
  workflow_dispatch:
  schedule:
    - cron: '40 19 * * *' # once a day at 19:40 UTC / 11:40 PST

permissions:
  contents: read
  issues: write

jobs:
  check_all_english_links:
    name: Check all links
    if: github.repository == 'github/docs-internal'
    runs-on: ubuntu-latest
    env:
      GITHUB_TOKEN: ${{ secrets.DOCUBOT_READORG_REPO_WORKFLOW_SCOPES }}
      FIRST_RESPONDER_PROJECT: Docs content first responder
      REPORT_AUTHOR: docubot
      REPORT_LABEL: broken link report
      REPORT_REPOSITORY: github/docs-content
    steps:
      - name: Check out repo's default branch
        uses: actions/checkout@v3
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: 16.13.x
          cache: npm
      - name: npm ci
        run: npm ci
      - name: npm run build
        run: npm run build
      - name: Run script
        run: |
          script/check-english-links.js > broken_links.md

      # check-english-links.js returns 0 if no links are broken, and 1 if any links
      # are broken. When an Actions step's exit code is 1, the action run's job status
      # is failure and the run ends. The following steps create an issue for the
      # broken link report only if any links are broken, so `if: ${{ failure() }}`
      # ensures the steps run despite the previous step's failure of the job.

      - if: ${{ failure() }}
        name: Get title for issue
        id: check
        run: echo "::set-output name=title::$(head -1 broken_links.md)"
      - if: ${{ failure() }}
        name: Create issue from file
        id: broken-link-report
        uses: peter-evans/create-issue-from-file@b4f9ee0a9d4abbfc6986601d9b1a4f8f8e74c77e
        with:
          token: ${{ env.GITHUB_TOKEN }}

          title: ${{ steps.check.outputs.title }}
          content-filepath: ./broken_links.md
          repository: ${{ env.REPORT_REPOSITORY }}
          labels: ${{ env.REPORT_LABEL }}
      - if: ${{ failure() }}
        name: Close and/or comment on old issues
        env:
          NEW_REPORT_URL: 'https://github.com/${{ env.REPORT_REPOSITORY }}/issues/${{ steps.broken-link-report.outputs.issue-number }}'
        run: |
          gh alias set list-reports "issue list \
                                       --repo ${{ env.REPORT_REPOSITORY }} \
                                       --author ${{ env.REPORT_AUTHOR }} \
                                       --label '${{ env.REPORT_LABEL }}'"

          # Link to the previous report from the new report that triggered this
          # workflow run.

          previous_report_url=$(gh list-reports \
                                  --state all \
                                  --limit 2 \
                                  --json url \
                                  --jq '.[].url' \
                                  | grep -v ${{ env.NEW_REPORT_URL }} | head -1)

          gh issue comment ${{ env.NEW_REPORT_URL }} --body "⬅️ [Previous report]($previous_report_url)"

          # If an old report is open and assigned to someone, link to the newer
          # report without closing the old report.

          for issue_url in $(gh list-reports \
                                  --json assignees,url \
                                  --jq '.[] | select (.assignees != []) | .url'); do
            if [ "$issue_url" != "${{ env.NEW_REPORT_URL }}" ]; then
              gh issue comment $issue_url --body "➡️ [Newer report](${{ env.NEW_REPORT_URL }})"
            fi
          done

          # Link to the newer report from any older report that is still open,
          # then close the older report and remove it from the first responder's
          # project board.

          for issue_url in $(gh list-reports \
                                  --search 'no:assignee' \
                                  --json url \
                                  --jq '.[].url'); do
            if [ "$issue_url" != "${{ env.NEW_REPORT_URL }}" ]; then
              gh issue comment $issue_url --body "➡️ [Newer report](${{ env.NEW_REPORT_URL }})"
              gh issue close $issue_url
              gh issue edit $issue_url --remove-project "${{ env.FIRST_RESPONDER_PROJECT }}"
            fi
          done

例の説明

次の表では、GitHub Actions ワークフローを作成するときにこれらの各機能がどのように使われるかを説明します。

"コード" 説明
YAML
name: Check all English links

GitHub リポジトリの [アクション] タブに表示されるワークフローの名前。

YAML
on:
  workflow_dispatch:
  schedule:
    - cron: '40 20 * * *' # once a day at 20:40 UTC / 12:40 PST

ワークフローのトリガーとして workflow_dispatchscheduled を定義します。

  • workflow_dispatch を使用すると、UI からこのワークフローを手動で実行できます。 詳細については、「workflow_dispatch」を参照してください。
  • schedule イベントにより、cron 構文を使用して、ワークフローを自動的にトリガーするための一定の間隔を定義できます。 詳細については、「schedule」を参照してください。
YAML
permissions:
  contents: read
  issues: write

GITHUB_TOKEN に付与される既定のアクセス許可を変更します。 これはワークフローのニーズによって異なります。 詳しい情報については、「ジョブへのアクセス許可の割り当て」を参照してください。

YAML
jobs:

ワークフロー ファイルで実行されるすべてのジョブをグループ化します。

YAML
  check_all_english_links:
    name: Check all links

ID check_all_english_links と名前 Check all links を持つジョブを定義します。これは jobs キー内に格納されます。

YAML
if: github.repository == 'github/docs-internal'

リポジトリが docs-internal という名前で、github という Organization 内にある場合のみ、check_all_english_links ジョブを実行します。 それ以外の場合、ジョブは "スキップ済み" としてマークされます。

YAML
runs-on: ubuntu-latest

Ubuntu Linux ランナーで実行するようにジョブを設定します。 これは、ジョブが GitHub によってホストされている新しい仮想マシンで実行されるということです。 他のランナーを使う構文例については、「GitHub Actions のワークフロー構文」を参照してください。

YAML
    env:
      GITHUB_TOKEN: ${{ secrets.DOCUBOT_READORG_REPO_WORKFLOW_SCOPES }}
      REPORT_AUTHOR: docubot
      REPORT_LABEL: broken link report
      REPORT_REPOSITORY: github/docs-content

カスタム環境変数を作成し、組み込み GITHUB_TOKEN 変数を再定義してカスタム シークレットを使用します。 これらの変数は、ワークフローで後から参照されます。

YAML
    steps:

check_all_english_links ジョブの一部として実行されるすべてのステップをグループ化します。 ワークフロー内の各ジョブには、独自の steps セクションがあります。

YAML
      - name: Check out repo's default branch
        uses: actions/checkout@v3

uses キーワードは、actions/checkout という名前のアクションを取得するようにジョブに指示します。 これは、リポジトリをチェックアウトしてランナーにダウンロードし、コードに対してアクション(テストツールなど)を実行できるようにします。 ワークフローがリポジトリのコードに対して実行されるとき、またはリポジトリで定義されたアクションを使用しているときはいつでも、チェックアウトアクションを使用する必要があります。

YAML
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: 16.8.x
          cache: npm

このステップでは、actions/setup-node アクションを使用して、指定したバージョンの node ソフトウェア パッケージをランナーにインストールします。これにより、npm コマンドにアクセスできるようになります。

YAML
      - name: Run the "npm ci" command
        run: npm ci
      - name: Run the "npm run build" command
        run: npm run build

run キーワードは、ランナーでコマンドを実行するようにジョブに指示します。 この場合、Node.js アプリケーションをリポジトリにインストールしてビルドするための個別のステップとして、npm ci コマンドと npm run build コマンドが実行されます。

YAML
      - name: Run script
        run: |
          script/check-english-links.js > broken_links.md

この run コマンドは、リポジトリの script/check-english-links.js に保存されているスクリプトを実行し、出力を broken_links.md というファイルにパイプで渡します。

YAML
      - if: ${{ failure() }}
        name: Get title for issue
        id: check
        run: echo "::set-output name=title::$(head -1 broken_links.md)"

check-english-links.js スクリプトで壊れたリンクが検出され、0 以外 (失敗) の終了状態が返された場合は、ワークフロー コマンドを使用して、broken_links.md ファイルの先頭行の値を持つ出力を設定します (これは次のステップで使用されます)。

YAML
      - if: ${{ failure() }}
        name: Create issue from file
        id: broken-link-report
        uses: peter-evans/create-issue-from-file@b4f9ee0a9d4abbfc6986601d9b1a4f8f8e74c77e
        with:
          token: ${{ env.GITHUB_TOKEN }}

          title: ${{ steps.check.outputs.title }}
          content-filepath: ./broken_links.md
          repository: ${{ env.REPORT_REPOSITORY }}
          labels: ${{ env.REPORT_LABEL }}

peter-evans/create-issue-from-file アクションを使用して、新しい GitHub のイシューを作成します。 この例は、b4f9ee0a9d4abbfc6986601d9b1a4f8f8e74c77e SHA を使用して、特定のバージョンのアクションに合わせて固定されています。

YAML
      - if: ${{ failure() }}
        name: Close and/or comment on old issues
        env:
          NEW_REPORT_URL: 'https://github.com/${{ env.REPORT_REPOSITORY }}/issues/${{ steps.broken-link-report.outputs.issue-number }}'
        run: |
          gh alias set list-reports "issue list \
                                       --repo ${{ env.REPORT_REPOSITORY }} \
                                       --author ${{ env.REPORT_AUTHOR }} \
                                       --label '${{ env.REPORT_LABEL }}'"
          previous_report_url=$(gh list-reports \
                                  --state all \
                                  --limit 2 \
                                  --json url \
                                  --jq '.[].url' \
                                  | grep -v ${{ env.NEW_REPORT_URL }} | head -1)

          gh issue comment ${{ env.NEW_REPORT_URL }} --body "⬅️ [Previous report]($previous_report_url)"

gh issue list を使用して、以前の実行から以前に作成したイシューを見つけます。 これには、後のステップでの処理を簡単にするために、gh list-reports という別名が付けられます。 イシューの URL を取得するために、jq 式で結果の JSON 出力を処理します。

次に gh issue comment を使用して、以前のイシューにリンクするコメントを新しいイシューに追加します。

YAML
          for issue_url in $(gh list-reports \
                                  --json assignees,url \
                                  --jq '.[] | select (.assignees != []) | .url'); do
            if [ "$issue_url" != "$" ]; then
              gh issue comment $issue_url --body "➡️ [Newer report]($)"
            fi
          done

以前の実行でのイシューが未解決であり誰かに割り当てられている場合は、gh issue comment を使用して、新しいイシューへのリンクを含むコメントを追加します。

YAML
          for issue_url in $(gh list-reports \
                                  --search 'no:assignee' \
                                  --json url \
                                  --jq '.[].url'); do
            if [ "$issue_url" != "${{ env.NEW_REPORT_URL }}" ]; then
              gh issue comment $issue_url --body "➡️ [Newer report](${{ env.NEW_REPORT_URL }})"
              gh issue close $issue_url
              gh issue edit $issue_url --remove-project "${{ env.FIRST_RESPONDER_PROJECT }}"
            fi
          done

以前の実行でのイシューが未解決であり誰にも割り当てられない場合は、次のようになります。

  • gh issue comment を使用して、新しいイシューへのリンクを含むコメントを追加します。
  • gh issue close を使用して以前のイシューを閉じます。
  • gh issue edit を使用して以前のイシューを編集し、特定の GitHub プロジェクト ボードから削除します。

次の手順