GitHub Actions
ビルドテスト自動化ツールとしてGitHub Actionsが現在社内で利用されている。
DevOpsを学んでいく上で、Jenkinsに並んで学んでおくべきCI/CDツールの一つである。
学んだ知見を本ページに集約する。
Tips
別リポジトリのWorkflowをキックする方法
各コンポーネントが更新されたのを契機に、インテグレーションをして統合テストを行いたい場合がある。コンポーネントごとにリポジトリが分かれていてそれぞれ別のチームで管理している場合、リポジトリ間のWorkflowを連携させたい。
Jenkinsであれば容易に親JOBから子JOBを呼び出すことが可能だが、GithubActionsの場合Workflowが各リポジトリに紐づいておりリポジトリ間の連携を行うのには一工夫いる。
(上記理由で、大規模ソフトウェア開発では各JOBが一元管理されるJenkinsがツールとしては使いやすいと個人的には思う。)
では具体的にどのようにすれば良いかというと、Githubの提供するAPIを利用する。
呼び出し元リポジトリのWorkflowから、curlで呼び出し先リポジトリのAPIをたたいてトリガーする。
ただし、この方法では呼び出し元リポジトリ側では、呼び出し先のリポジトリのworkflowの結果は見えないため、呼び出し先workflowの結果を呼び出し元リポジトリに知らせるような工夫が必要などの制約がある。いずれにしてもJenkinsのように各リポジトリのワークフローの一元管理ができないため、大規模ソフトウェアの開発における管理は難しいと思う。
それでは、具体例を示す。
呼び出し元リポジトリのworkflow(.github/workflows/sampleA.yml)は以下の通りである。
.github/workflows/sampleA.yml
---
name: Trigger to another repo
on:
push:
jobs:
trigger-to-another-repo:
runs-on: ubuntu-latest
steps:
- name: send
run: |
TOKEN=${{ secrets.PAT }}
ORG=${{ secrets.ORG }}
REPO=${{ secrets.TRIGGERREPO }}
## curl
curl \
-X POST \
-H "Authorization: token $TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/$ORG/$REPO/dispatches \
-d '{"event_type":"dispatch-test","client_payload":{"message": "Hello"}}'
client_payloadを利用して、呼び出し先リポジトリにmessageを渡すことが可能である。
(今回はHelloというmessageを送る。)
“https://api.github.com/repos/"を今回使用しているが、環境によっては"https://github.〇〇〇.com/api/v3/repos/"を使用する。
続いて、呼び出し先リポジトリのworkflow(.github/workflows/sampleB.yml)の例を示す。
.github/workflows/sampleB.yml
---
name: Triggered from other repo
on:
repository_dispatch:
types: [dispatch-test]
jobs:
triggered-from-other-repo:
runs-on: ubuntu-latest
steps:
- name: Receive
run: |
message=${{ github.event.client_payload.message }}
echo "message from other repo = $message"
実行契機として、repository_dispatchを用いる。
typesには呼び出し元で指定した"event_type"を指定する。(今回はdispatch-test)
実行結果は次の通りとなる。
呼び出し元(sampleA)実行結果
呼び出し先(sampleB)実行結果
matrix構文
複数のパターンでジョブを実行したい場合、matrix構文を用いて簡易的にworkflowを記述することができる。
例えば、下記の図で示すように各コンポーネントでビルドを行った後に複数のテスト条件でテストを行い結果を通知する場合を考える。
matirix構文については、こちらに文法が記載されている。
今回作成したワークフローは、以下の要求を満たすように設計されている。(ただし、実際にビルドを行ったり環境のセットアップをしているわけではないので、実践で利用する場合は該当ステップに実ビルドコマンドなどを置き換えて使用してください。)
・コンポーネントAのビルドとコンポーネントBのビルドを行う。
・上記ビルドが終了後に、コンポーネントAのテスト、コンポーネントBのテスト、インテグレーションテストをそれぞれ環境oldと環境latestで行う。
・上記テストはコンポーネントA、コンポーネントBのビルドが失敗した場合は行われない。
・テストが行われた場合、結果のOK,NGに関わらず毎回GithubにUploadされる。
・テスト結果の成果物管理ツール(例えばJFrog Artifactoryなど)へのUploadは、テスト結果がすべてOKの場合のみ行われる。
・テストが行われた場合、結果のOK,NGに関わらず毎回開発者に結果が通知される。(今回はログに表示しているだけだが、実践ではslackに通知するなどのActionを用いるとよい。)
今回作成したWorkflowは以下の通りである。
.github/workflows/matrix.yml
---
name: matrix-sample
on:
push:
workflow_dispatch:
jobs:
matrix-job:
strategy:
matrix:
common-settings: [old,latest]
task: [test-build-job-A,test-build-job-B,integ-test]
include:
- task: test-build-job-A
config: settings-A
- task: test-build-job-B
config: settings-B
- task: integ-test
config: settings-integ
runs-on: ubuntu-latest
needs: [build-job-A,build-job-B]
steps:
- name: common settings
run: |
echo "done common settings ${{ matrix.common-settings }}"
- name: individual settings
run: |
echo "done config ${{ matrix.config }}"
- name: test
run: |
echo "done test ${{ matrix.task }}"
mkdir -p test_results/${{ matrix.common-settings }}_${{ matrix.task }}
echo 'OK' > test_results/${{ matrix.common-settings }}_${{ matrix.task }}_result.txt
- name: upload artifacts (to GitHub)
if: ${{ always() }}
uses: actions/upload-artifact@v2
with:
name: ${{ matrix.common-settings }}_${{ matrix.task }}
path: test_results/${{ matrix.common-settings }}_${{ matrix.task }}_result.txt
build-job-A:
runs-on: ubuntu-latest
steps:
- name: setup
run: |
echo "setup done"
- name: build
run: |
echo "build done"
- name: deploy
run: |
echo "deploy done"
build-job-B:
runs-on: ubuntu-latest
steps:
- name: setup
run: |
echo "setup done"
- name: build
run: |
echo "build done"
- name: deploy
run: |
echo "deploy done"
upload:
runs-on: ubuntu-latest
needs: matrix-job
steps:
- name: upload
run: |
echo "upload to artifactory"
notify:
runs-on: ubuntu-latest
if: ${{ always() }}
needs: matrix-job
steps:
- name: download artifact
uses: actions/download-artifact@v2
with:
path: download-artifact
- name: notify results
run: |
artifact_result=(`find . -name "*result.txt"`)
for v in "${artifact_result[@]}"
do
test=`echo ${v##*/}`
result=$(
head -n 1 "$v"
)
echo "Tests:${test%_*}\Results:"$result""
done
実行結果は以下の通りとなる。
実行結果
テスト成功時のworkflow
テスト成功時の結果通知
テスト失敗時のworkflow
テスト失敗時の結果通知
matrix構文を利用することで、複数の条件でjobを回したいときにworkflowを簡易的に記載することができるので、ぜひ活用してみてください。
Github APIを使用した情報の取得
Githubを利用したソフトウェア開発の中で、PRの数やcommitしたdevelopperの人数、コードの行数などの情報から、CI/CD指標を集計したい時がある。
GithubのUIからでもある程度の情報を取得することは可能だが、複数のリポジトリを調査したい場合、常に更新されていく情報を手動で集計するのは工数がかかる。
そこで、GithubActionsを利用した、自動集計のworkflowを作成した。
ファイル構成は以下の通りである。
|.
|--.github
| |--workflows
| | |--get-status.yml
|--config.json
|--README.md
|--tools
| |--get-pr-created-date.sh
まず、get-status.ymlファイルについて説明する。
今回のworkflowは、前章で説明したmatrix構文を用いる。
リポジトリごとにstepを分けるのは非常に冗長な表現になってしまうのと、可読性や保守性が損なわれてしまう。そのため、config.jsonに記載したリポジトリを取得し、各リポジトリごとにJOBをmatrix構文にしたがって呼び出す構成にした。新たに情報を取得したいリポジトリがある場合は、config.jsonファイルのみ修正すればよい。
get-status.yml
---
name: get-status
on:
push:
workflow_dispatch:
env:
date_cal: 500
jobs:
set-config:
runs-on: ubuntu-latest
outputs:
confJson: ${{ steps.set-config.outputs.confJson }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set configuration
id: set-config
run: |
cat config.json | tr -d '\n' | jq -c
list=$(cat config.json | tr -d '\n' | jq -c)
echo "confJson=${list}" >> $GITHUB_OUTPUT
get-status:
needs: set-config
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
repo: ${{fromJson(needs.set-config.outputs.confJson).repository}}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Get pr-created-date
run: |
echo ${{ matrix.repo }}
chmod +x ./tools/get-pr-created-date.sh
./tools/get-pr-created-date.sh ${{ env.date_cal }} ${{ matrix.repo }} ${{ secrets.GIT_PAT }}
- name: Checkout target repository
uses: actions/checkout@v3
with:
repository: ${{ matrix.repo }}
fetch-depth: 0
token: ${{ secrets.GIT_PAT }}
path: target
- name: Check developper
run: |
cd ${{ github.workspace }}/target
echo "start showing developper"
git log | git shortlog -nse
echo "finish showing developper"
cd ${{ github.workspace }}
- name: Setup-cloc
run: |
sudo apt-get update
sudo apt-get install cloc
cloc --version
- name: Check-lines-of-code
run: |
cd ${{ github.workspace }}/target
cloc . --vcs=git
config.jsonファイルは以下の通りである。
config.json
{
"repository":[
"${OWNER1}/${REPO1}",
"${OWNER2}/${REPO2}"
]
}
過去のPR数の取得
Github APIを利用し、特定の日付以降に作成されたPRを取得する。
以下、シェルスクリプトである。
get-pr-created-date.sh
#!/bin/bash
calc_date=`date +%F --date "$1 day ago"`
echo $calc_date
pulls=$(curl \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token $3" \
https://api.github.com/repos/$2/pulls?state=all&pre_page=100)
echo $pulls | jq --arg date $calc_date '.[] | select(.created_at >= $date) | .created_at'
developperの取得
ターゲットリポジトリのcommitした人の取得は、以下コマンドで取得する。(github apiを利用しても可能)
git log | git shortlog -nse
コード行数の取得
clocをインストールし、gitでバージョン管理されているファイルに対して集計する。
sudo apt-get update
sudo apt-get install cloc
cd ${{ github.workspace }}/target
cloc . --vcs=git
ディスカッション
コメント一覧
まだ、コメントがありません