Skip to main content

실행기에서 GitHub CLI 사용

CI(연속 통합)를 위해 고급 GitHub Actions 기능을 사용하는 방법입니다.

예제 개요

이 문서에서는 예제 워크플로를 사용하여 GitHub Actions의 주요 CI 기능 중 일부를 보여 줍니다. 이 워크플로가 트리거되면 GitHub Docs 사이트에 끊어진 링크가 있는지 여부를 확인하는 스크립트가 자동으로 실행됩니다. 끊어진 링크가 있으면 워크플로는 GitHub CLI에서 세부 정보를 사용하여 GitHub 이슈를 만듭니다.

다음 다이어그램에서는 워크플로의 단계와 작업 내에서 실행되는 방법에 대한 개략적인 보기를 보여 줍니다.

GitHub CLI을(를) 사용하여 문제를 만드는 워크플로를 트리거하는 이벤트의 다이어그램입니다.

이 예제에서 사용되는 기능

예제 워크플로는 GitHub Actions의 다음 기능을 보여 줍니다.

기능구현
정기적으로 워크플로 실행schedule
토큰에 대한 사용 권한 설정permissions
특정 조건이 충족되지 않는 한, 작업 실행 방지if
워크플로에서 비밀 참조비밀
리포지토리를 실행기로 복제하는 중actions/checkout
실행기에 node 설치actions/setup-node
타사 작업 사용:peter-evans/create-issue-from-file
실행기에서 스크립트 실행:script/check-english-links.js 사용
출력 파일 생성:> 연산자를 사용하여 출력 파이핑
GitHub CLI을(를) 사용하여 기존 이슈 확인:gh issue list
GitHub CLI을(를) 사용하여 이슈에 주석 달기:gh issue comment

예시 워크플로

다음 워크플로는 GitHub Docs Engineering 팀에서 만들었습니다. github/docs 리포지토리에서 이 파일의 최신 버전을 검토하려면 다음을 참조하세요. check-all-english-links.yml.

다음 워크플로는 모든 영어 링크를 하루에 한 번 검사하여 문서 콘텐츠 팀이 검토할 DOC의 새 이슈를 만들어 끊어진 링크를 보고합니다.

YAML
name: Check all English links

이렇게 하면 GitHub 리포지토리의 "작업" 탭에 표시되는 워크플로의 이름이 정의됩니다.

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

Defines the workflow_dispatch and scheduled as triggers for the workflow.

The workflow_dispatch event lets you manually run this workflow from the UI. For more information, see workflow_dispatch.

The schedule event lets you use cron syntax to define a regular interval for automatically triggering the workflow. For more information, see schedule.

permissions:
  contents: read
  issues: write

Modifies the default permissions granted to GITHUB_TOKEN. This will vary depending on the needs of your workflow. For more information, see "작업에 권한 할당."

jobs:

Groups together all the jobs that run in the workflow file.

  check_all_english_links:
    name: Check all links

Defines a job with the ID check_all_english_links, and the name Check all links, that is stored within the jobs key.

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

Only run the check_all_english_links job if the repository is named docs-internal and is within the github organization. Otherwise, the job is marked as skipped.

    runs-on: ubuntu-latest

Configures the job to run on an Ubuntu Linux runner. This means that the job will execute on a fresh virtual machine hosted by GitHub. For syntax examples using other runners, see "GitHub Actions에 대한 워크플로 구문."

    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

Creates custom environment variables, and redefines the built-in GITHUB_TOKEN variable to use a custom secret. These variables will be referenced later in the workflow.

    steps:

Groups together all the steps that will run as part of the check_all_english_links job. Each job in the workflow has its own steps section.

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

The uses keyword tells the job to retrieve the action named actions/checkout. This is an action that checks out your repository and downloads it to the runner, allowing you to run actions against your code (such as testing tools). You must use the checkout action any time your workflow will run against the repository's code or you are using an action defined in the repository.

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: 16.13.x
          cache: npm

This step uses the actions/setup-node action to install the specified version of the node software package on the runner, which gives you access to the npm command.

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

The run keyword tells the job to execute a command on the runner. In this case, the npm ci and npm run build commands are run as separate steps to install and build the Node.js application in the repository.

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

This run command executes a script that is stored in the repository at script/check-english-links.js, and pipes the output to a file called broken_links.md.

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

If the check-english-links.js script detects broken links and returns a non-zero (failure) exit status, then use a workflow command to set an output that has the value of the first line of the broken_links.md file (this is used the next step).

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: Create issue from file
        id: broken-link-report
        uses: peter-evans/create-issue-from-file@ceef9be92406ace67ab5421f66570acf213ec395
        with:
          token: ${{ env.GITHUB_TOKEN }}
          title: ${{ steps.check.outputs.title }}
          content-filepath: ./broken_links.md
          repository: ${{ env.REPORT_REPOSITORY }}
          labels: ${{ env.REPORT_LABEL }}

Uses the peter-evans/create-issue-from-file action to create a new GitHub issue. This example is pinned to a specific version of the action, using the ceef9be92406ace67ab5421f66570acf213ec395 SHA.

      - 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)

Uses gh issue list to locate the previously created issue from earlier runs. This is aliased to gh list-reports for simpler processing in later steps.

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

gh issue comment is used to add a comment to the new issue that links to the previous one.

          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
          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 }})"

If an issue from a previous run is open and assigned to someone, then use gh issue comment to add a comment with a link to the new issue without closing the old report. To get the issue URL, the jq expression processes the resulting JSON output.

If an issue from a previous run is open and is not assigned to anyone, use gh issue comment to add a comment with a link to the new issue. Then use gh issue close and gh issue edit to close the issue and remove it from the project board.

              gh issue close $issue_url

Use gh issue close to close the old issue.

              gh issue edit $issue_url --remove-project "${{ env.FIRST_RESPONDER_PROJECT }}"
            fi
          done

Use gh issue edit to edit the old issue and remove it from a specific GitHub project board.

# 이렇게 하면 GitHub 리포지토리의 "작업" 탭에 표시되는 워크플로의 이름이 정의됩니다.
name: Check all English links

# Defines the `workflow_dispatch` and `scheduled` as triggers for the workflow.
#
# The `workflow_dispatch` event lets you manually run this workflow from the UI. For more information, see [`workflow_dispatch`](/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch).
#
# The `schedule` event lets you use `cron` syntax to define a regular interval for automatically triggering the workflow. For more information, see [`schedule`](/actions/using-workflows/events-that-trigger-workflows#schedule).
on:
  workflow_dispatch:
  schedule:
    - cron: '40 19 * * *' # once a day at 19:40 UTC / 11:40 PST

# Modifies the default permissions granted to `GITHUB_TOKEN`. This will vary depending on the needs of your workflow. For more information, see "[AUTOTITLE](/actions/using-jobs/assigning-permissions-to-jobs)."
permissions:
  contents: read
  issues: write

# Groups together all the jobs that run in the workflow file.
jobs:
  # Defines a job with the ID `check_all_english_links`, and the name `Check all links`, that is stored within the `jobs` key.
  check_all_english_links:
    name: Check all links
    # Only run the `check_all_english_links` job if the repository is named `docs-internal` and is within the `github` organization. Otherwise, the job is marked as _skipped_.
    if: github.repository == 'github/docs-internal'
    # Configures the job to run on an Ubuntu Linux runner. This means that the job will execute on a fresh virtual machine hosted by GitHub. For syntax examples using other runners, see "[AUTOTITLE](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on)."
    runs-on: ubuntu-latest
    # Creates custom environment variables, and redefines the built-in `GITHUB_TOKEN` variable to use a custom [secret](/actions/security-guides/using-secrets-in-github-actions). These variables will be referenced later in the workflow.
    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
    # Groups together all the steps that will run as part of the `check_all_english_links` job. Each job in the workflow has its own `steps` section.
    steps:
      # The `uses` keyword tells the job to retrieve the action named `actions/checkout`. This is an action that checks out your repository and downloads it to the runner, allowing you to run actions against your code (such as testing tools). You must use the checkout action any time your workflow will run against the repository's code or you are using an action defined in the repository.
      - name: Check out repo's default branch
        uses: actions/checkout@v4
      # This step uses the `actions/setup-node` action to install the specified version of the `node` software package on the runner, which gives you access to the `npm` command.
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: 16.13.x
          cache: npm
      # The `run` keyword tells the job to execute a command on the runner. In this case, the `npm ci` and `npm run build` commands are run as separate steps to install and build the Node.js application in the repository.
      - name: Run the "npm ci" command
        run: npm ci
      - name: Run the "npm run build" command
        run: npm run build
      # This `run` command executes a script that is stored in the repository at `script/check-english-links.js`, and pipes the output to a file called `broken_links.md`.
      - name: Run script
        run: |
          script/check-english-links.js > broken_links.md

      # If the `check-english-links.js` script detects broken links and returns a non-zero (failure) exit status, then use a [workflow command](/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter) to set an output that has the value of the first line of the `broken_links.md` file (this is used the next step).
      #
      # `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 "title=$(head -1 broken_links.md)" >> $GITHUB_OUTPUT
      # Uses the `peter-evans/create-issue-from-file` action to create a new GitHub issue. This example is pinned to a specific version of the action, using the `ceef9be92406ace67ab5421f66570acf213ec395` SHA.
      - if: ${{ failure() }}
        name: Create issue from file
        id: broken-link-report
        uses: peter-evans/create-issue-from-file@ceef9be92406ace67ab5421f66570acf213ec395
        with:
          token: ${{ env.GITHUB_TOKEN }}

          title: ${{ steps.check.outputs.title }}
          content-filepath: ./broken_links.md
          repository: ${{ env.REPORT_REPOSITORY }}
          labels: ${{ env.REPORT_LABEL }}
      # Uses [`gh issue list`](https://cli.github.com/manual/gh_issue_list) to locate the previously created issue from earlier runs. This is [aliased](https://cli.github.com/manual/gh_alias_set) to `gh list-reports` for simpler processing in later steps.
      - 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`](https://cli.github.com/manual/gh_issue_comment) is used to add a comment to the new issue that links to the previous one.
          gh issue comment ${{ env.NEW_REPORT_URL }} --body "⬅️ [Previous report]($previous_report_url)"

          # If an issue from a previous run is open and assigned to someone, then use [`gh issue comment`](https://cli.github.com/manual/gh_issue_comment) to add a comment with a link to the new issue without closing the old report. To get the issue URL, the `jq` expression processes the resulting JSON output.
          #
          # If an issue from a previous run is open and is not assigned to anyone, use [`gh issue comment`](https://cli.github.com/manual/gh_issue_comment) to add a comment with a link to the new issue. Then use [`gh issue close`](https://cli.github.com/manual/gh_issue_close) and [`gh issue edit`](https://cli.github.com/manual/gh_issue_edit) to close the issue and remove it from the project board.

          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

          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 }})"

              # Use [`gh issue close`](https://cli.github.com/manual/gh_issue_close) to close the old issue.
              gh issue close $issue_url

              # Use [`gh issue edit`](https://cli.github.com/manual/gh_issue_edit) to edit the old issue and remove it from a specific GitHub project board.
              gh issue edit $issue_url --remove-project "${{ env.FIRST_RESPONDER_PROJECT }}"
            fi
          done

다음 단계

  • GitHub Actions 개념에 대해 알아보려면 “GitHub Actions 이해”를 참조하세요.
  • 기본 워크플로를 만들기 위한 단계별 가이드는 "AUTOTITLE"을 참조하세요.
  • GitHub Actions의 기본 사항에 익숙한 경우 “워크플로 정보”에서 워크플로 및 해당 기능에 대해 알아볼 수 있습니다.