본문 바로가기
  • Let's study
DevOps/CI·CD

[GitHub Actions] 실행 구조와 태그·릴리즈 자동화

by 코딩고수이고파 2026. 11. 5.

지금까지는 코드를 수정한 뒤 직접 빌드하고 실행했다. GitHub Actions를 사용하면 저장소에서 특정 이벤트가 발생했을 때 필요한 작업을 자동으로 실행할 수 있다.

처음에는 간단한 메시지 출력부터 시작하고, 이후 태그와 릴리즈 생성으로 연결했다.

워크플로 파일과 실행 조건

워크플로는 저장소의 .github/workflows 아래에 YAML 파일로 작성한다. 파일 이름은 원하는 대로 정할 수 있다.

name: work-1

on:
  push:
    branches:
      - main

jobs:
  hello1:
    runs-on: ubuntu-latest
    steps:
      - name: sayHi
        run: echo "Hi"

      - name: sayMyName
        run: echo "${{ github.actor }}"

 

name은 워크플로 이름이고, on은 실행 조건이다.

위 설정은 GitHub의 main 브랜치에 push가 발생했을 때 실행된다. 로컬에서 커밋만 하거나 develop 브랜치에 푸시하면 실행되지 않는다.

${{ github.actor }}는 워크플로 실행을 시작한 GitHub 사용자의 이름을 가져온다. 이번 push 상황에서는 누가 푸시했는지에 따라 출력값이 달라진다.

Workflow, Job, Step의 관계

실행 구조는 다음과 같이 구분할 수 있다.

Workflow
├─ 실행 조건
├─ Job
│  ├─ Step
│  └─ Step
└─ Job
   ├─ Step
   └─ Step

 

하나의 워크플로에 여러 Job을 정의할 수 있고, 각 Job에는 여러 Step이 들어간다.

별도 의존 관계가 없는 Job은 서로 기다리지 않고 병렬로 실행될 수 있다. 반면 같은 Job 안의 Step은 작성한 순서대로 실행된다.

예를 들어 다음 두 Job이 있다면:

 

hello1: 인사 → 10초 대기 → 이름 출력
hello2: 인사 → 20초 대기 → 이름 출력

 

hello2가 hello1의 종료를 기다리지는 않는다. 다만 hello1 안에서 이름을 출력하려면 먼저 10초 대기가 끝나야 한다.

독립적인 Job 하나가 실패해도 다른 Job은 계속 실행될 수 있지만, 전체 워크플로에는 실패 결과가 남는다.

명령은 러너에서 실행된다

runs-on: ubuntu-latest

 

이 설정은 Job을 실행할 러너 환경을 지정한다. 이번에는 GitHub가 제공하는 Ubuntu 환경을 사용했다.

저장소에 작성한 워크플로를 내 컴퓨터에서 실행하는 것이 아니라, 별도로 준비된 러너가 명령을 수행한다.

러너가 준비됐다고 프로젝트 코드까지 자동으로 들어 있는 것은 아니다. 코드가 필요한 작업에는 체크아웃 단계가 필요하다.

 

- uses: actions/checkout@v4

 

실행 환경을 준비하는 것과 프로젝트 코드를 가져오는 것은 별도 과정이다.

태그는 빌드 성공 기록이 아니다

처음에는 태그를 “빌드 작업을 했다고 남기는 기록”처럼 생각했다. 하지만 Git 태그는 특정 커밋에 붙이는 이름표다.

커밋 A ← v1.0.0
커밋 B
커밋 C ← v1.1.0

 

태그를 통해 특정 버전의 코드를 다시 찾을 수 있다. 다만 태그 생성 자체가 애플리케이션을 빌드하거나 빌드 성공을 증명하지는 않는다.

워크플로에 빌드 명령이 없다면 태그가 생겼다는 이유만으로 빌드에 성공했다고 할 수 없다.

태그와 릴리즈 생성하기

jobs:
  makeTagAndRelease:
    runs-on: ubuntu-latest

    outputs:
      tag_name: ${{ steps.create_tag.outputs.new_tag }}

    steps:
      - uses: actions/checkout@v4

      - name: Create Tag
        id: create_tag
        uses: mathieudutour/github-tag-action@v6.2
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

      - name: Create Release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ steps.create_tag.outputs.new_tag }}
          release_name: Release ${{ steps.create_tag.outputs.new_tag }}
          body: ${{ steps.create_tag.outputs.changelog }}
          draft: false
          prerelease: false

 

uses는 만들어진 Action을 사용하는 설정이다. 직접 명령을 실행하는 run과 구분할 수 있다.

태그 생성 단계에는 create_tag라는 ID를 붙였다. 이후 릴리즈 단계에서 해당 Step의 출력값을 가져온다.

 

${{ steps.create_tag.outputs.new_tag }}

 

자동으로 만들어진 태그 이름을 그대로 사용하므로 버전을 직접 수정할 필요가 없다. 태그와 릴리즈가 어긋나는 것도 줄일 수 있다.

Step의 id를 바꾼다면 출력값을 참조하는 부분도 함께 바꿔야 한다.

태그 생성은 저장소에 쓰는 작업이므로 토큰에 필요한 쓰기 권한이 있어야 한다. GITHUB_TOKEN은 GitHub가 워크플로 실행을 위해 제공하는 토큰이며, 값을 코드에 직접 작성하지 않고 참조한다.

릴리즈는 필요한 시점에 만들면 된다. 이번에는 자동화 흐름을 확인하기 위해 조건에 맞는 push마다 생성하도록 구성했다. 생성 결과는 저장소의 Releases에서 확인할 수 있다.

필요한 변경에만 실행하기

모든 push에 실행하면 설명 파일만 수정해도 릴리즈가 생성될 수 있다. 이를 줄이기 위해 파일 경로 조건을 추가했다.

on:
  push:
    branches:
      - main
    paths:
      - ".github/workflows/**"
      - "src/**"
      - "build.gradle"
      - "Dockerfile"
      - "index.html"

 

브랜치와 경로 조건은 함께 만족해야 한다.

main에 푸시했더라도 README.md만 바뀌었다면 실행되지 않는다. 반면 변경 파일 중 하나라도 지정한 경로에 해당하면 실행 조건을 만족한다.

워크플로 파일 자체를 수정했을 때도 실행하려면 .github/workflows/**를 포함해야 한다. Kotlin DSL 빌드 설정을 사용하는 프로젝트라면 build.gradle.kts도 경로 조건에 포함할지 확인해야 한다.

이번에는 어떤 이벤트에 어떤 작업을 실행할지 선언하고, 단계의 결과를 다음 단계에 연결하는 방식을 이해했다.

 

댓글