Skip to main content
설명서에 자주 업데이트를 게시하며 이 페이지의 번역이 계속 진행 중일 수 있습니다. 최신 정보는 영어 설명서를 참조하세요.

작업을 사용하여 Projects 자동화

GitHub Actions를 사용하여 프로젝트를 자동화할 수 있습니다.

GitHub Actions 워크플로

이 섹션에서는 GraphQL API 및 GitHub Actions을(를) 사용하여 조직 프로젝트에 끌어오기 요청을 추가하는 방법을 보여 줍니다. 예제 워크플로에서 끌어오기 요청이 “검토 준비 완료”로 표시되면 “상태” 필드가 “Todo”로 설정된 새 작업이 프로젝트에 추가되고 현재 날짜가 사용자 지정 “게시 날짜” 필드에 추가됩니다.

아래 워크플로 중 하나를 복사하고 아래 표에 설명된 대로 수정하여 요구 사항을 충족할 수 있습니다.

프로젝트는 여러 리포지토리에 걸쳐 있지만 워크플로는 리포지토리에만 적용됩니다. 프로젝트에서 추적하려는 각 리포지토리에 워크플로를 추가합니다. 워크플로 파일을 만드는 방법에 대한 자세한 내용은 "GitHub Actions 빠른 시작"을 참조하세요.

이 문서에서는 GitHub Actions에 대한 기본적인 이해가 있다고 가정합니다. GitHub Actions에 대한 자세한 내용은 "GitHub Actions 설명서.

API를 통해 프로젝트에 적용할 수 있는 다른 변경 내용에 대한 자세한 내용은 "API를 사용하여 Projects 관리"을 참조하세요.

GitHub에 의해 유지 관리되고 지정된 프로젝트에 현재 문제 또는 끌어오기 요청을 추가하는 actions/add-to-project 워크플로를 사용할 수도 있습니다. 자세한 내용은 actions/add-to-project 리포지토리 및 추가 정보를 참조하세요.

참고: GITHUB_TOKEN은 리포지토리 수준으로 범위가 지정되며 projects에 액세스할 수 없습니다. projects에 액세스하려면 GitHub App(조직 프로젝트에 권장) 또는 personal access token(사용자 프로젝트에 권장)를 만들 수 있습니다. 두 방법 모두에 대한 워크플로 예제는 다음과 같습니다.

GitHub App을(를) 사용하여 인증하는 예제 워크플로

  1. GitHub App을(를) 만들거나 조직이 소유한 기존 GitHub App을(를) 선택합니다. 자세한 내용은 "GitHub 앱 만들기"을 참조하세요.

  2. GitHub App에 조직 프로젝트에 대한 읽기 및 쓰기 권한을 부여합니다. 자세한 내용은 "GitHub 앱의 권한 편집"을 참조하세요.

    참고: 조직 프로젝트 및 리포지토리 프로젝트에 대한 앱의 권한을 제어할 수 있습니다. 조직 프로젝트를 읽고 쓸 수 있는 권한을 부여해야 합니다. 리포지토리 프로젝트를 읽고 쓸 수 있는 권한만으로는 충분하지 않습니다.

  3. 조직에 GitHub App을(를) 설치합니다. 프로젝트에 액세스해야 하는 모든 리포지토리에 설치합니다. 자세한 내용은 "GitHub 앱 설치"을 참조하세요.

  4. GitHub App의 ID를 리포지토리 또는 조직에 비밀로 저장합니다. 다음 워크플로에서 APP_ID를 비밀 이름으로 바꿉니다. 앱의 설정 페이지 또는 앱 API를 통해 앱 ID를 찾을 수 있습니다. 자세한 내용은 ""을 참조하세요.

  5. 앱에 대한 프라이빗 키를 생성합니다. 결과 파일의 콘텐츠를 리포지토리 또는 조직에 비밀로 저장합니다. (-----BEGIN RSA PRIVATE KEY----------END RSA PRIVATE KEY-----를 포함하여 파일의 전체 콘텐츠를 저장합니다.) 다음 워크플로에서 APP_PEM을 비밀 이름으로 바꿉니다. 자세한 내용은 "GitHub 앱에 대한 프라이빗 키 관리"을 참조하세요.

  6. 다음 워크플로에서 YOUR_ORGANIZATION을 조직 이름으로 바꿉니다. 예: octo-org. YOUR_PROJECT_NUMBER를 프로젝트 번호로 바꿉니다. 프로젝트 번호를 찾으려면 프로젝트 URL을 확인합니다. 예를 들어 https://github.com/orgs/octo-org/projects/5의 프로젝트 번호는 5입니다.

YAML
# 이 워크플로는 GitHub에서 인증되지 않은 작업을 사용합니다.
# 작업은 타사에서 제공하며
# 별도의 서비스 약관, 개인정보처리방침, 지원 설명서에서 규정됩니다.
# 참조하세요.

# 커밋 SHA에 작업을 고정하는 것이 좋습니다.
# 최신 버전을 얻으려면 SHA를 업데이트해야 합니다.
# 태그 또는 분기를 참조할 수도 있지만 경고 없이 작업이 변경될 수 있습니다.

name: Add PR to project
on:
  pull_request:
    types:
      - ready_for_review
jobs:
  track_pr:
    runs-on: ubuntu-latest
    steps:
      - name: Generate token
        id: generate_token
        uses: tibdex/github-app-token@36464acb844fc53b9b8b2401da68844f6b05ebb0
        with:
          app_id: ${{ secrets.APP_ID }}
          private_key: ${{ secrets.APP_PEM }}

      - name: Get project data
        env:
          GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
          ORGANIZATION: YOUR_ORGANIZATION
          PROJECT_NUMBER: YOUR_PROJECT_NUMBER
        run: |
          gh api graphql -f query='
            query($org: String!, $number: Int!) {
              organization(login: $org){
                projectV2(number: $number) {
                  id
                  fields(first:20) {
                    nodes {
                      ... on ProjectV2Field {
                        id
                        name
                      }
                      ... on ProjectV2SingleSelectField {
                        id
                        name
                        options {
                          id
                          name
                        }
                      }
                    }
                  }
                }
              }
            }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json

          echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
          echo 'DATE_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Date posted") | .id' project_data.json) >> $GITHUB_ENV
          echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
          echo 'TODO_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV

      - name: Add PR to project
        env:
          GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
          PR_ID: ${{ github.event.pull_request.node_id }}
        run: |
          item_id="$( gh api graphql -f query='
            mutation($project:ID!, $pr:ID!) {
              addProjectV2ItemById(input: {projectId: $project, contentId: $pr}) {
                item {
                  id
                }
              }
            }' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectV2ItemById.item.id')"

            echo 'ITEM_ID='$item_id >> $GITHUB_ENV

      - name: Get date
        run: echo "DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV

      - name: Set fields
        env:
          GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
        run: |
          gh api graphql -f query='
            mutation (
              $project: ID!
              $item: ID!
              $status_field: ID!
              $status_value: String!
              $date_field: ID!
              $date_value: Date!
            ) {
              set_status: updateProjectV2ItemFieldValue(input: {
                projectId: $project
                itemId: $item
                fieldId: $status_field
                value: { 
                  singleSelectOptionId: $status_value
                  }
              }) {
                projectV2Item {
                  id
                  }
              }
              set_date_posted: updateProjectV2ItemFieldValue(input: {
                projectId: $project
                itemId: $item
                fieldId: $date_field
                value: { 
                  date: $date_value
                }
              }) {
                projectV2Item {
                  id
                }
              }
            }' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.TODO_OPTION_ID }} -f date_field=$DATE_FIELD_ID -f date_value=$DATE --silent

personal access token을(를) 사용하여 인증하는 예제 워크플로

  1. repo 범위를 사용하여 personal access token (classic)을(를project) 만듭니다. 자세한 내용은 "개인용 액세스 토큰 만들기"을 참조하세요.
  2. personal access token을(를) 리포지토리 또는 조직에 비밀로 저장합니다.
  3. 다음 워크플로에서 YOUR_TOKEN을 비밀 이름으로 바꿉니다. YOUR_ORGANIZATION을 조직 이름으로 바꿉니다. 예: octo-org. YOUR_PROJECT_NUMBER를 프로젝트 번호로 바꿉니다. 프로젝트 번호를 찾으려면 프로젝트 URL을 확인합니다. 예를 들어 https://github.com/orgs/octo-org/projects/5의 프로젝트 번호는 5입니다.
YAML
name: Add PR to project
on:
  pull_request:
    types:
      - ready_for_review
jobs:
  track_pr:
    runs-on: ubuntu-latest
    steps:
      - name: Get project data
        env:
          GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
          ORGANIZATION: YOUR_ORGANIZATION
          PROJECT_NUMBER: YOUR_PROJECT_NUMBER
        run: |
          gh api graphql -f query='
            query($org: String!, $number: Int!) {
              organization(login: $org){
                projectV2(number: $number) {
                  id
                  fields(first:20) {
                    nodes {
                      ... on ProjectV2Field {
                        id
                        name
                      }
                      ... on ProjectV2SingleSelectField {
                        id
                        name
                        options {
                          id
                          name
                        }
                      }
                    }
                  }
                }
              }
            }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json

          echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
          echo 'DATE_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Date posted") | .id' project_data.json) >> $GITHUB_ENV
          echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
          echo 'TODO_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV

      - name: Add PR to project
        env:
          GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
          PR_ID: ${{ github.event.pull_request.node_id }}
        run: |
          item_id="$( gh api graphql -f query='
            mutation($project:ID!, $pr:ID!) {
              addProjectV2ItemById(input: {projectId: $project, contentId: $pr}) {
                item {
                  id
                }
              }
            }' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectV2ItemById.item.id')"

            echo 'ITEM_ID='$item_id >> $GITHUB_ENV

      - name: Get date
        run: echo "DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV

      - name: Set fields
        env:
          GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
        run: |
          gh api graphql -f query='
            mutation (
              $project: ID!
              $item: ID!
              $status_field: ID!
              $status_value: String!
              $date_field: ID!
              $date_value: Date!
            ) {
              set_status: updateProjectV2ItemFieldValue(input: {
                projectId: $project
                itemId: $item
                fieldId: $status_field
                value: { 
                  singleSelectOptionId: $status_value
                  }
              }) {
                projectV2Item {
                  id
                  }
              }
              set_date_posted: updateProjectV2ItemFieldValue(input: {
                projectId: $project
                itemId: $item
                fieldId: $date_field
                value: { 
                  date: $date_value
                }
              }) {
                projectV2Item {
                  id
                }
              }
            }' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.TODO_OPTION_ID }} -f date_field=$DATE_FIELD_ID -f date_value=$DATE --silent

워크플로 설명

다음 표에서는 예제 워크플로의 섹션을 설명하고 고유한 용도로 워크플로를 조정하는 방법을 보여 줍니다.

on:
  pull_request:
    types:
      - ready_for_review
이 워크플로는 리포지토리의 끌어오기 요청이 “검토 준비 완료”로 표시될 때마다 실행됩니다.

GitHub App에만 다음이 해당됩니다.

- name: Generate token
  id: generate_token
  uses: tibdex/github-app-token@36464acb844fc53b9b8b2401da68844f6b05ebb0
  with:
    app_id: ${{ secrets.APP_ID }}
    private_key: ${{ secrets.APP_PEM }}
tibdex/github-app-token 작업을 사용하여 앱 ID 및 프라이빗 키에서 앱에 대한 설치 액세스 토큰을 생성합니다. 설치 액세스 토큰은 나중에 워크플로에서 ${{ steps.generate_token.outputs.token }}로 액세스됩니다.

APP_ID를 앱 ID가 포함된 비밀 이름으로 바꿉니다.

APP_PEM를 앱 프라이빗 키가 포함된 비밀 이름으로 바꿉니다.

GitHub App:

env:
  GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
  ORGANIZATION: YOUR_ORGANIZATION
  PROJECT_NUMBER: YOUR_PROJECT_NUMBER

Personal access token:

env:
  GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
  ORGANIZATION: YOUR_ORGANIZATION
  PROJECT_NUMBER: YOUR_PROJECT_NUMBER
이 단계에 대한 환경 변수를 설정합니다.

personal access token을(를) YOUR_TOKEN 사용하는 경우 을 personal access token이(가) 포함된 비밀의 이름으로 바꿉니다.

YOUR_ORGANIZATION을 조직 이름으로 바꿉니다. 예: octo-org.

YOUR_PROJECT_NUMBER를 프로젝트 번호로 바꿉니다. 프로젝트 번호를 찾으려면 프로젝트 URL을 확인합니다. 예를 들어 https://github.com/orgs/octo-org/projects/5의 프로젝트 번호는 5입니다.
gh api graphql -f query='
  query($org: String!, $number: Int!) {
    organization(login: $org){
      projectV2(number: $number) {
        id
        fields(first:20) {
          nodes {
            ... on ProjectV2Field {
              id
              name
            }
            ... on ProjectV2SingleSelectField {
              id
              name
              options {
                id
                name
              }
            }
          }
        }
      }
    }
  }'  -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json

GitHub CLI를 사용하여 API에 프로젝트 ID를 쿼리하고 프로젝트의 처음 20개 필드의 이름과 ID를 반환합니다. fields는 공용 구조체를 반환하고 쿼리는 인라인 조각(... on)을 사용하여 ProjectV2FieldProjectV2SingleSelectField 필드에 대한 정보를 반환합니다.

응답은 project_data.json이라는 파일에 저장됩니다.

echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
echo 'DATE_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Date posted") | .id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo 'TODO_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV
API 쿼리의 응답을 구문 분석하고 관련 ID를 환경 변수로 저장합니다. 다른 필드 또는 옵션에 대한 ID를 가져오도록 수정합니다. 예를 들면 다음과 같습니다.
  • Team이라는 필드의 ID를 얻으려면 echo 'TEAM_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Team") | .id' project_data.json) >> $GITHUB_ENV를 추가합니다.
  • Team 단일 선택 필드에 대해 Octoteam이라는 옵션의 ID를 가져오려면 echo 'OCTOTEAM_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Team") |.options[] | select(.name=="Octoteam") |.id' project_data.json) >> $GITHUB_ENV를 추가합니다.
참고: 이 워크플로에서는 “Todo”라는 옵션과 “게시한 날짜”라는 날짜 필드가 포함된 “상태”라는 단일 선택 필드가 있는 프로젝트가 있다고 가정합니다. 테이블에 있는 필드와 일치하도록 이 섹션을 수정해야 합니다.

GitHub App:

env:
  GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
  PR_ID: ${{ github.event.pull_request.node_id }}

Personal access token:

env:
  GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
  PR_ID: ${{ github.event.pull_request.node_id }}
이 단계에 대한 환경 변수를 설정합니다. GITHUB_TOKEN은 위에서 설명합니다. PR_ID는 이 워크플로를 트리거한 끌어오기 요청의 ID입니다.
item_id="$( gh api graphql -f query='
  mutation($project:ID!, $pr:ID!) {
    addProjectV2ItemById(input: {projectId: $project, contentId: $pr}) {
      item {
        id
      }
    }
  }' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectV2ItemById.item.id')"
GitHub CLI 및 API를 사용하여 이 워크플로를 트리거한 끌어오기 요청을 프로젝트에 추가합니다. jq 플래그는 응답을 구문 분석하여 만든 항목의 ID를 가져옵니다.
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
생성된 항목의 ID를 환경 변수로 저장합니다.
echo "DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV
현재 날짜를 yyyy-mm-dd 형식의 환경 변수로 저장합니다.

GitHub App:

env:
  GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}

Personal access token:

env:
  GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
이 단계에 대한 환경 변수를 설정합니다. GITHUB_TOKEN은 위에서 설명합니다.
gh api graphql -f query='
  mutation (
    $project: ID!
    $item: ID!
    $status_field: ID!
    $status_value: String!
    $date_field: ID!
    $date_value: Date!
  ) {
    set_status: updateProjectV2ItemFieldValue(input: {
      projectId: $project
      itemId: $item
      fieldId: $status_field
      value: { 
        singleSelectOptionId: $status_value
        }
    }) {
      projectV2Item {
        id
        }
    }
    set_date_posted: updateProjectV2ItemFieldValue(input: {
      projectId: $project
      itemId: $item
      fieldId: $date_field
      value: { 
        date: $date_value
      }
    }) {
      projectV2Item {
        id
      }
    }
  }' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.TODO_OPTION_ID }} -f date_field=$DATE_FIELD_ID -f date_value=$DATE --silent
Status 필드의 값을 Todo로 설정합니다. Date posted 필드의 값을 설정합니다.