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


# 公式リファレンス
## Github Docs

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

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

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

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

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

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

1. そもそもstepをまとめてしまう
1. 前stepの結果を判定するロジックをrunで書く
1. 【今回採用】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"`が最もわかりやすいです。
以下のような使い方ができます。

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

- name: 実行される事を確認
  if: steps.test1.outcome == "success"
  run: echo "処理される"
```

``` 失敗.yml
- name: 確実に失敗する処理
  id: test2
  continue-on-error: true  # 処理が失敗しても継続させる
  run: exit 1

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

``` 失敗した時でも処理したい.yml
- 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

#### ソースコード
``` 実践例.yml
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-

#### ソースコード
``` 応用例.yml
# 実行環境
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`には`python3`か`python3.9`か、どちらかが入っています。
重要なのは、実行するステップでは`pyc`に何が入っているか気にしなくても良い事です。
より厳密なチェックをするなら、`which "${pyc}"`のパスが有効である事を検証するのも良いかもしれません。

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

``` 良い方法.yml
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