はじめに
GitHubActionsはビジネスロジックもあまり入ってこないし、大きなリポジトリだったり複雑なサービス構成でもない限りやることも似通っている。
それなら、生成AIにやらせるのがぴったりだと思い「簡単なGitHubActionsは生成AIに作らせよう」というこぎみの良いタイトルで記事を書きながら検証を始めましたが、確かに助けにはなりますが、思ったよりすんなりいかない生成AIの現実、当然のようにハルシネーションにでくわしたのでその過程と回避策や注意点をベタにまとめようと思います。
また、生成AI、ChatGPTどう使っている、使うときはどのあたりを気をつけている、と聞かれた時のとてもベタな作業レベルでイメージが共有できたらなという思いで記述しています。
前提として
- doc以下のmdファイルの更新を検知するとhtmlに変換してpublicディレクトリにpushするworkflowの実装を目指す
- 利用する生成AIはChatGPTのモデル「ChatGPT 4o」
📂 .github/
└── 📂 workflows/
└── 📄 doctohtml.yaml # 成果物
📂 doc/
└── 📄 test.md
📂 public/
本記事で表現したいこと
- 生成AIを使った試行錯誤の過程とうまく利用するための注意点
- GithubActionsによる md -> htmlの自動変換のコード
課題:doc以下のmdファイルの更新を検知するとhtmlに変換してpublicディレクトリにpushするworkflowを実装する
命令①:箇条書きで実現したいロジックを記述
プロンプトを真剣に学んでる方からはなんとかしろと言われかねない内容ですが、内容も内容ですしこんなもんでいけます。
以下の条件でGitHubActionsを組んでくれ
・リポジトリに含まれているmdファイルをHTMLに変換する
・その際、docディレクトリ配下にあるmdファイルの変更を検知して実行する。
・pushされると、実行されて変換したHTMLがPUSHされる。
GPT回答①:ロジックの流れはこの時点で完成
上記の質問のみでロジックの流れはこの段階で概ね完成します(以下展開式のパネル)。処理を追ってみると問題ないように見えます。pandocというライブラリを使っていることをチェックします。
GPT-4oの1回目の回答 - エラーあり
name: Convert Markdown to HTML
on:
push:
branches:
- main # 実行したいブランチを指定
paths:
- 'doc/**/*.md' # docディレクトリ配下の.mdファイルのみ検知
jobs:
convert-md-to-html:
runs-on: ubuntu-latest
steps:
# リポジトリのチェックアウト
- uses: actions/checkout@v4
# 変更されたMarkdownファイルのリストを取得
- name: Get changed markdown files
id: changed-files
uses: tj-actions/changed-files@v45
with:
files: |
**.md
# Pandocをインストール
- name: Install Pandoc
run: sudo apt-get install -y pandoc
# MarkdownファイルをHTMLに変換
- name: Convert Markdown to HTML
if: steps.changed-files.outputs.any_changed == 'true'
env:
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
run: |
for file in ${ALL_CHANGED_FILES}; do
if [[ $file == doc/*.md ]]; then
base_name=$(basename "$file" .md)
pandoc -f markdown -t html "$file" -o "public/${base_name}.html"
fi
done
# 変換したHTMLをGitHubにコミット
- name: Commit HTML files
if: steps.changed-files.outputs.any_changed == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions@users.noreply.github.com"
git add public/*.html
git commit -m "Auto-convert Markdown to HTML by GitHub Actions"
git push
この時点でロジックの流れ自体はもうほぼ完成しています。それほど難しいことをしているわけではありませんが、大事なファイルの存在チェックの判定や、忘れがちなshellの文法など、秒で作成してくれるのは頼もしい限りです。
実行結果①:PUSHでエラー
git push大丈夫かなと思ったらやっぱり出ます。すかさず再度GPT4oに質問します。
出てきたGithubActionsのエラーをそのまま貼り付けます。
命令②:雑にエラーを貼って原因を聞く
これどうしよ、はいらないです。
これどうしよ
Run git config user.name "github-actions[bot]"
git config user.name "github-actions[bot]"
git config user.email "github-actions@users.noreply.github.com"
git add public/*.html
git commit -m "Auto-convert Markdown to HTML by GitHub Actions"
git push
shell: /usr/bin/bash -e {0}
[main 95bbb97] Auto-convert Markdown to HTML by GitHub Actions
1 file changed, 55 insertions(+)
create mode 100644 public/test.html
remote: Permission to xxxxx/githubactions-sanbox.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/xxxxx/githubactions-sanbox/': The requested URL returned error: 403
Error: Process completed with exit code 128.
GPT回答②:エラーの解決策を記述、設定周りの確認も合わせて説明。
ソースは省略して貼りますが、趣旨はGITHUB_TOKENをつっこんでくれ、とのことでgit push時にGITHUB_TOKENを使うように以下のように修正します。
# 変換したHTMLをGitHubにコミット
(...省略)
git commit -m "Auto-convert Markdown to HTML by GitHub Actions"
# git push
- name: Push changes to GitHub
if: steps.changed-files.outputs.any_changed == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git push https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git
また、リポジトリ設定の確認も要求されました。説明されたリポジトリの設定欄は微妙に現状の状態と違いましたが、同等の箇所はわかるので、これを持ってGitHubから設定を修正します。以下がGPTがくれた回答です。
デフォルトの GITHUB_TOKEN がリポジトリにプッシュできないように設定されている可能性があります。この場合、リポジトリの設定から GITHUB_TOKEN の権限を確認する必要があります。
- リポジトリの Settings -> Actions -> General に移動します。
- Workflow permissions の設定を確認してください。
Read and write permissions を選択して、GitHub Actionsがリポジトリに書き込みできるようにします。
Actionsのyaml内でできることだろうと疑いググった結果。permissionsを見つけますが、一旦よしとします。(※このあと、これはpermissionsでできるだろうと尋ねると、GPTはコードを提示してくれました)
permissions:
contents: write
実行結果②: markdown->html自動生成が動作するようになった、が、生成されたHTMLにスタイルがない。
コードに問題ありませんでした、が、今回pandocで出力されたHTMLの内容はスタイル適用がなく、いまいちです。これでは使えません。
命令③-1:pandocによるスタイル適用を依頼する
ここで、pandocで生成するHTMLにスタイル適用してくれ、と聞きました。が、最初適当な1行分のスタイルのcssを示したり、手動で作り出すので、ここで自分はpandocにはいわゆるテンプレのようなものは組み込まれておらず、自分で選んでくるものなのか、と早合点し、別のライブラリによる作成に舵を切ります。それが命令④以降です。
質問例①:
phandocで適用して
質問例②:
phandocでもスタイル指定すればmarkdown綺麗に出力できるんだね。
githubactionsならどうかく?
GPT回答③-1:CSSファイルの作成とスタイリング適用方法を提案
見る気も失せるcssカスタムを提案してくれました。いやこういうものはテンプレートだろうとpandocが知らなくても想像はつくのでスキップ。
# おすすめカスタムCSSを作成
- name: Create custom CSS
run: |
echo "body { font-family: Arial, sans-serif; line-height: 1.6; margin: 20px; }" > custom.css
echo "h1, h2, h3 { color: #333; }" >> custom.css
echo "code { background-color: #f4f4f4; padding: 2px 4px; border-radius: 4px; }" >> custom.css
echo "table { border-collapse: collapse; width: 100%; }" >> custom.css
echo "th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }" >> custom.css
echo "th { background-color: #f2f2f2; }" >> custom.css
(省略)
pandoc "$file" -o "./public/${base_name}.html" --css=custom.css
命令③-1 -> 命令③-2の間にGoogle検索で情報収集の時間があります。いい感じにスタイル入れてよ、ではGPTはpandocのtemplateを利用するやり方を一向に提案してくれませんでした。③-1での察してくれなさは個人的には意外でした。
命令③-2:Google検索でpandocのtemplatesの存在を把握し、その上で質問を投げる
命令③-1でもらった結果は実行せず、pandocについて調べてテンプレートの適用方法について把握し、具体的なコマンドを投げつつ、改めてGPTに命令します。
このテンプレートの命令をロジックに入れて挙げて
pandoc -s --toc --template=easy-pandoc-templates/html/elegant_bootstrap_menu.html sample.md -o sample.html
あと、テンプレートのこれインストールも忘れずに
curl 'https://raw.githubusercontent.com/ryangrose/easy-pandoc-templates/master/copy_templates.sh' | bash
GPT回答③-2:pandocのテンプレートを指定したHTML出力部分をズバリ回答
やっと察してくれました。
また、sample.mdなど適当な指定していても、これを置き換えて今までのロジックの中にディレクトリ内のループで出力してくれています。
- name: Download Pandoc templates
run: |
curl 'https://raw.githubusercontent.com/ryangrose/easy-pandoc-templates/master/copy_templates.sh' | bash
# MarkdownファイルをHTMLに変換
- name: Convert Markdown to HTML with Template
if: steps.changed-files.outputs.any_changed == 'true'
env:
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
run: |
for file in ${ALL_CHANGED_FILES}; do
base_name=$(basename "$file" .md)
pandoc -f markdown -t html --template=easy-pandoc-templates/html/elegant_bootstrap_menu.html "$file" -o "public/${base_name}.html"
done
実行結果③-2: 完成
完成しました。
name: Convert Markdown to HTML fix
on:
push:
branches:
- phandoc-ver
- main # 実行したいブランチを指定
paths:
- 'doc/**/*.md' # docディレクトリ配下の.mdファイルのみ検知
jobs:
convert-md-to-html:
runs-on: ubuntu-latest
steps:
# リポジトリのチェックアウト
- uses: actions/checkout@v4
# 変更されたMarkdownファイルのリストを取得
- name: Get changed markdown files
id: changed-files
uses: tj-actions/changed-files@v45
with:
files: |
**.md
# Pandocをインストール
- name: Install Pandoc
run: sudo apt-get install -y pandoc
- name: Download Pandoc templates
run: |
curl 'https://raw.githubusercontent.com/ryangrose/easy-pandoc-templates/master/copy_templates.sh' | bash
# MarkdownファイルをHTMLに変換
- name: Convert Markdown to HTML
if: steps.changed-files.outputs.any_changed == 'true'
env:
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
run: |
for file in ${ALL_CHANGED_FILES}; do
if [[ $file == doc/*.md ]]; then
base_name=$(basename "$file" .md)
pandoc -f markdown -t html -s --template=easy_template --metadata title="${base_name}" "$file" -o "public/${base_name}.html"
fi
done
# 変換したHTMLをGitHubにコミット
- name: Commit HTML files
if: steps.changed-files.outputs.any_changed == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions@users.noreply.github.com"
git add public/*.html
git commit -m "Auto-convert Markdown to HTML by GitHub Actions"
- name: Push changes to GitHub
if: steps.changed-files.outputs.any_changed == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git push https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git
そして、もう一つ、この命令③からGPT回答③-2の回答で完成としたmd→html出力ですが、命令③-1のGPTの回答で右往左往している間に、pandoc以外の別のライブラリを見つけて、試したりもしました。
命令④-1:pandocの代わりにと、URLを共有しつつ見つけたライブラリの書き換えを提案。
https://github.com/marketplace/actions/converts-markdown-text-to-html
こいつを使って、markdown -> htmlするようにしたのを、
(省略:上述のソース貼り付け)
にあてはめて再度出力してほしい
GPT回答④-1: 存在しないアクションをひいてしまう
(省略)
- name: Convert Markdown to HTML
if: steps.changed-files.outputs.any_changed == 'true'
uses: tj-actions/markdown-to-html@v2
with:
source: '${{ steps.changed-files.outputs.all_changed_files }}'
destination: 'public/'
(省略)
良さそうに見える回答が返ってきました、が、vscodeはそんなものはないと赤線を引くありさま。よく見ると渡したURLとは全然違うActionを指定していることに気がつきます。
古いものなのか、はたまた存在してなかったのか、どちらにせよ、URLでページを読ませてやってくれというのは厳しいようです。この回答を受けて命令を変えます。
命令④-2: アクションではなく、手動コマンドでの実行を提案。
GitHub MarketPlaceが怪しいのなら、npmパッケージの方は情報も古くからあったのかもしれないと、そちらで書き換えを依頼してみます。
※意訳:何回かに分けて質問してます
nodejs入れてmarkdown-to-html-cliを手動でインストールして、今のpandocでやってることやって
GPT回答④-2: 書いてくれる
良さそうな内容で出力してくれました。
(省略)
# Node.jsとnpmをインストール
- name: Install Node.js
run: |
sudo apt update
sudo apt install -y nodejs npm
# markdown-to-html-cliをインストール
- name: Install markdown-to-html-cli
run: |
npm install -g markdown-to-html-cli
# MarkdownファイルをHTMLに変換
- name: Convert Markdown to HTML
if: steps.changed-files.outputs.any_changed == 'true'
run: |
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
base_name=$(basename "$file" .md)
mkdir -p ./public
markdown-to-html "$file" -o "./public/${base_name}.html"
done
(省略)
実行結果④-2: 存在しないパスを指定しエラー
Convert Markdown to HTMLブロックでエラーになってしまいました。
(省略)
Run for file in doc/test.md; do
for file in doc/test.md; do
base_name=$(basename "$file" .md)
mkdir -p ./public
markdown-to-html "$file" -o "./public/${base_name}.html"
done
shell: /usr/bin/bash -e {0}
node:fs:1391
handleErrorFromBinding(ctx);
^
Error: ENOTDIR: not a directory, mkdir '/home/runner/work/githubactions-sanbox/githubactions-sanbox/public/test.html/doc'
at Object.mkdirSync (node:fs:1391:3)
at module.exports.makeDirSync (/usr/local/lib/node_modules/markdown-to-html-cli/node_modules/fs-extra/lib/mkdirs/make-dir.js:23:13)
at file:///usr/local/lib/node_modules/markdown-to-html-cli/lib/index.js:81:16
(省略)
mkdirでおこっているように見えたので、mkdir -p ./public を消しましたが、当然変わりません。-pはディレクトリが存在しない場合のみ作るの意です。
命令④-3: 上記のエラーの内容をべたに質問
どうやらmarkdown-to-htmlのコマンドが怪しそうですが、一旦ベタに聞いてしまいます。
エラーだとさ
(省略)
[実行結果④-2:貼り付け]
(省略)
GPT回答④-3:回答は変わらない。
出力先が間違っているからエラーになる、という回答ですが、答えとして提示されるコードが変わりません。これはかなりGPTあるあるです。こうなった時点でGPTとはお別れするべきです。markdown-to-htmlのコマンドの調整を期待しましたがそうはなりませんでした。
改めて公式サイトを見に行くと、シンプルに引数を間違えていた。というより足りてませんでした。
🙅♀️間違い
markdown-to-html "$file" -o "./public/${base_name}.html"
↓
🙆正しい
markdown-to-html --source "$file" -o "./public/${base_name}.html"
これが修正内容です。とGPTが言って返ってきた回答が前と変わらない場合は、GPTを見限る。こちらからもGPTがわかっていないことがはっきりと自覚できる分、嘘情報よりは安易か
実行結果④-3:上記の引数追加で成功。
上記の引数指定により無事に出力されました。
こちらのライブラリは、デフォルトでDarkモードLightモードの切り替えのJSイベントがついてくるなど魅力的でしたが、nodejsをインストールする手間などでpandoc側のアクションの実行速度が速かったこともあり③の方を採用しました。
name: Convert Markdown to HTML fix
on:
push:
branches:
- main
- phandoc-ver # 実行したいブランチを指定
paths:
- 'doc/**/*.md' # docディレクトリ配下の.mdファイルのみ検知
jobs:
convert-md-to-html:
runs-on: ubuntu-latest
steps:
# リポジトリのチェックアウト
- uses: actions/checkout@v4
# Node.jsとnpmをインストール
- name: Install Node.js
run: |
sudo apt update
sudo apt install -y nodejs npm
# markdown-to-html-cliをインストール
- name: Install markdown-to-html-cli
run: |
npm install -g markdown-to-html-cli
# 変更されたMarkdownファイルのリストを取得
- name: Get changed markdown files
id: changed-files
uses: tj-actions/changed-files@v45
with:
files: |
**.md
# MarkdownファイルをHTMLに変換
- name: Convert Markdown to HTML
if: steps.changed-files.outputs.any_changed == 'true'
run: |
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
base_name=$(basename "$file" .md)
echo "base_name: $base_name"
echo "file: $file"
markdown-to-html --source "$file" -o "./public/${base_name}.html"
done
# 変換したHTMLをGitHubにコミット
- name: Commit HTML files
if: steps.changed-files.outputs.any_changed == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions@users.noreply.github.com"
git add public/*.html
git add doc/*.html
git commit -m "Auto-convert Markdown to HTML by GitHub Actions"
- name: Push changes to GitHub
if: steps.changed-files.outputs.any_changed == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git push https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git
結論
ChatGPTは知らないことを知らないと言ってくれないのが出現当時から今も変わらぬハマりやすい盲点かと思います。要はハルシネーションです。
- 最初に投げて返ってくる一筆書きのようなロジックは「おおむね」頼りになる
- URLを共有して「〇〇を踏まえた上で解いてくれ」の聞き方はあまり信用できない(2024年9月のGPT4o時点)
- ググって調べて、生成されたコードの技術の最新情報、公式ドキュメントをきちんとあたること。
- GPTから同じ回答が返ってきた時は諦める
- ビジネスロジックや秘匿情報は突っ込まないように、ということを考えると、GitHubActionsあたりはやっぱり利用しやすい
余談
「簡単なGitHubActionsは生成AIに作らせよう」のタイトルで記事を書き出した時の「はじめに」
CI/CDの考え方自体には歴史があり、Jenkins,Travis CI,CircleCI,AzurePipelines,GitHubActionsなどツールも数々生まれて来ました。歴史ありツールは様々ありますが、基本的にやることは変わっていません。ビルド、テスト(検証含む)、デプロイ、それぞれの自動化を目論むものであることは変わっていません。
上記の歴史も踏まえ、以下の理由からGitHubActionsは生成AI(ChatGPT-4o)に任せてしまうのが何よりと考えています。
- CI/CDでやることは基本的には決まっている。ビルド、テスト、デプロイ、という目的はプロジェクトがいくら複雑化しても変わることはありません
- ビジネスロジックが入る余地はない。プロジェクトごとに必要な固有のカスタマイズがあるのは当然だと思いますが、生成AIに食わせるに躊躇うようなロジックが入ることは少ないです