📝

GithubActionsでrunにifを書かない方法で、ステップごとに実行判断をするロジックの書き方・使い方(実例あり)

2023/08/29に公開

https://qiita.com/items/90cc5288bb65988a578a


お詫び

Qiitaの元記事にて、区切り線を「---」で書いている場所があり、これがZennの記法に干渉して一部うまく表示できない記事がある事を認識しています。
全ての記事を精査しきれていないため、お手数ですがお見かけの際は教えていただけると大変喜びます。


公式リファレンス

Github Docs

https://docs.github.com/ja/actions/learn-github-actions/contexts

本稿ではstepsコンテキストを使っています

実行結果によって処理をする・しないを分岐する

先に結論を言うと、runでif文を書けるので、shellを書くのと同じ感覚で書けばやりたい事は実現できます。
ロギングがしたいならechoでログを出すか、ログファイルも更新してpushすればGithubActionsを探しに行かなくてよくなります。

が、ここではGithubActionsの流儀に則って制御を考えます。
また、runで実行すると、途中でエラーになった時にどこで失敗したのか特定するのが難しくなるので、運用を考えるならなるべく切り分けたいからです。

やり方は、if: 条件をいれるだけです。
問題は、条件に何を書くかです。

条件分岐で使えるもの

色々なものが使えますが、ここでやりたいのは「前回実行したステップの結果を受け取りたい」というものです。
たとえば、前回実行した結果が全て完了したとか、特定の処理をしたかどうか。
解決アプローチとして、3つのパターンがあります。

  1. そもそもstepをまとめてしまう
  2. 前stepの結果を判定するロジックをrunで書く
  3. 【今回採用】stepを実行する前にif条件を入れる

大事な事なのでもう一度繰り返します。
うまく行かない場合は、今回採用する方法にこだわる必要はありません。
実務で採用する場合にまで、後でできる事を今こだわるとハマって進捗率を下げてしまう、なんて事も考えられます。
状況に合わせて活用してください。

ソース例と解説

今回の制御で見る公式ドキュメントの位置

https://docs.github.com/ja/actions/learn-github-actions/contexts#steps-context

Thanks:

https://qiita.com/ljourm/items/556f5ccc8425891865de

if: steps.(ステップのid).outcome == "success"が最もわかりやすいです。
以下のような使い方ができます。

- name: 確実に成功する処理
  id: test1
  continue-on-error: true  # 処理が失敗しても継続させる
  run: echo "成功"

- name: 実行される事を確認
  if: steps.test1.outcome == "success"
  run: echo "処理される"
- name: 確実に失敗する処理
  id: test2
  continue-on-error: true  # 処理が失敗しても継続させる
  run: exit 1

- name: 実行される事を確認
  if: steps.test2.outcome == "success"
  run: echo "スキップ"
- name: 確実に失敗する処理
  id: test2
  continue-on-error: true  # 処理が失敗しても継続させる
  run: exit 1

- name: 実行される事を確認
  if: steps.test2.outcome == "success"
  run: echo "スキップ"

適当なリポジトリを作って、.github/workflows以下に置いて検証してみてください。

実践例

この方法は、Ubuntu20.04にデフォルトで入っているpythonのバージョンが古くて動かないスクリプトがある場合、処理をしないための例です。

参考

https://docs.python.org/ja/3/library/pathlib.html#pathlib.PurePath.with_stem

Ubuntu22.04 LTSではどうなるか気になるところです。

https://www.youtube.com/watch?v=iL-ZvDEQH0M

https://wiki.ubuntu.com/MitsuyaShibata/Slides

ソースコード

runs-on: ubuntu-latest
steps:
  # 以下、ステップ
  - name: PosixPath.with_stemが使えないので、スクリプトを実行できるか判断する
    id: check_python
    continue-on-error: true
    run: |
      # python3のマイナーバージョンが9未満か判定
      if [ "$(python3 --version | cut -d"." -f2)" -lt "${minor}" ]
      then
        exit 1
      fi

  - name: スクリプトを実行
    if: steps.check_python.outcome == 'success'
    run: python3 (実行スクリプト)

check_pythonでexit 1を実行しなければスクリプトを実行します。

応用例

この方法は、Ubuntu20.04にデフォルトで入っているpythonのバージョンが古くて動かないスクリプトを動かすための例です。
もっといい方法があるので、以下はあくまで実践例です。

今回のGAとは関係ないですが、WSLに入れる時に参考になりました。

https://codechacha.com/ja/ubuntu-install-python39/

https://stackoverflow.com/questions/65644782/how-to-install-pip-for-python-

ソースコード

# 実行環境
runs-on: ubuntu-latest
steps:
  # 以下、ステップ
  - name: 判定ロジックは同じ。上記では`exit 1`で終わらせたが、こちらはインストールする
    id: check_python
    env:
      minor: 9
    run: |
      pyc=$(python3)

      # python3のマイナーバージョンが9未満の時だけ実施する
      if [ "$(python3 --version | cut -d"." -f2)" -lt "${minor}" ]
      then
        sudo apt update && sudo apt install software-properties-common
        sudo add-apt-repository ppa:deadsnakes/ppa
        sudo apt install python3.${minor}
        pyc=python3.${minor}
        sudo apt update && sudo apt install python3.${minor}-distutils
      fi
      
      echo "::set-output name=pyc::${pyc}"

  - name: pythonスクリプト実行
    env:
      # id: check_pythonの出力からpycを取得してenvに入れる
      pyc: ${{ steps.check_python.outputs.pyc }}
    run: |
      ${pyc} -m pip install --upgrade pip
      ${pyc} -m pip install pathlib
      ${pyc} (実行スクリプト)

pycにはpython3python3.9か、どちらかが入っています。
重要なのは、実行するステップではpycに何が入っているか気にしなくても良い事です。
より厳密なチェックをするなら、which "${pyc}"のパスが有効である事を検証するのも良いかもしれません。

良い方法

環境構築系は自分で頑張るより、usesを探した方が楽です。
pythonのバージョンを指定する方法はあります。

steps:
 - uses: actions/setup-python@v3
   with:
     python-version: '3.9'

  - name: pythonスクリプト実行
    run: |
      python -m pip install --upgrade pip
      python -m pip install pathlib
      python (実行スクリプト)

あれだけ長いコードが、こんなに圧縮できるのでusesは非常に優秀です。
usesで使えるものは以下の通り

今回使ったもの

https://github.com/actions/setup-python

使えるもの

https://github.com/orgs/actions/repositories

自分でusesを作れます

usesを見ると、Githubユーザー/リポジトリの関係であることに気付きます。
これは具体例を挙げるのが難しい(私が具体例を知らないため)ですが、オリジナルの環境構築ができるのは便利です。
メンテナンスを考えると決して楽な選択ではありませんが、どうしてもという場合には使えそうです。

https://qiita.com/HeRo/items/e2d5e3bc3dbe810f0482

使用例

https://nomuraya.tk/2022/03/githubactions.html

私がやりたかったこと

pushされるたびにCHANGELOG.mdを自動で生成してPRを出すスクリプトを書きたかったんですが、

  • github-changelogs(node)
  • github-changelog-generator(ruby)

を使って自動生成する仕組みを作ろうとしていました。
わざわざ自前で環境構築をやってコマンド打ち込んで…とやると大変なので、CIでなんとかならないかと思っていたところでした。
いきなり難しい事をやると手がつかないので、手始めに上記のように簡単なCIを色々作ってみてGithubActionsのナレッジも蓄積してきたので、そろそろ挑戦しようと思っていました。
実務ではなく趣味でやっているCIだと、CIの勉強だけだと運用経験が積めず、なかなか学びが進まないので非常に時間がかかりましたが、ようやくここまで来れました。

本稿の内容を踏まえて、プログラマーを目指す方へ

ぶっちゃけ本題です。
冗長になりすぎたので、別記事にします。

https://nomuraya.tk/2022/03/consultant_learn.html

GitHubで編集を提案

Discussion