Skip to main content

GitHub Action


Workflow 파일

GitHub Action을 위한 Workflow yaml파일을 리포지토리의 .github/workflows 디렉토리에 저장하고 GitHub에 반영하면 자동으로 반영되어 실행됩니다.

컨텍스트 정보

사용할 수 있는 컨텍스트 정보를 아래 Action을 통해 확인 할 수 있습니다.

name: Context testing
on: push

jobs:
dump_contexts_to_log:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
id: github_context_step
run: echo '${{ toJSON(github) }}'
- name: Dump job context
run: echo '${{ toJSON(job) }}'
- name: Dump steps context
run: echo '${{ toJSON(steps) }}'
- name: Dump runner context
run: echo '${{ toJSON(runner) }}'
- name: Dump strategy context
run: echo '${{ toJSON(strategy) }}'
- name: Dump matrix context
run: echo '${{ toJSON(matrix) }}'

동시성 제어

같은 Workflow, 같은 브랜치에서 실행되는 Workflow는 마지막에 제출된 것만 실행되도록하는 설정은 아래와 같습니다.

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

concurrency는 Job에 선언할 수 있습니다. group은 대소문자를 구분하지 않습니다.

버전 태그

name: Hash

on:
push:
branches:
- main
workflow_dispatch:

jobs:
hash:
runs-on: ubuntu-latest
steps:
- name: Get TAG
id: tag
run: |
TAG=$(echo ${{ github.sha }} | cut -c1-7)
echo TAG=$TAG
echo "tag=$TAG" >> $GITHUB_OUTPUT
name: Version

on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"

jobs:
version:
runs-on: ubuntu-latest
steps:
- name: Get TAG
id: tag
run: |
TAG=${{ github.ref_name }}
echo TAG=$TAG
echo "tag=$TAG" >> $GITHUB_OUTPUT

Container Registry

ECR

name: Push to Amazon ECR

on:
push:
branches:
- main

jobs:
build:
name: Build and Push Image
runs-on: ubuntu-latest
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2

- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

# https://github.com/docker/build-push-action
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
${{ steps.login-ecr.outputs.registry }}/backend:${{ steps.tag.outputs.tag }}
cache-from: type=gha
cache-to: type=gha,mode=max

Githup

name: Push to GitHub Container Registry

on:
push:
branches:
- main

jobs:
build:
name: Build and Push Image
runs-on: ubuntu-latest
steps:
# https://github.com/docker/login-action
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.PAT }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

# https://github.com/docker/build-push-action
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/backend:${{ steps.tag.outputs.tag }}
cache-from: type=gha
cache-to: type=gha,mode=max

Auto Release

name: Auto Release

on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"

jobs:
release:
name: Publish auto release
runs-on: ubuntu-latest
needs: [build]
permissions:
contents: write
steps:
- name: Release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true

필터를 사용하는 Required Job

Required job이 pathspaths-ignore 같은 옵션으로 인해 실행되지 않으면 Pending 상태에 빠져서 PR을 완료할 수 없습니다. 이를 해결하기 위해서는

  • 반대되는 필터를 갖는 Workflow를 만들고 Job 이름이 같은 dummy Job을 만드는 방법
  • dorny/paths-filter를 사용하는 방법

이 있습니다.

info

Job 실행 결과는 success, failure, cancelled, skipped 중 하나입니다. Pending은 실행 자체가 안된 상태입니다.

successskipped는 Required 검사를 통과합니다.

Dummy Job 만들기

.github/workflows/job.yaml
name: job

on:
pull_request:
branches:
- main
paths:
- "backend/**"

jobs:
tests:
runs-on: ubuntu-latest
steps:
- name: Test backend
run: |
# ...
.github/workflows/job-dummy.yaml
name: job

on:
pull_request:
branches:
- main
paths-ignore:
- "backend/**"

jobs:
tests:
if: false
runs-on: ubuntu-latest
steps:
- run: echo "Unreachable"

paths-filter 사용하기

jobs:
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
backend: ${{ steps.filter.outputs.backend }}
backend_files: ${{ steps.filter.outputs.backend_files }}
frontend: ${{ steps.filter.outputs.frontend }}
steps:
# PR에 대한 filter의 경우 checkout이 필요 없습니다.
- name: Find changes
uses: dorny/paths-filter@v3
id: filter
with:
list-files: shell
filters: |
backend:
- "backend/**"
frontend:
- "frontend/**"

backend-tests:
needs: changes
if: needs.changes.outputs.backend == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Test backend
run: |
# ...

- name: Lint backend
run: |
for file in ${{ needs.changes.outputs.backend_files }}; do
# ...
done

frontend-tests:
needs: changes
if: needs.changes.outputs.frontend == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Test frontend
run: |
# ...