GitHub Actions入門
GitHub Actionsとは?
GitHub Actionsは、GitHubが提供する「スクリプトを動かしてあげるよ~」なサービスです。
具体的に言うと、リポジトリに以下のようなディレクトリを作って、その中に「こういうときにこれを実行してね」なYAMLファイルを設置しておくだけで、GitHubが「お!これを実行したらええんやな!」と認識してくれます。
📁.github
└📁workflows
└📄hoge.yml 👈これの中身が実行される
料金(2024年05月現在)
publicリポジトリだと無料で使い放題です。すごい。
privateリポジトリでも無料枠が2,000分/月もあります。
その前に:YAMLの書き方を予習する
先にYAMLの予習をしておくのがオススメです。
というのも、先にYAMLの書き方が分かっていないと「これはGitHub Actionsの機能なの?YAMLの機能なの?」と迷うからです。
学習としてオススメなのが、JSONでいろいろなデータを表現してみたあとに「これをYAMLで表現するならどう書けばいいか」をやってみることです👇
▲こんな感じで「このYAMLをJSONにするとどうなるか?」を想像する→JSONにしてみるを繰り返すだけでいい練習になります
基本的な書き方
まず以下のようなディレクトリとhoge.yml
というファイルを作ってください。
📁.github
└📁workflows
└📄hoge.yml
ちなみにファイル名は何でも大丈夫ですが、.github
やworkflows
といったディレクトリ名は1文字でも違っていると動作しません!お気をつけください!
hoge.yml
には、以下のように書きます。
name: GitHub Actions Demo
on: [push]
jobs:
echo_hello_world:
runs-on: ubuntu-latest
steps:
- run: echo "hello world!!"
内容は「pushされたらechoしてね」になっています。
(詳しい内容は後から説明します)
実際にリポジトリを作ってmainブランチにpushすると、GitHubが「これを実行したらいいんだな」と解釈してくれて、勝手に実行してくれます👇
▲GitHubが実行してくれるGitHub Actionsのログは、リポジトリのActions
というタブから確認できます。
何を実行するか
echo "hello world!!"
の部分は、コマンドなら基本何でも書けます。
ただしrun-on
の部分で指定したOSで使えるコマンド限定です。この場合、Ubuntuを指定しているので、UNIX系のコマンドなら基本使えます。
たとえば👇のようにls
コマンドを実行したりもできますし
jobs:
echo_hello_world:
runs-on: ubuntu-latest
steps:
- run: ls
👇のように、「特定のURLにリクエストを送る」とかもできます。
jobs:
echo_hello_world:
runs-on: ubuntu-latest
steps:
- run: curl http://exmaple.com
複数コマンドを実行する
stepsの中にrunを増やしていくと、複数のコマンドを実行できます👇
jobs:
echo_hello:
runs-on: ubuntu-latest
steps:
- run: echo "Nice to meet you!!"
- run: echo "My Name is Taro!!"
- run: echo "I love programming!!"
また、それぞれにname:
をつけることもできます👇
jobs:
echo_hello:
runs-on: ubuntu-latest
steps:
- name: "挨拶"
run: echo "Nice to meet you!!"
- name: "名前を言う"
run: echo "My Name is Taro!!"
- name: "趣味を話す"
run: echo "I love programming!!"
stepsの中に書く1つ1つの要素のことを「ステップ」と呼びます👇
基本的には👆のように「1つのステップ=1つのコマンドと名前」にすると分かりやすいです。
ちなみに、最初のコードは👇のようにも書けますが(これはYAMLの文法です)
jobs:
echo_hello_world:
runs-on: ubuntu-latest
steps:
- name: "自己紹介"
run: |
echo "Nice to meet you!!"
echo "My Name is Taro!!"
echo "I love programming!!"
このように👆1つのステップで複数のコマンドを実行してしまうと、失敗したときに原因を特定するのが面倒になるので、基本的に「1ステップ=1コマンド」にするのが良いかもです。
用語
ここからは用語ベースで書きます。
▲こういうイメージ
ワークフロー🟩
「こういうときにこれを実行してね」なYAMLファイルに書かれた処理をワークフローと呼びます。
「YAMLファイル=1つのワークフロー」という理解で良いと思います。
ジョブ🟦
複数のコマンドをまとめた単位のことをジョブといいます。
ジョブは複数定義することができます。
たとえば、👇のようにジョブを2つ書くこともできます。
jobs:
echo_hello:
runs-on: ubuntu-latest
steps:
- name: "挨拶"
run: echo "Nice to meet you!!"
- name: "名前を言う"
run: echo "My Name is Taro!!"
- name: "趣味を話す"
run: echo "I love programming!!"
echo_goodbye:
runs-on: ubuntu-latest
steps:
- name: "別れの挨拶をする"
run: echo "Good Bye!!"
ここで重要なのが、ジョブの中のステップは直列で実行されるが、それぞれのジョブは並列で実行されるという点です。
この場合、echo_hello
とecho_goodbye
はヨーインドン!で同時に並列で実行されます。
▲Actionsタブで見ても、ジョブが2つになっている
なので、たとえば「別れの挨拶をする」というステップは「趣味を話す」のステップの後に実行してほしいんだよな~という場合は、👇のように1つのジョブの中に書く必要があります。
jobs:
echo_hello:
runs-on: ubuntu-latest
steps:
- name: "挨拶"
run: echo "Nice to meet you!!"
- name: "名前を言う"
run: echo "My Name is Taro!!"
- name: "趣味を話す"
run: echo "I love programming!!"
- name: "別れの挨拶をする"
run: echo "Good Bye!!"
逆に、ステップAとステップBに依存関係がない限り、ステップAとステップBは別々のジョブとして定義したほうが良いです。その分だけ早く終わるからです。
また、ワークフローもジョブと同じでヨーインドン!で同時に並列に実行されます。
たとえば、👇のように複数のワークフローを作った場合、条件に合致するすべてのワークフローがヨーインドン!で同時に処理がスタートします。
📁.github
└📁workflows
├🗒1.yml
├🗒2.yml
└🗒3.yml
トリガー🟪
「どういうタイミングで実行するか」のことをトリガーと呼びます。
ymlファイルのon
の部分でトリガーを指定できます。
たとえば👇のように書くと「15分ごとに実行してね」になります。
on:
schedule:
- cron: '*/15 * * * *'
👇のように書くと「プルリクエストが作られたら実行してね」になります。
on:
pull_request:
👇のように書くと「手動で実行できるようにしてね」になります。
on:
workflow_dispatch:
▲workflow_dispatchを指定すると、Actionsタブから手動で実行できるようになる
👇のように書くと「developブランチにpushされたら実行してね」になります。
on:
push:
branches:
- develop
👇のように書くと「appsディレクトリ内のファイルに変更があって、かつ、developブランチにpushされたら実行してね」になります。
on:
push:
branches:
- develop
paths:
- 'apps/**'
ほかにも色々なタイミングを指定できます。
公式ページにどういうタイミングを設定できるのか全部書いています👇
Workflow syntax for GitHub Actions - GitHub Docs
アクション
「誰かか作った処理をそのままワークフローの一部として使っちゃおう」ができる機能をアクションと呼びます。
話は変わりますが、GitHub Actions上では、リポジトリのソースはデフォルトでは含まれていません。
たとえばAというリポジトリで、GitHub Actionsを動かしたとしても、その実行環境の中ではAというリポジトリのソースは存在しません。自分で用意する必要があります。
え?じゃあ毎回git clone
する必要があるの?面倒くさ~!と思うかもですが、そういう面倒なことをしなくても良いように、GitHub公式が「これを使えば特定のリポジトリのソースを持ってこれるよ~」なアクションを用意してくれています👇
さらに、GitHub Actionsでは、デフォルトでNode.jsが使えないので、Node.jsをインストールするためのアクションも用意されています👇
これらのアクションは、uses: アクション名
という形で使用できます。
実際に、この2つを使って「GitHub Actionsで自作のindex.jsというスクリプトを動かしたい!」という場合は、👇のような感じで書けます。
name: Run JavaScript in GitHub Actions
on:
push:
branches:
- main
jobs:
setup_and_run:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4 #👈リポジトリのソースを持ってくる
- name: Set up Node.js
uses: actions/setup-node@v3 #👈Node.jsを使えるようにする
with:
node-version: '20'
- name: Install dependencies
run: npm install
- name: Run script
run: node index.js
CI/CD
GitHub Actionsのようなサービスで、「このテストを実行してね」な処理を書くことをCIと呼びます。
「ここにデプロイしてね」な処理を書くことをCDを呼びます。
両方書くことをCI/CDと呼びます。
用語なんてどうでもいいのですが、開発の現場では当たり前のように「CIが~」「CI/CDが~」みたいに使われるので、覚えておいたほうが良いです。
ちなみに、日本語にすると👇のような意味になるらしいです。
- CI:Continuous Integration(継続的インテグレーション)
- CD:Continuous Delivery & Deployment(継続的デリバリー&デプロイ)
実務でどうやって使うか?
ここまでは簡単な例だったので、実際に実務でどうやって使えばいいのか?について書きます。
弊社でOSSとして公開している「LooksToMe」というアプリがあるのですが、こちらのアプリを例に紹介します!
▲画像をアップして、こういう文字を合成できるアプリです
たとえば、CIは👇のコードで実現しています。
具体的な内容を説明すると、👇の4つのジョブを含むワークフローが
- Build(Next.jsなどのアプリのビルドが成功するか?)
- Test(書いたテストが全部通るか?)
- Lint(ESLintのチェックが全部通るか?)
- Type(tsxの型チェックが全部通るか)
👇のときにトリガーされます。
- プルリクがオープンしたとき
- プルリクが再オープンしたとき
- プルリクにpushされたとき
そして「これらのすべてのジョブが成功✅で終わらなかった場合、マージさせないぞ」という設定にしています👇
▲リポジトリのSettings→Branchesから設定できる
ちなみにOSSとして公開しているので、だれでもGitHub Actionsの実行ログを確認できます!👇
弊社では、全プロダクトでこのようなCI/CDを構築しています。
また、👇のような便利なOSSを公開していたりもします。
ブランチ名をもとにPRに自動でラベルを貼るGitHub Actions
良さげな会社だな~と思った方は、ぜひカジュアル面談にご応募ください~!🙏
\ PR /
弊社では「中級エンジニアになろう!」なブートキャンプのメンバーを募集しています!
「3人1組でたくさんの課題に挑戦しよう!」なやつで、名前を「プラハチャレンジ」といいます。
期間限定募集です!
- 応募締め切り:5月17日(金)の18時まで
- 費用:9,800円/月(税抜き)
データベース設計やドメイン駆動設計と言った課題など色々あります。
GitHub Actionsの課題もあります!
興味のある方はぜひ~!!👇
Discussion
分かりやすい記事をありがとうございます。
PRのブートキャンプを見て昨日応募したのですが、事前テストの締め切りは今日までで合っていますか。
Webサイトでは今日までとあったのですが、Notionのカリキュラムだと昨日までと記載されていたので気になっています。
ありがとうございます!
今日までで合っています!
紛らわしくて申し訳ございません🙇♀
この部分、ジョブは並列で実行されるが、ステップは直列で実行されるという書き間違いですかね?
複数のジョブ記述に対して正しい説明ではなさそう?と思いました。
ご指摘ありがとうございます!
おっしゃる通りでしたので、修正しました!