🍴

GithubActionsで、shellを外部ファイルに切り出す

2024/05/24に公開
4

概要

shellスクリプトが長くなってくると、外部ファイルに切り出したくなる。
外部ファイルに定義して呼び出すときに躓いたので、方法をメモする。

やり方

GithubActionsでは、外部ファイルも実行することが出来るので、一般的なshellのように切り出せばOK

actions.yml
- name: create-txt
  run |
    chmod +x .github/workflows/create-text.sh
    .github/workflows/create-text.sh ${{ github.repository}}
    cat repo-name.txt
create-text.sh
#!/bin/bash

echo "repository name is $1" > repo-name.txt

ポイント

  • shellファイルはリポジトリルート以下であればどこでも参照できるので、どこに配置しても良い
  • shellファイルの中では、GithubActionsのコマンドは使えないので、必要があれば外部から取得する必要がある(例えば引数で渡すなど)
  • shファイルに実行権限が必要なので、与えてから実行する
    • shファイル自体に実行権限があればchmodは不要
    • ローカルで git update-index --chmod=+x .github/workflows/create-text.sh を実行してcommit→pushすれば、実行権限を付与できる(ドキュメント)

Discussion

rakiraki

整理するならドキュメントを読むところから。。。
https://docs.github.com/en/actions/learn-github-actions/essential-features-of-github-actions#adding-scripts-to-your-workflow

shellファイルの中では、GithubActionsのコマンドは使えないので、必要があれば外部から引数で渡す必要がある

コマンドってゆうか、値の引数渡しが必要なのはシェルスクリプトの中でそう書くからで、env 渡しや外部ファイル参照でも渡せます。

run: のデフォルトは linux ランナーなら通常 bash で見つからない場合は sh が使われるので、sh 呼び出しは必須ではありません(むしろしないほうがいい)。
実行権限について言及するほうが整理されていると思います。

ゆつぼゆつぼ

コメントありがとうございます!
メモ程度に書いてしまっていたので、スクラップを使う方が適切だったかもしれませんね。

shellファイルの中では、GithubActionsのコマンドは使えないので、必要があれば外部から引数で渡す必要がある

これは、最初はrun:の中に書いていたスクリプトを外部ファイルにしたときに、 ${{ github.repository }} をそのままにしてしまったことで、 Bad substitution エラーが出たので、直書きは出来ない(それはそう)との気付きとして書いていました。
ので、引数以外でも渡せるのはそうですね。

run: のデフォルトは linux ランナーなら通常 bash で見つからない場合は sh が使われるので、sh 呼び出しは必須ではありません(むしろしないほうがいい)。

ありがとうございます!
.shを実行するにはshコマンドが必要だと思っていました。
付けない場合デフォルトが使われるので、付けない方がいいのですね。

実行権限について言及するほうが整理されていると思います。

「shファイルに実行権限がないので、chmodで権限を変更してから実行すべき」ということなのでしょうか?
Windowsが絡む場合には実行権限の考慮が必要だと思っていました。
shコマンドは実行権限まで付けてくれるということなんでしょうか?(そんなことはなさそうだが)

rakiraki

付けない場合デフォルトが使われるので、付けない方がいいのですね。

run 自体がデフォルトで bash (フォールバックしてsh)で動くので、新たにシェルを噛ませる必要がありません。

  run |
    sh .github/workflows/create-text.sh ${{ github.repository}}

だと、デフォルトでbashが動いている中で別プロセス sh (実態は$PATHが処理された先のシェルで、何になるかはランナー次第)が動いて、その後シェルスクリプト中のシェバンが処理されて /bin/bash で動くことになります。ぶっちゃけ無駄です。

「shファイルに実行権限がないので、chmodで権限を変更してから実行すべき」ということなのでしょうか?

リンク貼った先に言及あるので。。。
git update-index されていれば必要ないですし、されていないなら実行権がつけるか、最初の例のように sh をつけて実行するです。
ここは、整理する、という記事ならどういう理屈で動いてるのか、なぜこう書いているのか、くらいは把握して、記事内で言及して欲しい、くらいの意味でコメントしました。

Windowsが絡む場合には実行権限の考慮が必要だと思っていました。

Windows ユーザ(クライアント)が権限を考慮しない、的な話なら前述のとおりファイルに実行権をつけられます。
Windows ランナー(runs-on:windows)でスクリプトファイルに権限がなくても実行したい、という話なら、同じく権限をつけるのが筋ですし、別の sh を呼び出す理由にはなりません。
(あとWindowsランナーでbashを走らせるならもっと別の考慮がいるはずです)
単に実行権のないスクリプトファイルを実行させよう、なら

  run |
    chmod +x .github/workflows/create-text.sh
    .github/workflows/create-text.sh ${{ github.repository}}

のようにするのがドキュメント的にも適切です。

shコマンドは実行権限まで付けてくれるということなんでしょうか?(そんなことはなさそうだが)

sh コマンドは渡された引数のファイルがシェルスクリプトであるならそれを実行してくれます(ファイルに権限をつけるわけではない)。

chmod -x .github/workflows/create-text.sh

sh .github/workflows/create-text.sh
sh < .github/workflows/create-text.sh
cat .github/workflows/create-text.sh | sh

chmod +x .github/workflows/create-text.sh
.github/workflows/create-text.sh

って書けばわかりますか?
厳密には異なりますが、結果は全部同じです。

ゆつぼゆつぼ

デフォルトでbashが動いている中で別プロセス sh (実態は$PATHが処理された先のシェルで、何になるかはランナー次第)が動いて、その後シェルスクリプト中のシェバンが処理されて /bin/bash で動くことになります。ぶっちゃけ無駄です。

ありがとうございます。理解できました!

、整理する、という記事ならどういう理屈で動いてるのか、なぜこう書いているのか、くらいは把握して、記事内で言及して欲しい

自分の意図をうまく反映出来ていなかったようです。
新しく理解できたことを追記し、記事を修正しようと思います。

リンク貼った先に言及あるので。。。

ドキュメントは読ませていただきました!当方知識不足のため、指摘内容と自分の認識があっているかの確認の意図でした。

されていないなら実行権がつけるか、最初の例のように sh をつけて実行するです。

上記と下記例から読み取ると、shコマンドを使うと、実行権限がないファイルも実行できるのか?と思って調べたのですが、そういうことなのですね。

sh .github/workflows/create-text.sh
sh < .github/workflows/create-text.sh
cat .github/workflows/create-text.sh | sh

.github/workflows/create-text.shは.sh自体に実行権限がないと実行できない。
sh .github/workflows/create-text.shはshに実行権限があれば、.shになくても実行できる。
根本的な部分の理解が足りなかったようで、理解できてスッキリしました。

コメントいただき助かりました!