github action 주요 component로는 다음이 있다.
.github/workflows
경로에 파일이 있어야하고, 여러 개의 workflow들이 있을 수 있다.push
, pull
등이 있고, 시간, 외부 요청으로도 가능하다.job
을 실행할 수 있는 서버로 각 runner는 하나의 job
을 실행할 수 있다. job
은 동일한 runner
에서 실행될 수 있는 각 step들의 집합이다. workflow안에 job들은 여러 개가 있을 수 있는데, 병렬 실행, 순차 실행(needs)이 가능하다.uses
라는 키워드를 이용해서 action
을 로드한다. 하나의 step에서 하나의 action만 사용할 수 있다. action에는 github
에서 공식 제공 action과 community에서 만든 action, 사용자가 직접 만든 action들도 있다.
Event ---> -------Runner:unbuntu-latest--------
| job: check-bats-version--------- |
| | step1: check out repo | |
| | - uses: actions/checkout@v3 | |
| | | |
| | step2: install Node.js | |
| | - uses: actions/setup-node@v3| |
| -------------------------------- |
------------------------------------
setup-node
라는 action으로 nodejs를 쉽게 설치할 수 있는 것이다.
github marketplace는 action의 저장소로 직접 만든 custom action을 publish할 수 있다. 필요한 기능이 있다면 사용하는 게 편리하다.
checkout
이라는 github action을 사용할 수 있느데, 여기서 사용 방법들 나열된 것을 볼 수 있다.
- uses: actions/checkout@v4
with:
# Repository name with owner. For example, actions/checkout
# Default: ${{ github.repository }}
repository: ''
# The branch, tag or SHA to checkout. When checking out the repository that
# triggered a workflow, this defaults to the reference or SHA for that event.
# Otherwise, uses the default branch.
ref: ''
...
with
은 하나의 parameter를 받는 것으로 repository
와 ref
라는 parameter를 받는다는 것이다. 이는 다른 repo의 특정 code나 다른 branch의 code를 사용하고 싶다면 여기에 입력해주면 된다.
github action의 핵심은 event
에 따른 action
인 것이다. 따라서, 어떠한 event
들이 먼저 알아보고, 이에 따른 action
들에 대한 example들을 살펴보자
git push
event가 발생하면 github action이 발생하도록 하는 것이다. 자신의 github repo에 .github/workflows
디렉터리를 만들고 다음의 파일을 만들도록 하자.
name: push-workflow
on: push # event
jobs:
push-job:
runs-on: ubuntu-latest # runner
steps: # job이 실행할 step들을 순차적으로 적는다.
- name: step1
run: echo hello world
- name: step2
run: |
echo hello world
echo githu action
다른 github action을 실행시키기 위해서 .github/workflows/push.yaml
을 .github/workflows/push/push.yaml
에 저장시키도록 하자. 이렇게두면 push.yaml
이 실행되지 않는다.
pull request가 실행되면 발생하는 event를 만들어보도록 하자.
name: pull-request-workflow
on: pull_request
jobs:
pull-request-job:
runs-on: ubuntu-latest # runner
steps: # job이 실행할 step들을 순차적으로 적는다.
- name: step1
run: echo hello world
- name: step2
run: |
echo hello world
echo github action
다른 branch를 하나 만들고 commit을 올려주도록 하자.
git switch -c test1
echo "h" >> ./README.md
git add ./README.md
git commit -m "add2"
git push origin test1
이제 github로 가서 pull request를 만들어주도록 하자, 단 'Merge pull request' 버튼은 누르지 않도록 하자. pull request가 올라간 것 만으로도 github action이 실행될 것이다.
한번 더 commit을 만들어주면 이전에 만들었던 pull request에 commit이 추가될 것이다.
git switch -c test1
echo "h" >> ./README.md
git add ./README.md
git commit -m "add2"
git push origin test1
그런데, 이상한 것이 있다. github action을 보면 action이 두 번 실행되었을 것이다. 즉, 새로 올린 commit에 대해서 pull request를 만들지 않고, 기존 pull request에 포함된 것임에도 불구하고 github action이 또 실행되는 것이다.
왜 이렇게 되었냐면, pull_request
를 on
에 설정할 때 default activity 때문에 그렇다. 만약 pull request를 open시킬 때만 github action을 실행시키고 싶었다면 다음과 같이 정의하면 된다.
name: pull-request-workflow
on:
pull_request:
types: [opened]
jobs:
pull-request-job:
runs-on: ubuntu-latest # runner
steps: # job이 실행할 step들을 순차적으로 적는다.
- name: step1
run: echo hello world
- name: step2
run: |
echo hello world
echo github action
이런식으로 정의하면 pull request가 생성된 시점에만 실행된다. 모든 event들이 activity type이 있는 것은 아니고, event마다 activity type이 다르다.
issue event는 bug, 기능 요청, 질문, 논의 등 추적 및 관리하기 위해서 사용하는데, project의 버그나 기능 개발 등의 진행 상황을 한눈에 파악할 수 있다. issue를 생성할 때 trigger되는 github action을 만들어보도록 하자. 단, issue event는 오직 default branch에 workflow가 있어야만 동작한다는 특징이 있다.
issue event도 activity가 있는데, default로 모든 issue에 대해서 trigger된다는 특징이 있다.
name: issue-workflow
on:
issues:
types: [opened]
jobs:
push-job:
runs-on: ubuntu-latest # runner
steps: # job이 실행할 step들을 순차적으로 적는다.
- name: step1
run: echo hello world
issue
가 open될 때에만 해당 github action이 실행된다.
issue comment는 issue에 comment를 생성하거나, pull request에 comment를 생성할 때 실행되는 action을 말한다. activity로 default는 모든 type들이고, type으로는 created
, edited
, deleted
3개가 있다.
name: issue-comment-workflow
on: issue_comment
jobs:
pr-comment:
if: ${{ github.event.issue.pull_request }}
runs-on: ubuntu-latest
steps:
- name: pr comment
run: echo ${{ github.event.issue.pull_request }}
issue-comment:
if: ${{ !github.event.issue.pull_request }}
runs-on: ubuntu-latest
steps:
- name: issue comment
run: echo ${{ github.event.issue.pull_request }}
두 가지 job인 pr-comment
와 issue-comment
가 있는데, pr-comment
는 pull request에 comment가 생기면 job을 실행하도록 하기위해서 if
문을 ${{ github.event.issue.pull_request }}
으로 써주었다. issue-comment
는 issue에 comment가 추가될 때 실생되도록 if
문에 ${{ !github.event.issue.pull_request }}
을 넣어주었다.
이러한 코드를 context라고 한다. context를 넣어주면 유연한 동작이 가능하다.
cron으로 특정 시간마다 github action을 실행시켜주는 것이다. default branch에 github workflow가 있어야 동작한다. 그러나, schedule
은 부하가 많기 때문에 실행에 있어서 누락이 있을 가능성이 높다. 그래서 정확한 시간에 정확하게 실행되어야 하는 app에 대해서는 schedule
을 쓰지 않도록 하자. 특히, 5분 30분 간격의 cron job들에 대해서는 누락이 많이 된다.
name: schedule-workflow
on:
schedule:
- cron: '15 * * * *'
jobs:
schedule-job:
runs-on: ubuntu-latest
steps:
- name: schedule test
run: echo hello world
사용자가 원할 때 수동으로 trigger할 수 있는 event가 있는데, default branch에서만 동작한다. 또한, input 값을 넣을 수 있다는 특징이 있는데, input 데이터의 type으로는 다음과 같다.
choice
는 미리 옵션으로 지정한 것들을 넣을 수 있다.
name: workflow-dispatch
on:
workflow_dispatch:
inputs:
name:
description: 'set name'
required: true
default: 'github-actions'
type: string
environment:
description: 'set env'
required: true
default: 'dev'
type: choice
options:
- dev
- prod
inputs
이라는 keyword를 통해서 값을 받을 수 있는데, name
과 environment
input을 파라미터로 받는다. 각 파라미터는 description
, required
, default
, type
을 설정해주어야 한다.
choice
의 경우는 options
를 통해서 설정이 가능하다.
이 input값들은 workflow의 job에서 다음과 같이 사용이 가능하다.
jobs:
workflow-dispatch-job:
runs-on: ubuntu-lates
steps:
- name: step1 echo hello world
run: echo Hello, world!
- name: step2 echo github action
run: |
echo hello, world!
echo github action!
- name: echo inputs
run: |
echo "NAME: ${{ inputs.name }}"
echo "NAME: ${{ inputs.environment }}"
inputs.name
, inputs.environment
로 접근 가능한 것을 볼 수 있다.
name: workflow-dispatch
on:
workflow_dispatch:
inputs:
name:
description: 'set name'
required: true
default: 'github-actions'
type: string
environment:
description: 'set env'
required: true
default: 'dev'
type: choice
options:
- dev
- qa
- prod
jobs:
workflow-dispatch-job:
runs-on: ubuntu-latest
steps:
- name: step1
run: echo hello world
- name: step2
run: |
echo hello world
echo github action
- name: echo inputs
run: |
echo ${{ inputs.name }}
echo ${{ inputs.environment }}
github에 넣어준 다음에 github actions tab으로 가면 Run workflow
라는 버튼이 있다. 이 버튼을 누르면 수동으로 실행시켜줄 수 있는 버튼들이 나온다.
on
event에 여러 개의 event를 주도록 하여, 하나의 workflow를 실행시킬 수 있다.
name: multiple-event-workflow
on:
push:
issues:
types: [opened]
workflow_dispatch:
jobs:
multiple-event-job:
runs-on: ubuntu-latest # runner
steps: # job이 실행할 step들을 순차적으로 적는다.
- name: step1
run: echo hello world
- name: step2
run: |
echo hello world
echo github action
위의 코드는 push
, issue
가 열릴 때, 수동으로 workflow를 실행시킬 때 해당 job들이 실행된다는 것을 나타낸다. 따라서 여러 개의 event에 대해서 하나의 workflow를 실행시킬 수 있는 것이다.
하나의 workflow에서 여러 개의 job을 정의해서 사용하는 경우가 많다.
jobs:
pr-comment:
if: ${{ github.event.issue.pull_request }}
runs-on: ubuntu-latest
steps:
- name: pr comment
run: echo ${{ github.event.issue.pull_request }}
issue-comment:
if: ${{ !github.event.issue.pull_request }}
runs-on: ubuntu-latest
steps:
- name: issue comment
run: echo ${{ github.event.issue.pull_request }}
이렇게 하나의 workflow에 여러 개의 job이 있는 경우, 병렬로 실행된다는 특징을 갖는다.
그런데, 순차적으로 실행이 필요한 경우가 있는데 이렇게 의존 관계가 있는 경우에는 needs
를 사용한다.
needs
는 하나의 job이 다른 job 또는 여러 job이 완료될 때, 실행되도록 할 수 있다. 이를 통해서 여러 job의 실행 순서를 조절할 수 있는 것이다.
가장 대표적인 경우가 test job이 실행되고 나서 배포 job이 실행되도록 할 수 있다.
name: needs
on: push
jobs:
job1:
runs-on: ubuntu-latest
steps:
- name: echo
run: echo "job1 done"
job2:
runs-on: ubuntu-latest
needs: [job1]
steps:
- name: echo
run: echo "job2 done"
job3:
runs-on: ubuntu-latest
steps:
- name: echo
run: |
echo "job3 failed"
exit 1
job4:
runs-on: ubuntu-latest
needs: [job3]
steps:
- name: echo
run: echo "job4 done"
job1이 실행되어 성공해야 job2가 실행되고, job3이 실행되어야 job4가 실행된다. 단, job3의 경우 exit 1
을 주었는데, github action은 exit 1
을 실행하면 실패로 여기기 때문에 job4
는 실행되지 않을 것이다.
이제 code를 push해보고 결과를 확인해보도록 하자.
job1 o---------o job2
job3 o---------o iob4
이렇게 나오고 job1, job2는 실행되었지만, job3는 실행되지 않아 job4도 실행되지 않는 것을 볼 수 있다.
job3가 실패했으므로 re-run
을 트리거할 수 있다. re-run
은 과거에 실행된 workflow를 재실행하는 것으로, 성공과 실패의 상관없이 재실행이 가능하다. 단, trigger된 그 시점을 다시 실행하는 것이다.
즉, 특정 workflow를 re-run
시켜도 해당 workflow 이후의 commit들에 대해서 반영되지 않은, 딱 그 workflow가 실행된 처음 시점의 commit을 기준으로만 re-run
되는 것이다. 따라서, 과거에 실행된 workflow를 re-run
해도 수정한 내용은 반영되지 않는다. 수정한 파일이 포함된 commit을 만들고, 새로운 workflow가 실행되어야 반영되는 것이다.
+ commit1
workflow#1 --- commit1
+ commit2
workflow#2 --- commit2
commit1
이 들어온 후에 workflow#1
이 실행되었다고 하자. 이 다음 commit2
가 들어와서 workflow#2
가 실행되었는데, workflow#1
을 re-run시켜버리면 commit2
까지 반영된 코드가 아니라 commit
만 반영된 code로 실행된다는 것이다.