100일 챌린지 Day 86 - 재사용 가능한 커스텀 Actions를 만들어봅니다.
배울 내용
- Actions 유형 이해
- JavaScript Action 만들기
- Action 공유하기
Actions 유형
1. JavaScript Action
1
2
3
4
5
6
7
8
9
| 특징:
- Node.js로 작성
- 빠른 실행
- GitHub API 쉽게 사용
사용처:
- API 호출
- 파일 처리
- 간단한 자동화
|
2. Docker Action
1
2
3
4
5
6
7
8
9
| 특징:
- 모든 언어 사용 가능
- 독립적인 환경
- 복잡한 작업 가능
사용처:
- 특정 언어/도구 필요
- 복잡한 빌드
- 시스템 도구 사용
|
3. Composite Action
1
2
3
4
5
6
7
8
| 특징:
- 여러 Step 조합
- YAML로 작성
- 재사용성 높음
사용처:
- 반복되는 Step 패턴
- 워크플로우 템플릿
|
JavaScript Action 만들기
프로젝트 구조
1
2
3
4
5
| my-action/
├── action.yml # Action 메타데이터
├── index.js # 메인 코드
├── package.json
└── README.md
|
1. action.yml 작성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| name: 'Hello Action'
description: '인사 메시지를 출력합니다'
author: 'Your Name'
inputs:
who-to-greet:
description: '인사할 대상'
required: true
default: 'World'
outputs:
greeting-message:
description: '생성된 인사 메시지'
runs:
using: 'node20'
main: 'index.js'
|
2. package.json 작성
1
2
3
4
5
6
7
8
9
| {
"name": "hello-action",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/github": "^5.1.1"
}
}
|
3. index.js 작성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| const core = require('@actions/core');
const github = require('@actions/github');
try {
// Input 가져오기
const nameToGreet = core.getInput('who-to-greet');
// 로직 실행
const message = `Hello ${nameToGreet}!`;
console.log(message);
// Output 설정
core.setOutput('greeting-message', message);
// GitHub 컨텍스트
const payload = JSON.stringify(github.context.payload, null, 2);
console.log(`이벤트 payload: ${payload}`);
} catch (error) {
core.setFailed(error.message);
}
|
4. 의존성 설치
Action 사용하기
로컬 저장소에서
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # .github/workflows/test.yml
name: Test Action
on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Hello Action 사용
uses: ./ # 현재 저장소의 Action
with:
who-to-greet: 'GitHub'
|
다른 저장소에서
1
2
3
4
| steps:
- uses: username/my-action@v1
with:
who-to-greet: 'GitHub'
|
Composite Action 만들기
action.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| name: 'Node.js 설정 및 테스트'
description: 'Node.js 설정, 의존성 설치, 테스트 실행'
inputs:
node-version:
description: 'Node.js 버전'
required: true
default: '20'
runs:
using: 'composite'
steps:
- name: Node.js 설정
uses: actions/setup-node@v4
with:
node-version: $
cache: 'npm'
- name: 의존성 설치
shell: bash
run: npm ci
- name: 테스트 실행
shell: bash
run: npm test
|
사용
1
2
3
4
5
6
| steps:
- uses: actions/checkout@v4
- uses: username/setup-and-test@v1
with:
node-version: '18'
|
Docker Action 만들기
프로젝트 구조
1
2
3
4
5
| my-docker-action/
├── action.yml
├── Dockerfile
├── entrypoint.sh
└── README.md
|
action.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
| name: 'Docker Hello'
description: 'Docker 기반 Action'
inputs:
name:
description: '이름'
required: true
runs:
using: 'docker'
image: 'Dockerfile'
args:
- $
|
Dockerfile
1
2
3
4
5
6
| FROM alpine:latest
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
|
entrypoint.sh
1
2
3
| #!/bin/sh
echo "Hello $1!"
|
실전 예제: PR 크기 체크
action.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| name: 'PR Size Checker'
description: 'PR의 변경 라인 수를 확인합니다'
inputs:
max-lines:
description: '최대 허용 라인 수'
required: true
default: '500'
outputs:
is-valid:
description: 'PR이 유효한지 여부'
runs:
using: 'node20'
main: 'index.js'
|
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
| const core = require('@actions/core');
const github = require('@actions/github');
async function run() {
try {
const maxLines = parseInt(core.getInput('max-lines'));
const token = process.env.GITHUB_TOKEN;
const octokit = github.getOctokit(token);
const { context } = github;
const pr = context.payload.pull_request;
if (!pr) {
core.setFailed('PR 정보를 찾을 수 없습니다');
return;
}
const { data: files } = await octokit.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
});
let totalChanges = 0;
files.forEach(file => {
totalChanges += file.additions + file.deletions;
});
console.log(`총 변경 라인: ${totalChanges}`);
console.log(`최대 허용 라인: ${maxLines}`);
const isValid = totalChanges <= maxLines;
core.setOutput('is-valid', isValid);
if (!isValid) {
core.setFailed(
`PR이 너무 큽니다! (${totalChanges} > ${maxLines})`
);
} else {
console.log('✅ PR 크기가 적절합니다');
}
} catch (error) {
core.setFailed(error.message);
}
}
run();
|
사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| name: Check PR Size
on: pull_request
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: username/pr-size-checker@v1
with:
max-lines: 500
env:
GITHUB_TOKEN: $
|
Action 배포
버전 태그
1
2
3
4
5
6
7
| # 태그 생성
git tag -a v1.0.0 -m "First release"
git push origin v1.0.0
# 메이저 버전 태그 (권장)
git tag -fa v1 -m "Update v1"
git push origin v1 --force
|
사용자들이 사용
1
2
3
4
5
| # 특정 버전
- uses: username/my-action@v1.0.0
# 메이저 버전 (자동 업데이트)
- uses: username/my-action@v1
|
정리
완료 체크:
- Actions 유형 이해
- JavaScript Action 작성
- Composite Action 작성
- Action 배포
핵심 요약:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| Action 유형:
- JavaScript: 빠르고 간단
- Docker: 모든 언어 지원
- Composite: Step 재사용
필수 파일:
- action.yml: 메타데이터
- index.js 또는 Dockerfile
- README.md
배포:
- Git 태그 사용
- v1, v1.0.0 형식
- README에 사용 예시
|
다음: Day 87 - 캐시와 Artifacts →
← Day 86 | 전체 커리큘럼 | Day 87 →