Beta参加の秘密保持条項に反しているのでは?という指摘をいただいたので、一部修正を行いました
1人AdventのDay-7です。なるほど、1週間・・・
私の環境でも、GitHub Actionsを触れるようになりました!!
自分の手で実際に触ってみて、動かしてみると「おお!これはすごい!!」という感想です。。。!
実際に動いているものを見ないと「何があってどういうものなのか」のイメージが付きにくかったのですが、手元で動かしてみると「なるほど、、、そういう!」とワクワクしてきます。
今の自分なりの理解を、改めて、ドキュメント等を整理する形でまとめてみたいと思います。
GitHub Actions、ざっくりいうと
- GitHub上での様々なイベントで発火させる「Workflow」と、Workflowから具体的な起動される「Action」からなる
- Actionは、利用するDockerイメージを指定して、そのコンテナの内部で実行される
- 1つのWorkflowに、複数のActionを連鎖・並行させて紐付けることができる
- Workflowの編集のためのvisual editorが用意されていたり各Actionごとの実行結果(ログ)の閲覧が可能
個人的な感想としては、
- 今まで1つの汎用CIにまとめていた処理を、細分化・専門化して組み合わせることが用意になりそう
- 自前のDockerfileをゴニョゴニョして使い放題なので、ローカルでやっていた処理を簡単にクラウドに移せそう
- 通常のGitHub(git操作やIssue更新など)だけでなく、incoming hook系のAPIも用意されているので、chatops等の実装とも親和性が抜群に高そう
といったところです。
現在、業務でCIの活用見直しやデプロイフローの最適化を進めている最中です。それと絡めて、「Travis CIの処理をいい感じにする」というネタで触ってみました!
やろうとしていること
- 今の状態
- Travis CIを利用しているプロジェクトにおいて
- script/deploy等をベタで書いており
- 例えば「tagをpushした」際にも丸々とscriptフェーズが実行される
- やってみたいこと
- master以外のブランチへのpush/prは、scriptまで。deployはしない
- masterの修正(merge commit)は、scriptとdeployを行う
- コードに差分がないときにはdeplyフェーズのみを実行し、scriptを実行させない
- リリースの作成やタグ付けなど!
これを、「.travis.ymlの修正を行わずにできるかな」という風に遊んでみたいと思います。
サンプルプロジェクトのセットアップ
実際に遊んで見るに当たり、サンプルとなるプロジェクトを用意しました。CakePHPのスケルトンプロジェクトを設置し、ごくごく簡単なtravis.ymlを一緒に置きます。
$ tree -a -L 3 -I .git . ├── .travis.yml ├── README.md └── o0h_home ├── .gitignore └── app ├── .editorconfig ├── .gitattributes ├── .github ├── .gitignore ├── .htaccess ├── .travis.yml ├── README.md ├── bin ├── composer.json ├── composer.lock ├── config ├── index.php ├── logs ├── phpcs.xml ├── phpunit.xml.dist ├── plugins ├── src ├── tests ├── tmp ├── vendor └── webroot
.travis.yml
language: php php: - 7.2 cache: composer: true directories: - o0h_home/app/vendor install: - cd o0h_home/app && composer install && cd $TRAVIS_BUILD_DIR before_script: - echo "I'm in before_script!" script: - cd o0h_home/app && vendor/bin/phpcs deploy: - provider: script script: echo "I'm in deploy @master!" on: branch: master - provider: script script: echo "I'm in deploy @tag!" on: tags: true
まずはTravis CIのAPIを、最低限理解する
APIがどんな感じになっていれば行けそうかな?を整理する
Actionsは「どんな条件で」「どんな風に」処理を呼び出すか?という機能に見えます。
今回、私が求めている世界は、「.travis.ymlに記述されている内容を部分的に実行する」という術が必要なのではないでしょうか。つまり、「こういう呼び出し方をしたら、scriptをスキップできるよ」という方法があれば勝利に1歩近づきます。
そのためには、
- A: 実行対象となるフェーズを任意に組み合わせて、ビルドを実行できる
- B: 実行内容をAPIキックのタイミングで任意に改変して、ビルドを実行できる
- C: 予め実行内容(のセット)を定義しておき、ビルドを実行できる
このいずれかの手立てがあれば良さそうです。*1
ということで、「Travis CI側のApiがとうなってるの?」を掴まない限りは、何も始まりません。
実際にAPIを見てみる
Triggering builds with API V3 - Travis CI
こちらを覗くと、
- ビルド作成のリクエスト時に、.travis.ymlのコンテンツと同じような処理内容を渡すことができる
- もともとの.travis.ymlの内容と、リクエストに含めた処理内容を、「どう混ぜるか」を指定することができる(merge_mode)
- merge_modeは以下の3種類
- replace replaces the full, original build configuration with the configuration in the API request body
- merge (default) replaces sections in the original configuration with the configuration in the API request body
- deep_merge merges the configuration in the API request body into the build configuration
これを見ると、「scriptだけ内容を変える」ができそうに思います💡
GitHub ActionsからTravis CIを利用できそう?
次にやるのは、「GitHub ActionsからTravis CIのAPIを叩く」です。
そして、そのリクエスト内容に「script処理をスキップする」といった内容を混ぜたり混ぜなかったりしようと思います。
そう思って探していると、「ActionsからTravis」になんだかお誂え向きのものがありました!
The Travis CI action wraps the Travis CI API so that new builds can be created based on Push and Pull Request GitHub events.
と書いてあります。これを扱えれば、「ActionsからTravis CIにリクエストを飛ばす」は出来そうな感じがしてきました。
では、今度はtravis-ci/actionsを理解するために、そもそものところである「Actionsから○○を実行する」に関する概念をつかみにいきたいと思います。
GitHub Actionsの正体は、○○を実行させるものだった
travis-ci/actionsを見ると、Dockerfileやentrypointといった単語を発見することができます。ということは、なるほど、なにか「Dockerを使ったもの」であるなと推察できます。
github actions docker
でググると、次の記事に行き当たります。
GitHub Actions are code run in Docker containers.
なるほど、「Dockerコンテナを起動してその中でなんでもやっていいよ!」でしょうか。
そのDockerイメージ/コンテナはどうやって作成されるんだ?
GitHub Actions execute in Docker containers. An action can use an existing publicly available Docker image, or you can create your own Docker image by including a Dockerfile with your code.
既存のものを使うこともできるし、自作したDockerfileを利用することもできるよ〜と。であれば、恐らく、Actionsの設定のやり方で「どのイメージを使いますか」という設定をする部分があるのでしょう。
ここまできたら、次は「Actionsはどうやって使うんですか」のイメージを掴みに行くのが良さそうです。
Actionsに触ってみる
Actionsへは、GitHubのレポジトリ画面からアクセスできます。
ここに、Actionsの作成画面があります。
「Workflow」なる概念が飛び出してきました・・・!
Workflowってなんだ・・?
どうやら大本になる概念な予感がするので、Actionsの最も大元となるdocに書いてあるだろうと期待します。
サイドメニューを見るに、GitHub Actions = Workflow + Action
というイメージですかね?
説明を見てみます。
Workflows are a composite of many different GitHub Actions, or tasks you want to accomplish, and are triggered by webhook events.
Workflowsは、「発動条件」と「発動時の設定」って感じすかね。それで「何をやりますか」というSVOのOに当たる部分が、Actionsである〜という風に理解しました。
それでは、さっきの「どうやったらtravis-ci/actionsを呼び出せるの」は、workflowを作れば何か出てきそうですね。
Workflowを作ってみる!
「Create a new workflow」ボタンを押したら、新規ファイル作成のページに飛びます(ページURLとページタイトルが、new fileのそれ)。
そして、特徴的なGUIが現れます。
デフォルトでは、コレは同時に octo-test/.github/main.workflow
というファイルの新規作成でもあるということが、見て取れます。
隣にあるタブ、 Edit new file
ではテキストベースでの編集に入れます。
あ!なんか、このDSLは見覚えがあるぞ。travis-ci/actiosnレポのREADMEに、こんな感じのサンプルがありました。
いろいろと、点と点がつながってきました・・・!
Workflowの定義
黒いボックス、 workflowの方にある Edit
をクリックすると、次のようなメニューが現れます。
キャプチャ上の Issues
になっている部分で、発火条件としたいイベントを選択するという寸法!
どこ見ればいいかな?
定義の一覧があるはずなので、公式docを当たりました。
Workflow configuration options | GitHub Developer Guide
resolve
が何者かまだわかっていませんが、とりあえず今の我々に必要なのは on
に関する知識でしょう。リンクが貼られているので、GitHub eventについて知識を求めに参ります。
今回のスコープでいうと「tagが作成されたとき」です。Event nameとしては、 create
でしょうか。 これに、副条件として「タグ(が作成された)」を加えたいのですが。
具体的な処理を行う前に、イベントをフィルタリングするには?
簡単な比較条件を突っ込んで(branch == 'master'
みたいな)弾ければいいのに・・・と思うのですが、どうやらそういう記述はできなさそう。
我々が使える武器は「workflow」と「action」なので、じゃあ「何かプログラマブルに処理を注入するには、actionを重ねるのかな?」と思いました。GUI的にも、actionを多層化してチェインすることはできそうなので。
どうでしょう、もし「簡単なシェルスクリプトを実行する」ためだけのDockerイメージがあれば、これは実現できそうな気がします。
GitHub公式のActionを見てみます。
bin って、めっちゃそれっぽいな・・・w 開いてみます。
Usage information for individual commands can be found in their respective directories.
はい。そして、filter
というディレクトリがあるので、これにすがってみます。
For example, here is a workflow that publishes a package to npm when the master branch receives a push:
どんぴしゃっぽい!
サンプルを見てみます。
workflow "Build, Test, and Publish" { on = "push" resolves = ["Publish"] } action "Build" { uses = "actions/npm@master" args = "install" } action "Test" { needs = "Build" uses = "actions/npm@master" args = "test" } # Filter for master branch action "Master" { needs = "Test" uses = "actions/bin/filter@master" args = "branch master" } action "Publish" { needs = "Master" uses = "actions/npm@master" args = "publish --access public" secrets = ["NPM_AUTH_TOKEN"] }
「masterブランチでフィルタ」をしているのは、 Master
のactionですね。
ついでにというか、さっき疑問だった「どうやって外部のイメージをactionに定義するのか」もこれで解消しました。 use
に指定するんですね。そして、依存関係にあるactionは前ステップにあたるあactionをneeds
として宣言する、と。
我々が実行したい createイベントでtagの場合のみ
は、filterディレクトリのREADMEに言及があるのでこれをそのまま使います。
.workflowはこのようになります。
workflow "on tag push" { on = "create" resolves = ["filter-only-tag-created"] } action "filter-only-tag-created" { uses = "actions/bin/filter@master" args = "tag" }
on tag push
というworkflowをcreate
イベントに反応して起動させfilter-only-tag-created
actionを呼ばせる
filter-only-tag-created
はactions/bin/filter@master"
のイメージを利用しtags
というパラメータ込みで起動する
actionにおけるuseの指定ですが、
- 自レポジトリの場合は、
./
から初めてPJルートからの相対パス指定 - 他レポジトリの場合は、
user名/レポジトリ名/ディレクトリへのパス@ブランチ
と指定
という形式になるようです。
filterを設定できたように思うので、Travis CIをキックする処理を入れます。
ここで、request bodyを変えてあげる必要があります。
が、travis-ci/actionsレポでentrypointに指定されているjsの内容を見てみると、どうやらコンテンツが固定されているようです。
自前のDockerfileを用意しよう・・・
どうやら外から注入というのが厳しいような気がしたので、自前で用意してみます。幸い、travis-ci/actionを見ても、複雑な処理は入っていません。なので、丸々っと必要な処理をコピペしてしまいます。
ひとまず、以下のようにしました。
自レポジトリ内のDockerイメージを利用する方法が、公式ドキュメントに書いてあります。PJルートから、コンテキストとなる = Dockerfileのあるディレクトリへのパスを指定してあげれば良さそうですね。
最終的には、このようになりました。
workflow "on tag push" { on = "create" resolves = ["deploy"] } action "filter-only-tag-created" { uses = "actions/bin/filter@master" args = "tag" } action "deploy" { uses = "./.github-aciton/travis-ci" needs = ["filter-only-tag-created"] secrets = ["TRAVIS_TOKEN"] }
Travis CIの利用には、TRAVIS_TOKEN
が必要です。
https://travis-ci.com/account/preferences で取得し、actionに設定してください。
実行してみる
エディタ右上の、Start commit
からコミットします。
その後にタグを打つと、定義したとおりのworkflowが動きます。
その後は、実行結果をグラフィカルに確認が可能です。 GitHub上で「Actionの履歴・実行結果が見れる様子」は、この動画の1:10辺りで垣間見ることができます。
左側に実行されたworkflowの履歴が表示され、その中にあるactionごとの実行結果ステータスが色により表されます。更に、actionのブロック内にあるlog
をクリックすると、詳細が確認できるわけです。
まとめ
本来であれば、.travis.ymlもちゃんといじりつつ行うべきだと思っています。
ただ、「新機能のポテンシャル」としては、「ここまで簡単に色々とできる!!」という手応えは間違いなく感じたので、個人的には大満足です。
Dockerでいろいろできる!はやばい。
どんどん活用していくしかねぇな・・・!という温度感です。
参考記事等
- Features • GitHub Actions · GitHub
- 全てはここから!
- GitHub Actions: みなさんが開発し、GitHubで実行 | The GitHub Blog
- イベントでのお披露目時の記事
- Customizing your project with GitHub Actions - User Documentation
- ドキュメント目次
- Creating a workflow with GitHub Actions - User Documentation
- Actionsの作り方step-by-step
- Workflow configuration options | GitHub Developer Guide
- 設定値リファレンス
- GitHub Actions · GitHub
- pre-buidlイメージ
- GitHub Actions用のDockerfileの作り方など参考になる
*1:もちろん、config等を設けたり環境変数デフラグをもたせて、travis.ymlやそこから呼び出すスクリプトの中でコントロールをする・・という手段はそうていされますが、今回の目的の1つに「あまりtravis.ymlを書き換えたくないな」があるので、こちらは却下