🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

GitHub Actions 커스텀 액션 만들기 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 11. 28. · 19 Views

GitHub Actions 커스텀 액션 만들기 완벽 가이드

GitHub Actions에서 자신만의 커스텀 액션을 만드는 방법을 초급자도 이해할 수 있도록 설명합니다. JavaScript, Docker, Composite 세 가지 액션 타입의 특징과 구현 방법을 실무 예제와 함께 알아봅니다.


목차

  1. 액션_타입_종류
  2. JavaScript_액션_구조
  3. action.yml_메타데이터
  4. @actions/core_라이브러리
  5. Docker_액션_만들기
  6. Composite_액션_만들기

1. 액션 타입 종류

김개발 씨는 회사의 CI/CD 파이프라인을 개선하라는 미션을 받았습니다. 매번 반복되는 배포 스크립트를 재사용 가능한 형태로 만들고 싶었는데, 마켓플레이스에서 딱 맞는 액션을 찾을 수가 없었습니다.

"직접 만들어야 하나?" 고민하던 중, 선배에게 커스텀 액션에 대해 물어보기로 했습니다.

GitHub Actions의 커스텀 액션은 크게 세 가지 타입으로 나뉩니다. JavaScript 액션, Docker 컨테이너 액션, 그리고 Composite 액션입니다.

마치 요리사가 상황에 따라 가스레인지, 오븐, 전자레인지를 선택하듯이, 개발자도 목적에 맞는 액션 타입을 선택해야 합니다.

다음 코드를 살펴봅시다.

# JavaScript 액션 - 빠른 실행, Node.js 환경
# 파일 위치: action.yml
name: 'My JS Action'
runs:
  using: 'node20'
  main: 'dist/index.js'

# Docker 액션 - 격리된 환경, 모든 언어 지원
runs:
  using: 'docker'
  image: 'Dockerfile'

# Composite 액션 - 여러 스텝을 하나로 조합
runs:
  using: 'composite'
  steps:
    - run: echo "Hello"
      shell: bash

김개발 씨는 입사 6개월 차 DevOps 엔지니어입니다. 최근 팀에서 사용하는 GitHub Actions 워크플로우가 점점 복잡해지면서, 비슷한 코드가 여러 저장소에 중복되는 문제가 생겼습니다.

매번 복사-붙여넣기를 하다 보니 한 곳을 수정하면 다른 곳도 일일이 바꿔야 하는 번거로움이 있었습니다. 선배 개발자 박시니어 씨가 커피를 건네며 말했습니다.

"그럴 때 커스텀 액션을 만들면 돼요. 한 번 만들어두면 어디서든 재사용할 수 있거든요." 그렇다면 커스텀 액션이란 정확히 무엇일까요?

쉽게 비유하자면, 커스텀 액션은 마치 레고 블록과 같습니다. 레고로 집을 만들 때 기본 블록들을 조합하듯이, 워크플로우도 여러 액션을 조합해서 만듭니다.

마켓플레이스에 원하는 블록이 없다면? 직접 만들면 됩니다.

GitHub에서는 세 가지 타입의 커스텀 액션을 제공합니다. 첫 번째는 JavaScript 액션입니다.

Node.js 환경에서 실행되며, 가장 빠른 시작 시간을 자랑합니다. GitHub에서 제공하는 러너에 이미 Node.js가 설치되어 있기 때문에 별도의 환경 설정 없이 바로 실행됩니다.

단, JavaScript나 TypeScript로 작성해야 한다는 제약이 있습니다. 두 번째는 Docker 컨테이너 액션입니다.

Docker 이미지 안에서 실행되므로 Python, Go, Rust 등 어떤 언어로든 액션을 만들 수 있습니다. 완전히 격리된 환경에서 실행되어 의존성 충돌 걱정이 없지만, 컨테이너를 빌드하고 시작하는 데 시간이 걸립니다.

Linux 러너에서만 동작한다는 점도 기억해야 합니다. 세 번째는 Composite 액션입니다.

여러 워크플로우 스텝을 하나의 액션으로 묶어주는 방식입니다. 새로운 코드를 작성할 필요 없이 기존 쉘 명령어나 다른 액션들을 조합할 수 있어서 진입 장벽이 가장 낮습니다.

그렇다면 어떤 상황에서 어떤 타입을 선택해야 할까요? 빠른 실행 속도가 중요하고 JavaScript에 익숙하다면 JavaScript 액션이 적합합니다.

특정 런타임이나 도구가 필요하거나 환경 격리가 중요하다면 Docker 액션을 선택하세요. 단순히 여러 스텝을 재사용 가능하게 묶고 싶다면 Composite 액션이 가장 간편합니다.

박시니어 씨의 조언을 들은 김개발 씨는 고개를 끄덕였습니다. "저희 팀은 Node.js를 주로 쓰니까 JavaScript 액션으로 시작해볼게요!" 올바른 액션 타입을 선택하는 것은 성공적인 커스텀 액션 개발의 첫걸음입니다.

다음 장에서는 가장 많이 사용되는 JavaScript 액션의 구조를 자세히 살펴보겠습니다.

실전 팁

💡 - JavaScript 액션은 Windows, macOS, Linux 모든 러너에서 동작합니다

  • Docker 액션은 Linux 러너에서만 사용 가능하다는 점을 기억하세요
  • 처음 시작한다면 Composite 액션으로 간단히 시작해보세요

2. JavaScript 액션 구조

JavaScript 액션을 만들기로 결심한 김개발 씨는 막상 어디서부터 시작해야 할지 막막했습니다. 폴더 구조는 어떻게 잡아야 하고, 어떤 파일들이 필요한지 전혀 감이 오지 않았습니다.

구글링을 해봐도 제각각인 예제들에 혼란스러워하던 중, 박시니어 씨가 기본 템플릿을 보여주었습니다.

JavaScript 액션은 action.yml 메타데이터 파일과 실행 스크립트로 구성됩니다. 마치 책의 표지와 본문처럼, action.yml은 액션의 이름과 입출력을 정의하고, JavaScript 파일은 실제 로직을 담당합니다.

npm 패키지처럼 package.json으로 의존성을 관리할 수 있습니다.

다음 코드를 살펴봅시다.

my-action/
├── action.yml          # 액션 메타데이터 (필수)
├── package.json        # npm 의존성 관리
├── src/
│   └── index.js        # 소스 코드
├── dist/
│   └── index.js        # 번들된 실행 파일
├── README.md           # 사용 설명서
└── node_modules/       # 의존성 (배포 시 번들링)

# 기본 index.js 구조
const core = require('@actions/core');

async function run() {
  const name = core.getInput('name');
  core.setOutput('greeting', `Hello, ${name}!`);
}

run();

김개발 씨는 빈 폴더 앞에서 한숨을 쉬었습니다. "도대체 뭐부터 만들어야 하는 거지?" 선배가 다가와 화이트보드에 폴더 구조를 그리기 시작했습니다.

JavaScript 액션의 구조는 생각보다 단순합니다. 가장 중요한 파일은 action.yml입니다.

이 파일은 마치 신분증과 같습니다. 액션의 이름이 무엇인지, 어떤 입력값을 받는지, 어떤 출력값을 내보내는지, 그리고 어떤 파일을 실행해야 하는지를 정의합니다.

GitHub는 이 파일을 보고 액션을 인식하고 실행합니다. 다음으로 중요한 것은 실행 스크립트입니다.

src 폴더에 소스 코드를 작성하고, 이를 번들링하여 dist 폴더에 단일 파일로 만듭니다. 왜 번들링을 할까요?

node_modules 폴더를 그대로 저장소에 올리면 수천 개의 파일이 포함됩니다. 이는 저장소를 무겁게 만들고, 액션 실행 시 체크아웃 시간을 늘립니다.

nccesbuild 같은 도구로 번들링하면 모든 의존성이 하나의 파일로 합쳐져 빠르고 깔끔합니다. package.json은 일반적인 npm 프로젝트와 동일하게 사용합니다.

다만 몇 가지 핵심 의존성은 거의 필수적으로 포함됩니다. @actions/core는 입출력 처리, 로깅, 시크릿 마스킹 등 액션 개발의 핵심 기능을 제공합니다.

@actions/github는 GitHub API와 상호작용할 때 사용합니다. 이 두 패키지는 GitHub에서 공식으로 제공하며, 대부분의 JavaScript 액션에서 활용됩니다.

README.md는 선택사항이지만 강력히 권장됩니다. 마켓플레이스에 공개할 때 사용자들이 가장 먼저 보는 문서이기 때문입니다.

입력값, 출력값, 사용 예제를 명확히 작성해두면 다른 개발자들이 쉽게 사용할 수 있습니다. 실제 개발 흐름을 살펴볼까요?

먼저 npm init으로 프로젝트를 초기화합니다. 그다음 필요한 패키지를 설치하고 src/index.js에 로직을 작성합니다.

개발이 완료되면 ncc build로 번들링하고, action.yml에서 dist/index.js를 실행 파일로 지정합니다. 김개발 씨가 구조를 이해하자 박시니어 씨가 덧붙였습니다.

"구조를 알았으니 이제 action.yml을 자세히 들여다볼까요? 이게 액션의 핵심이거든요."

실전 팁

💡 - @vercel/ncc를 사용하면 의존성을 단일 파일로 번들링할 수 있습니다

  • dist 폴더는 반드시 커밋해야 합니다. gitignore에 추가하지 마세요
  • TypeScript로 작성하고 JavaScript로 컴파일하는 것도 좋은 방법입니다

3. action.yml 메타데이터

김개발 씨는 action.yml 파일을 열어보았습니다. 몇 줄 안 되는 코드인데, 각 줄이 무엇을 의미하는지 정확히 알 수 없었습니다.

"name은 알겠는데, branding은 뭐고 inputs의 required는 어떻게 동작하는 거죠?" 박시니어 씨가 하나씩 짚어가며 설명을 시작했습니다.

action.yml은 액션의 모든 메타데이터를 담는 핵심 설정 파일입니다. 마치 상품의 라벨처럼 이름, 설명, 입력값, 출력값, 실행 방법을 정의합니다.

이 파일이 없으면 GitHub는 해당 폴더를 액션으로 인식하지 못합니다.

다음 코드를 살펴봅시다.

name: 'Greeting Action'
description: '사용자에게 인사하는 간단한 액션입니다'
author: 'kimdev'

# 마켓플레이스 아이콘 설정
branding:
  icon: 'message-circle'
  color: 'green'

# 입력 파라미터 정의
inputs:
  name:
    description: '인사할 대상의 이름'
    required: true
    default: 'World'
  greeting-type:
    description: '인사 유형 (formal/casual)'
    required: false
    default: 'casual'

# 출력 값 정의
outputs:
  message:
    description: '생성된 인사 메시지'

# 실행 설정
runs:
  using: 'node20'
  main: 'dist/index.js'

action.yml 파일을 처음 보면 복잡해 보이지만, 하나씩 뜯어보면 논리적인 구조를 가지고 있습니다. 가장 먼저 나오는 namedescription은 액션의 신원을 밝히는 부분입니다.

마켓플레이스에 공개하면 이 이름과 설명이 검색 결과에 표시됩니다. 짧고 명확하게 작성하는 것이 좋습니다.

branding 섹션은 마켓플레이스용 아이콘을 설정합니다. 필수는 아니지만, 공개 액션이라면 설정하는 것을 권장합니다.

icon은 Feather Icons에서 선택할 수 있고, color는 미리 정의된 색상 중 하나를 고릅니다. 핵심은 inputsoutputs 섹션입니다.

inputs는 액션이 받아들이는 파라미터를 정의합니다. 마치 함수의 매개변수와 같습니다.

각 입력값에는 description으로 설명을 붙이고, required로 필수 여부를 지정합니다. default 값을 설정하면 사용자가 값을 제공하지 않았을 때 기본값이 사용됩니다.

여기서 주의할 점이 있습니다. required가 true여도 default가 있으면 에러가 발생하지 않습니다.

기본값이 사용되기 때문입니다. 정말로 사용자가 반드시 값을 제공하게 하려면 default를 생략해야 합니다.

outputs는 액션이 내보내는 결과값을 정의합니다. 다른 스텝에서 이 값을 참조할 수 있습니다.

워크플로우에서 steps.스텝아이디.outputs.출력이름 형식으로 접근합니다. runs 섹션은 액션의 실행 방법을 지정합니다.

JavaScript 액션이라면 using에 node16, node18, node20 중 하나를 선택합니다. 숫자가 클수록 최신 Node.js 버전입니다.

main에는 실행할 JavaScript 파일 경로를 적습니다. 추가로 prepost 스크립트를 지정할 수 있습니다.

pre는 main 실행 전에, post는 main 실행 후에 실행됩니다. 예를 들어 pre에서 환경을 설정하고 post에서 정리 작업을 수행할 수 있습니다.

김개발 씨가 고개를 끄덕이며 말했습니다. "inputs로 값을 받고, outputs로 결과를 내보내는 거군요.

그런데 코드에서 이 값들을 어떻게 읽고 쓰나요?" 박시니어 씨가 미소를 지었습니다. "좋은 질문이에요.

바로 @actions/core 라이브러리가 그 역할을 합니다."

실전 팁

💡 - inputs의 이름은 케밥 케이스(kebab-case)를 권장합니다

  • 민감한 정보를 다룬다면 해당 input에 secret: true를 고려하세요
  • runs.using에는 가능하면 최신 Node.js 버전을 사용하세요

4. @actions/core 라이브러리

김개발 씨는 드디어 실제 코드를 작성할 차례가 되었습니다. action.yml에서 정의한 입력값을 어떻게 읽어오고, 출력값은 어떻게 내보내는 걸까요?

또 에러가 발생하면 어떻게 처리해야 할까요? GitHub에서 제공하는 @actions/core 라이브러리가 이 모든 것을 담당합니다.

@actions/core는 GitHub Actions 개발의 스위스 아미 나이프입니다. 입력값 읽기, 출력값 설정, 로깅, 시크릿 마스킹, 액션 상태 관리 등 필수 기능을 제공합니다.

이 라이브러리 없이 JavaScript 액션을 만드는 것은 맨손으로 요리하는 것과 같습니다.

다음 코드를 살펴봅시다.

const core = require('@actions/core');
const github = require('@actions/github');

async function run() {
  try {
    // 입력값 읽기
    const name = core.getInput('name', { required: true });
    const greetingType = core.getInput('greeting-type');

    // 로깅
    core.info(`인사 대상: ${name}`);
    core.debug('디버그 모드에서만 보이는 메시지');

    // 시크릿 마스킹
    const token = core.getInput('token');
    core.setSecret(token);

    // 출력값 설정
    const message = `Hello, ${name}!`;
    core.setOutput('message', message);

    // 워크플로우 요약 작성
    core.summary.addHeading('인사 완료').write();

  } catch (error) {
    // 실패 처리
    core.setFailed(`액션 실패: ${error.message}`);
  }
}

run();

JavaScript 액션을 만들 때 @actions/core 라이브러리는 필수입니다. 이 라이브러리가 제공하는 함수들을 하나씩 살펴보겠습니다.

가장 먼저 알아야 할 함수는 getInput입니다. action.yml에서 정의한 입력값을 읽어옵니다.

첫 번째 인자로 입력 이름을 전달하고, 옵션으로 required를 지정할 수 있습니다. required가 true인데 값이 없으면 에러가 발생합니다.

한 가지 주의할 점이 있습니다. getInput은 항상 문자열을 반환합니다.

불리언 값이 필요하다면 getBooleanInput을 사용하세요. 'true', 'True', 'TRUE' 등을 모두 true로 변환해줍니다.

setOutput은 출력값을 설정합니다. 다른 스텝에서 이 값을 참조할 수 있게 해줍니다.

예를 들어 빌드 버전을 계산해서 출력하면, 다음 스텝에서 그 버전을 사용할 수 있습니다. 로깅 함수도 여러 가지가 있습니다.

core.info는 일반 정보를, core.warning은 경고를, core.error는 에러를 출력합니다. core.debug는 특별합니다.

워크플로우에서 ACTIONS_STEP_DEBUG 시크릿을 true로 설정해야만 보입니다. 개발 중 디버깅에 유용합니다.

setSecret은 민감한 정보를 마스킹합니다. 이 함수로 등록한 값은 로그에 ***로 표시됩니다.

API 토큰이나 비밀번호를 다룰 때 반드시 사용해야 합니다. 가장 중요한 함수 중 하나가 setFailed입니다.

이 함수를 호출하면 액션이 실패 상태로 종료됩니다. try-catch로 에러를 잡아서 setFailed로 처리하는 것이 일반적인 패턴입니다.

이렇게 하면 어떤 에러가 발생했는지 명확히 알 수 있습니다. GitHub Actions의 최신 기능인 Job Summary도 지원합니다.

core.summary를 사용하면 워크플로우 실행 결과 페이지에 마크다운 형식의 요약을 표시할 수 있습니다. 테스트 결과나 배포 정보를 보기 좋게 정리할 때 유용합니다.

@actions/github 라이브러리도 함께 알아두면 좋습니다. 이 라이브러리는 GitHub API 클라이언트와 컨텍스트 정보를 제공합니다.

github.context로 현재 실행 중인 워크플로우의 정보(저장소, 이벤트, 커밋 SHA 등)에 접근할 수 있습니다. 김개발 씨는 코드를 따라 치며 이해가 되기 시작했습니다.

"이제 JavaScript 액션은 알겠어요. 그런데 Python이나 Go로 액션을 만들고 싶으면 어떻게 해야 하나요?" 박시니어 씨가 답했습니다.

"그럴 때는 Docker 액션을 사용하면 됩니다."

실전 팁

💡 - 항상 try-catch로 감싸고 catch에서 setFailed를 호출하세요

  • 민감한 정보는 반드시 setSecret으로 마스킹하세요
  • core.summary로 실행 결과를 보기 좋게 정리하면 사용자 경험이 좋아집니다

5. Docker 액션 만들기

김개발 씨의 팀에 새로운 프로젝트가 생겼습니다. Python으로 작성된 코드 분석 도구를 GitHub Actions로 만들어야 하는데, JavaScript로 다시 작성하기엔 시간이 부족했습니다.

"이럴 때 Docker 액션이 딱이에요." 박시니어 씨가 새로운 방법을 알려주었습니다.

Docker 액션은 컨테이너 안에서 실행되므로 어떤 언어로든 액션을 만들 수 있습니다. Python, Go, Rust, 심지어 Bash 스크립트도 가능합니다.

마치 이사할 때 모든 짐을 컨테이너에 담아 운반하듯이, 필요한 모든 의존성을 Docker 이미지에 담아 배포합니다.

다음 코드를 살펴봅시다.

# action.yml
name: 'Python Analyzer'
description: 'Python으로 코드를 분석합니다'
inputs:
  path:
    description: '분석할 경로'
    required: true
    default: '.'
runs:
  using: 'docker'
  image: 'Dockerfile'
  args:
    - ${{ inputs.path }}

# Dockerfile
FROM python:3.11-slim

COPY requirements.txt /requirements.txt
RUN pip install -r /requirements.txt

COPY entrypoint.py /entrypoint.py
RUN chmod +x /entrypoint.py

ENTRYPOINT ["python", "/entrypoint.py"]

# entrypoint.py
import os
import sys

def main():
    path = sys.argv[1] if len(sys.argv) > 1 else '.'
    print(f"Analyzing: {path}")
    # 분석 로직...

if __name__ == '__main__':
    main()

Docker 액션은 JavaScript 액션과 다른 접근 방식을 취합니다. 코드가 Docker 컨테이너 안에서 실행되므로, 완전히 격리된 환경을 갖습니다.

왜 Docker 액션을 선택할까요? 첫 번째 이유는 언어의 자유입니다.

JavaScript가 아닌 다른 언어로 이미 작성된 도구가 있다면, Docker 액션으로 쉽게 감쌀 수 있습니다. Python 린터, Go 빌드 도구, Rust 분석기 등 무엇이든 가능합니다.

두 번째 이유는 환경 일관성입니다. 개발 환경과 CI 환경의 차이로 인한 "내 컴퓨터에서는 되는데" 문제를 방지합니다.

필요한 모든 의존성이 이미지에 포함되어 있으니까요. Docker 액션을 만들려면 세 가지 파일이 필요합니다.

action.yml에서 runs.using을 'docker'로 설정하고, image에 'Dockerfile'을 지정합니다. args로 입력값을 컨테이너에 전달할 수 있습니다.

Dockerfile은 일반적인 Docker 이미지 빌드 파일입니다. 베이스 이미지를 선택하고, 의존성을 설치하고, 실행 스크립트를 복사합니다.

ENTRYPOINT로 실행할 명령을 지정합니다. entrypoint 스크립트가 실제 로직을 담당합니다.

쉘 스크립트일 수도 있고, Python 스크립트일 수도 있습니다. 환경 변수로 입력값을 받거나, 커맨드 라인 인자로 받을 수 있습니다.

입출력 처리 방식이 JavaScript 액션과 다릅니다. 입력값은 INPUT_이름 형식의 환경 변수로 전달됩니다.

예를 들어 path 입력은 INPUT_PATH 환경 변수로 접근합니다. 또는 action.yml의 args를 통해 커맨드 라인 인자로 전달할 수도 있습니다.

출력값을 설정하려면 GITHUB_OUTPUT 환경 변수가 가리키는 파일에 이름=값 형식으로 씁니다. 과거에는 echo "::set-output name=이름::값" 형식을 사용했지만, 현재는 deprecated되었습니다.

Docker 액션의 단점도 있습니다. 컨테이너를 빌드하고 시작하는 데 시간이 걸립니다.

간단한 작업이라면 JavaScript 액션보다 느릴 수 있습니다. 또한 Linux 러너에서만 동작합니다.

Windows나 macOS 러너에서는 사용할 수 없습니다. 성능을 개선하려면 미리 빌드된 이미지를 사용할 수 있습니다.

action.yml의 image에 'Dockerfile' 대신 'docker://ghcr.io/사용자/이미지:태그'처럼 레지스트리 경로를 지정하면 됩니다. 김개발 씨가 Docker 액션을 테스트해보았습니다.

"오, Python 도구가 그대로 동작하네요! 그런데 더 간단한 방법은 없나요?

그냥 몇 개 명령어를 묶고 싶을 뿐인데..." 박시니어 씨가 웃으며 말했습니다. "그럴 때는 Composite 액션이 있죠."

실전 팁

💡 - 베이스 이미지는 가능하면 slim이나 alpine 버전을 사용해 크기를 줄이세요

  • 자주 변경되지 않는 레이어를 먼저 빌드하면 캐시 효율이 좋아집니다
  • 미리 빌드된 이미지를 사용하면 실행 시간을 단축할 수 있습니다

6. Composite 액션 만들기

김개발 씨는 팀의 여러 저장소에서 같은 배포 스크립트가 반복되는 것을 발견했습니다. Node.js 설치, 의존성 캐싱, 빌드, 배포까지 거의 동일한 10개의 스텝이 복사-붙여넣기 되어 있었습니다.

"이걸 하나로 묶을 수 없을까?" JavaScript나 Docker를 새로 작성하기엔 과한 것 같았습니다.

Composite 액션은 여러 워크플로우 스텝을 하나의 재사용 가능한 단위로 묶어줍니다. 마치 요리 레시피처럼, 여러 단계를 하나의 요리법으로 정리하는 것입니다.

새로운 코드를 작성할 필요 없이 기존 쉘 명령어와 다른 액션들을 조합합니다.

다음 코드를 살펴봅시다.

# action.yml
name: 'Node.js Build and Deploy'
description: 'Node.js 프로젝트 빌드 및 배포 통합 액션'
inputs:
  node-version:
    description: 'Node.js 버전'
    required: false
    default: '20'
  deploy-target:
    description: '배포 대상 (staging/production)'
    required: true

runs:
  using: 'composite'
  steps:
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ inputs.node-version }}
        cache: 'npm'

    - name: Install dependencies
      shell: bash
      run: npm ci

    - name: Build
      shell: bash
      run: npm run build

    - name: Deploy
      shell: bash
      run: |
        echo "Deploying to ${{ inputs.deploy-target }}"
        npm run deploy:${{ inputs.deploy-target }}

outputs:
  build-version:
    description: '빌드 버전'
    value: ${{ steps.get-version.outputs.version }}

Composite 액션은 세 가지 타입 중 가장 접근하기 쉽습니다. JavaScript를 작성하거나 Docker를 설정할 필요 없이, 익숙한 워크플로우 문법 그대로 사용합니다.

어떤 상황에서 Composite 액션이 적합할까요? 여러 저장소에서 동일한 스텝 패턴이 반복될 때입니다.

Node.js 프로젝트 설정, Python 환경 구성, 특정 클라우드로의 배포 등 비슷한 스텝 조합이 계속 나타난다면 Composite 액션으로 묶을 수 있습니다. 기존 액션들을 조합하고 싶을 때도 적합합니다.

actions/checkout, actions/setup-node 같은 공식 액션들을 조합해서 팀만의 표준 패턴을 만들 수 있습니다. Composite 액션의 구조는 간단합니다.

runs.using을 'composite'로 설정하고, steps에 일반 워크플로우처럼 스텝들을 나열합니다. 다른 액션을 uses로 호출할 수도 있고, run으로 쉘 명령어를 실행할 수도 있습니다.

중요한 규칙이 하나 있습니다. run을 사용할 때는 반드시 shell을 명시해야 합니다.

일반 워크플로우에서는 기본값이 있지만, Composite 액션에서는 필수입니다. bash, sh, pwsh, python 등을 지정할 수 있습니다.

입력값은 ${{ inputs.이름 }} 형식으로 접근합니다. JavaScript 액션의 getInput과 달리 표현식 문법을 사용합니다.

스텝 간에 값을 전달하려면 GITHUB_OUTPUT 파일에 기록하고 steps 컨텍스트로 참조합니다. 출력값 설정도 독특합니다.

outputs 섹션에서 value에 표현식을 사용해 특정 스텝의 출력을 그대로 노출하거나 가공할 수 있습니다. Composite 액션의 장점은 투명성입니다.

워크플로우 로그에서 각 스텝이 개별적으로 표시됩니다. JavaScript나 Docker 액션은 하나의 스텝으로 보이지만, Composite 액션은 내부 스텝들이 모두 펼쳐져 보입니다.

디버깅할 때 어느 스텝에서 문제가 생겼는지 바로 알 수 있습니다. 단점도 있습니다.

복잡한 로직이 필요하다면 YAML만으로는 표현하기 어렵습니다. 조건문, 반복문, 에러 처리 등이 복잡해지면 JavaScript 액션이 더 적합합니다.

Composite 액션 안에서 다른 Composite 액션을 호출할 수도 있습니다. 하지만 너무 깊게 중첩되면 디버깅이 어려워지니 적절히 사용해야 합니다.

김개발 씨는 팀의 배포 스크립트를 Composite 액션으로 리팩토링했습니다. 10개의 스텝이 하나의 uses 문으로 바뀌자 워크플로우 파일이 훨씬 깔끔해졌습니다.

"이제 한 곳만 수정하면 모든 저장소에 반영되겠네요!" 김개발 씨가 뿌듯하게 말했습니다. 박시니어 씨가 고개를 끄덕였습니다.

"맞아요. 이게 바로 재사용의 힘이에요.

이제 당신도 커스텀 액션을 만들 수 있는 개발자가 됐네요."

실전 팁

💡 - Composite 액션의 모든 run 스텝에는 shell을 반드시 명시하세요

  • 너무 많은 스텝을 하나로 묶으면 유연성이 떨어집니다. 적절히 분리하세요
  • working-directory를 사용해 스텝별로 실행 경로를 지정할 수 있습니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#GitHub Actions#Custom Actions#CI/CD#DevOps#Automation#GitHub Actions,CI/CD,DevOps

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.