워크플로우 재사용하기

워크플로우 재사용하기

워크플로우를 만들 때 기존 워크플로우를 재사용해 중복을 피하는 방법을 알려드릴게요.

출처: 문서

본문

워크플로우를 만들 때 기존 워크플로우를 재사용해 중복을 피할 수 있어요.

재사용 가능한 워크플로우 만들기

재사용 가능한 워크플로우는 다른 워크플로우 파일과 매우 유사한 YAML 형식의 파일이에요. 다른 워크플로우 파일과 마찬가지로 재사용 가능한 워크플로우는 저장소의 .github/workflows 디렉토리에 둡니다. workflows 디렉토리의 하위 디렉토리는 지원되지 않아요.

워크플로우가 재사용 가능하려면 on의 값에 workflow_call이 포함되어야 합니다:

on:
  workflow_call:

재사용 가능한 워크플로우에서 입력과 시크릿 사용하기

호출자 워크플로우에서 전달되어 호출된 워크플로우 내에서 사용할 수 있는 입력과 시크릿을 정의할 수 있어요. 재사용 가능한 워크플로우에서 입력이나 시크릿을 사용하는 단계는 세 가지예요.

  1. 재사용 가능한 워크플로우에서 inputssecrets 키워드를 사용해 호출자 워크플로우에서 전달될 입력이나 시크릿을 정의하세요.

    on:
      workflow_call:
        inputs:
          config-path:
            required: true
            type: string
        secrets:
          personal_access_token:
            required: true
    

    입력과 시크릿을 정의하는 구문에 대한 자세한 내용은 on.workflow_call.inputson.workflow_call.secrets를 참고하세요.

  2. 재사용 가능한 워크플로우에서 이전 단계의 on 키에 정의한 입력이나 시크릿을 참조하세요.

    [!NOTE] 호출 워크플로우에서 secrets: inherit을 사용해 시크릿을 상속하면 on 키에 명시적으로 정의하지 않았더라도 이를 참조할 수 있어요. 자세한 내용은 Workflow syntax for GitHub Actions를 참고하세요.

    jobs:
      reusable_workflow_job:
        runs-on: ubuntu-latest
        steps:
        - uses: actions/labeler@v6
          with:
            repo-token: ${{ secrets.personal_access_token }}
            configuration-path: ${{ inputs.config-path }}
    

    위 예시에서 personal_access_token은 저장소 또는 조직 수준에서 정의된 시크릿이에요.

    [!WARNING] on.workflow_callenvironment 키워드를 지원하지 않으므로 환경(environment) 시크릿은 호출자 워크플로우에서 전달될 수 없어요. 재사용 가능한 워크플로우의 작업 수준에 environment를 포함하면 호출자 워크플로우에서 전달된 시크릿이 아니라 환경 시크릿이 사용됩니다. 자세한 내용은 Managing environments for deploymentWorkflow syntax for GitHub Actions를 참고하세요.

  3. 호출자 워크플로우에서 입력이나 시크릿을 전달하세요.

    호출된 워크플로우에 이름 있는 입력을 전달하려면 작업에서 with 키워드를 사용하세요. 이름 있는 시크릿을 전달하려면 secrets 키워드를 사용하세요. 입력의 경우 입력 값의 데이터 타입이 호출된 워크플로우에 지정된 타입(boolean, number 또는 string)과 일치해야 해요.

    jobs:
      call-workflow-passing-data:
        uses: octo-org/example-repo/.github/workflows/reusable-workflow.yml@main
        with:
          config-path: .github/labeler.yml
        secrets:
          personal_access_token: ${{ secrets.token }}
    

    같은 조직 또는 엔터프라이즈에서 재사용 가능한 워크플로우를 호출하는 워크플로우는 inherit 키워드를 사용해 시크릿을 암시적으로 전달할 수 있어요.

    jobs:
      call-workflow-passing-data:
        uses: octo-org/example-repo/.github/workflows/reusable-workflow.yml@main
        with:
          config-path: .github/labeler.yml
        secrets: inherit
    

재사용 가능한 워크플로우 예시

workflow-B.yml이라는 이 재사용 가능한 워크플로우 파일(나중에 예시 호출자 워크플로우에서 언급할게요)은 호출자 워크플로우에서 입력 문자열과 시크릿을 받아 액션에서 사용합니다.

name: Reusable workflow example

on:
  workflow_call:
    inputs:
      config-path:
        required: true
        type: string
    secrets:
      token:
        required: true

jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/labeler@v6
      with:
        repo-token: ${{ secrets.token }}
        configuration-path: ${{ inputs.config-path }}

재사용 가능한 워크플로우 호출하기

uses 키워드를 사용해 재사용 가능한 워크플로우를 호출합니다. 워크플로우 내에서 액션을 사용할 때와 달리, 재사용 가능한 워크플로우는 작업 단계에서가 아니라 작업 내에서 직접 호출해요.

jobs.<job_id>.uses

재사용 가능한 워크플로우 파일은 다음 구문 중 하나로 참조합니다:

  • 같은 저장소의 재사용 가능한 워크플로우에 $/.github/workflows/{filename}. 같은 저장소의 재사용 가능한 워크플로우를 참조하는 데 권장되는 구문이에요. 이 구문은 GitHub Enterprise Server에서 사용할 수 없습니다.
  • 공개 및 비공개 저장소의 재사용 가능한 워크플로우에 {owner}/{repo}/.github/workflows/{filename}@{ref}.
  • 같은 저장소의 재사용 가능한 워크플로우에 ./.github/workflows/{filename}.

{owner}/{repo}@{ref}로 재사용 가능한 워크플로우를 참조할 때, {ref}는 SHA, 릴리스 태그 또는 브랜치 이름일 수 있어요. 릴리스 태그와 브랜치의 이름이 같으면 릴리스 태그가 브랜치 이름보다 우선합니다. 안정성과 보안을 위해 커밋 SHA를 사용하는 것이 가장 안전한 선택이에요. 자세한 내용은 Secure use reference를 참고하세요.

$/ 또는 ./({owner}/{repo}@{ref} 없이)로 같은 저장소의 재사용 가능한 워크플로우를 참조하면 호출된 워크플로우는 호출자 워크플로우와 같은 커밋에서 옵니다. $/ 참조에는 @{ref} 접미사가 포함되어서는 안 되며, $/는 GitHub Enterprise Server에서 사용할 수 없어요. refs/headsrefs/tags 같은 ref 접두사는 허용되지 않습니다. 이 키워드에서는 컨텍스트나 표현식을 사용할 수 없어요.

여러 워크플로우를 호출할 수 있으며, 각각을 별도의 작업에서 참조합니다.

jobs:
  call-workflow-1-in-local-repo:
    uses: octo-org/this-repo/.github/workflows/workflow-1.yml@172239021f7ba04fe7327647b213799853a9eb89
  call-workflow-2-in-local-repo:
    uses: ./.github/workflows/workflow-2.yml
  # The `$/` syntax is not available in GitHub Enterprise Server.
  call-workflow-in-same-repo-at-running-commit:
    uses: $/.github/workflows/workflow-2.yml
  call-workflow-in-another-repo:
    uses: octo-org/another-repo/.github/workflows/workflow.yml@v1

예시 호출자 워크플로우

이 워크플로우 파일은 두 개의 워크플로우 파일을 호출합니다. 그중 두 번째인 workflow-B.yml(예시 재사용 가능한 워크플로우에 표시)에는 입력(config-path)과 시크릿(token)이 전달됩니다.

name: Call a reusable workflow

on:
  pull_request:
    branches:
      - main

jobs:
  call-workflow:
    uses: octo-org/example-repo/.github/workflows/workflow-A.yml@v1

  call-workflow-passing-data:
    permissions:
      contents: read
      pull-requests: write
    uses: octo-org/example-repo/.github/workflows/workflow-B.yml@main
    with:
      config-path: .github/labeler.yml
    secrets:
      token: ${{ secrets.GITHUB_TOKEN }}

재사용 가능한 워크플로우에 입력과 시크릿 전달하기

호출된 워크플로우에 이름 있는 입력을 전달하려면 작업에서 with 키워드를 사용하세요. 이름 있는 시크릿을 전달하려면 secrets 키워드를 사용하세요. 입력의 경우 입력 값의 데이터 타입이 호출된 워크플로우에 지정된 타입(boolean, number 또는 string)과 일치해야 해요.

jobs:
  call-workflow-passing-data:
    uses: octo-org/example-repo/.github/workflows/reusable-workflow.yml@main
    with:
      config-path: .github/labeler.yml
    secrets:
      personal_access_token: ${{ secrets.token }}

같은 조직 또는 엔터프라이즈에서 재사용 가능한 워크플로우를 호출하는 워크플로우는 inherit 키워드를 사용해 시크릿을 암시적으로 전달할 수 있어요.

jobs:
  call-workflow-passing-data:
    uses: octo-org/example-repo/.github/workflows/reusable-workflow.yml@main
    with:
      config-path: .github/labeler.yml
    secrets: inherit

재사용 가능한 워크플로우와 매트릭스 전략 사용하기

매트릭스 전략을 사용하는 작업은 재사용 가능한 워크플로우를 호출할 수 있어요.

매트릭스 전략을 사용하면 단일 작업 정의의 변수를 사용해 변수 조합에 기반한 여러 작업 실행을 자동으로 만들 수 있어요. 예를 들어 매트릭스 전략을 사용해 재사용 가능한 워크플로우에 다른 입력을 전달할 수 있습니다. 매트릭스에 대한 자세한 내용은 Running variations of jobs in a workflow를 참고하세요.

아래의 이 예시 작업은 재사용 가능한 워크플로우를 호출하고 target 변수를 [dev, stage, prod] 값으로 정의해 매트릭스 컨텍스트를 참조합니다. 변수의 각 값에 대해 하나씩 세 개의 작업을 실행합니다.

jobs:
  ReusableMatrixJobForDeployment:
    strategy:
      matrix:
        target: [dev, stage, prod]
    uses: octocat/octo-repo/.github/workflows/deployment.yml@main
    with:
      target: ${{ matrix.target }}

재사용 가능한 워크플로우 중첩하기

최대 10개 수준의 워크플로우를 연결할 수 있어요. 즉 최상위 호출자 워크플로우와 최대 9개 수준의 재사용 가능한 워크플로우입니다. 예: caller-workflow.ymlcalled-workflow-1.ymlcalled-workflow-2.ymlcalled-workflow-3.yml → ... → called-workflow-9.yml.

워크플로우 트리의 루프는 허용되지 않습니다.

[!NOTE] 중첩된 재사용 가능한 워크플로우는 체인의 모든 워크플로우가 호출자에게 접근 가능해야 하며, 권한은 체인 전체에서 유지되거나 줄어들 수만 있고 높아질 수는 없어요. 자세한 내용은 Reusing workflow configurations를 참고하세요.

재사용 가능한 워크플로우 내에서 다른 재사용 가능한 워크플로우를 호출할 수 있어요.

name: Reusable workflow

on:
  workflow_call:

jobs:
  call-another-reusable:
    uses: octo-org/example-repo/.github/workflows/another-reusable.yml@v1

중첩된 워크플로우에 시크릿 전달하기

호출 워크플로우에서 jobs.<job_id>.secrets를 사용해 직접 호출된 워크플로우에 이름 있는 시크릿을 전달할 수 있어요. 또는 jobs.<job_id>.secrets.inherit을 사용해 호출 워크플로우의 모든 시크릿을 직접 호출된 워크플로우에 전달할 수 있어요. 자세한 내용은 위의 재사용 가능한 워크플로우에 입력과 시크릿 전달하기 섹션과 참조 문서 Workflow syntax for GitHub Actions를 참고하세요. 시크릿은 직접 호출된 워크플로우에만 전달되므로, A > B > C 체인에서 워크플로우 C는 A에서 B로, 그리고 B에서 C로 전달된 경우에만 A로부터 시크릿을 받습니다.

다음 예시에서 워크플로우 A는 inherit 키워드를 사용해 모든 시크릿을 워크플로우 B에 전달하지만, 워크플로우 B는 하나의 시크릿만 워크플로우 C에 전달합니다. 워크플로우 B에 전달된 다른 시크릿은 워크플로우 C에서 사용할 수 없어요.

jobs:
  workflowA-calls-workflowB:
    uses: octo-org/example-repo/.github/workflows/B.yml@main
    secrets: inherit # pass all secrets
jobs:
  workflowB-calls-workflowC:
    uses: different-org/example-repo/.github/workflows/C.yml@main
    secrets:
      repo-token: ${{ secrets.personal_access_token }} # pass just this secret

재사용 가능한 워크플로우에서 출력 사용하기

재사용 가능한 워크플로우는 호출자 워크플로우에서 사용하려는 데이터를 생성할 수 있어요. 이러한 출력을 사용하려면 이를 재사용 가능한 워크플로우의 출력으로 지정해야 해요.

출력을 설정하는 재사용 가능한 워크플로우가 매트릭스 전략으로 실행되면, 출력은 실제로 값을 설정하는 매트릭스의 마지막으로 성공적으로 완료된 재사용 가능한 워크플로우가 설정한 출력이 됩니다. 즉 마지막으로 성공적으로 완료된 재사용 가능한 워크플로우가 출력에 빈 문자열을 설정하고, 두 번째로 마지막으로 성공적으로 완료된 재사용 가능한 워크플로우가 출력에 실제 값을 설정하면, 출력에는 두 번째로 마지막으로 완료된 재사용 가능한 워크플로우의 값이 포함됩니다.

다음 재사용 가능한 워크플로우는 두 개의 단계를 포함하는 단일 작업을 가져요. 각 단계에서 "hello"와 "world"라는 단일 단어를 출력으로 설정합니다. 작업의 outputs 섹션에서 이 단계 출력을 output1output2라는 작업 출력에 매핑합니다. 그런 다음 on.workflow_call.outputs 섹션에서 워크플로우 자체에 대해 두 개의 출력을 정의합니다. 하나는 output1에 매핑되는 firstword이고, 다른 하나는 output2에 매핑되는 secondword입니다.

value는 호출된 워크플로우 내 작업 수준 출력의 값으로 설정되어야 해요. 단계 수준 출력은 아래와 같이 먼저 작업 수준 출력에 매핑되어야 합니다.

자세한 내용은 Passing information between jobsWorkflow syntax for GitHub Actions를 참고하세요.

name: Reusable workflow

on:
  workflow_call:
    # Map the workflow outputs to job outputs
    outputs:
      firstword:
        description: "The first output string"
        value: ${{ jobs.example_job.outputs.output1 }}
      secondword:
        description: "The second output string"
        value: ${{ jobs.example_job.outputs.output2 }}

jobs:
  example_job:
    name: Generate output
    runs-on: ubuntu-latest
    # Map the job outputs to step outputs
    outputs:
      output1: ${{ steps.step1.outputs.firstword }}
      output2: ${{ steps.step2.outputs.secondword }}
    steps:
      - id: step1
        run: echo "firstword=hello" >> $GITHUB_OUTPUT
      - id: step2
        run: echo "secondword=world" >> $GITHUB_OUTPUT

이제 같은 워크플로우 내 작업의 출력을 사용하는 것과 같은 방식으로 호출자 워크플로우에서 출력을 사용할 수 있어요. 재사용 가능한 워크플로우에서 워크플로우 수준으로 정의한 이름인 firstwordsecondword로 출력을 참조합니다. 이 워크플로우에서 job1은 재사용 가능한 워크플로우를 호출하고 job2는 재사용 가능한 워크플로우의 출력("hello world")을 워크플로우 로그의 표준 출력으로 출력합니다.

name: Call a reusable workflow and use its outputs

on:
  workflow_dispatch:

jobs:
  job1:
    uses: octo-org/example-repo/.github/workflows/called-workflow.yml@v1

  job2:
    runs-on: ubuntu-latest
    needs: job1
    steps:
      - run: echo ${{ needs.job1.outputs.firstword }} ${{ needs.job1.outputs.secondword }}

작업 출력 사용에 대한 자세한 내용은 Workflow syntax for GitHub Actions를 참고하세요. 워크플로우 간에 변수가 아닌 다른 것(예: 빌드 아티팩트)을 공유하려면 Store and share data with workflow artifacts를 참고하세요.

재사용 가능한 워크플로우에서 캐시 접근 제어하기

cache-mode 키를 사용해 재사용 가능한 워크플로우에 필요한 최소한의 GitHub Actions 캐시 접근 권한을 부여할 수 있어요. 값은 read, write, write-only 또는 none일 수 있어요. cache-mode를 생략하면 트리거 유형에 따라 read 또는 write 기본값이 사용됩니다. 전체 구문과 각 값의 의미는 Workflow syntax for GitHub Actions를 참고하세요. 트리거 종속 기본값은 Dependency caching reference를 참고하세요.

호출자 워크플로우가 재사용 가능한 워크플로우를 호출할 때 cache-mode는 호출된 워크플로우로 전파됩니다. 호출 작업의 명시적인 cache-mode 또는 호출자 워크플로우에서 상속된 값은 호출된 워크플로우가 요청할 수 있는 캐시 접근을 제한합니다.

호출 작업이 명시적인 cache-mode를 설정하거나 상속하지 않는 경우, 호출자의 낮은 신뢰 트리거가 read로 기본 설정되어도 호출된 워크플로우는 명시적으로 write를 요청할 수 있어요. 호출된 워크플로우를 읽기 전용으로 제한하려면 이를 호출하는 작업에 cache-mode: read를 설정하세요.

호출된 워크플로우가 이 명시적 한도를 초과하는 접근을 요청하는 cache-mode를 선언하면 실행이 시작되지 않고 GitHub가 검증 오류를 보고합니다. 예를 들어 최대 read를 허용하는 호출자는 write를 선언하는 워크플로우를 호출할 수 없어요. read는 복원 접근을 부여하고 write-only는 저장 접근을 부여하므로 이 둘은 겹치지 않는 기능이며, 둘 사이의 불일치도 과다 요청입니다. 예를 들어 write-only 호출자는 read를 선언하는 워크플로우를 호출할 수 없어요.

캐시 접근과 네 가지 모드에 대한 자세한 내용은 Dependency caching reference를 참고하세요.

어떤 워크플로우가 사용되고 있는지 모니터링하기

GitHub Enterprise Cloud를 사용하는 조직은 GitHub REST API를 통해 감사 로그(audit log)와 상호 작용해 어떤 워크플로우가 사용되고 있는지 모니터링할 수 있어요. 자세한 내용은 the GitHub Enterprise Cloud documentation를 참고하세요.

다음 단계

워크플로우 재사용의 복잡한 세부 사항을 알아보려면 Reusing workflow configurations를 참고하세요.

더 알아보기 (Learn more)