github-action-artifactbundle
というGitHub Actionを作った。これでAppleの規定するバイナリ配布形式、Artifact Bundleに添ったアーカイブを簡単に作成できる。
Artifact Bundleは、本来、Package Pluginなどの仕組みでのexecutableの配布を想定したフォーマットだが、@mtj0928の開発したexecutable管理ツールnestもArtifact Bundleを想定しているため、この形式で配布しておくとユーザーの利便性が高い。
Artifact Bundleはアーキテクチャやプラットフォームごとのバイナリをzipに詰め、メタデータとしてJSONを添付するだけの簡易なフォーマットだ。一方で、簡単に作る方法がなく配布がとても面倒。このActionを使えば、Swift Packageからビルドしたバイナリを簡単に配布できる。
on: release: types: [published, edited] name: Upload Artifact Bundle to Release env: DEVELOPER_DIR: '/Applications/Xcode_16.2.app/Contents/Developer' jobs: release: runs-on: macos-15 steps: - uses: actions/checkout@v4 - name: Build Universal Binary run: swift build --disable-sandbox -c release --arch arm64 --arch x86_64 - uses: giginet/github-action-artifactbundle@v2 id: artifactbundle with: artifact_name: myexecutable - name: Upload Artifact Bundle to Release run: | BODY="${{ github.event.release.body }}" BUNDLE_PATH="${{ steps.artifactbundle.outputs.bundle_path }}" SHA256="${{ steps.artifactbundle.outputs.bundle_sha256 }}" TAG_NAME="${{ github.event.release.tag_name }}" gh release upload "${TAG_NAME}" "${BUNDLE_PATH}" NEW_BODY="$(printf "%s\n%s" "$BODY" "$SHA256")" gh release edit "${TAG_NAME}" --notes "${NEW_BODY}" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ビルドや配布の責務は持たないこととして、予め用意したバイナリを指定のフォーマットに圧縮するだけの設計にした。
Artifact Bundleの仕様上、バイナリであれば特にどの言語で書かれたものかは問わないが、このアクションでは割り切ってSwift Packageからのビルドにしか対応していない*1。Swift Packageのビルドディレクトリ構造から経験的にバイナリを探したり、アーキテクチャを特定している。
SHA256ハッシュの計算もできる。サンプルのようにReleaseトリガーや、gh
と併用すれば、リリース作成時に簡単にアーカイブとハッシュ値を公開できる。
Static Linux SDKサポート
Swift 6.0から、macOSのみでLinux向けのSwiftバイナリをビルドできるようになった。このActionはこの仕組みによる成果物にも対応している。
Swift.org - Getting Started with the Static Linux SDK
macOS Runnerさえあれば、macOSとLinux両方に対応したバイナリ配布が容易にできる。これによって、macOSのいらないSwiftで書いたツールをLinuxで動かしたりもできる。
TypeScriptで書いた
GitHub Actionには、Dockerアクション、複合アクション、JavaScriptアクションの3つの形式があり、その気になればどの言語でもActionを実装できる。
とはいえ、今回のケースでは、まずmacOSでの実行を最優先に考えなくてはならない。残念ながらmacOS RunnerではDockerアクションは実行できないので、これで多くのインタプリタ言語が候補から消える。*2
もちろん、Swiftの採用は有力候補だったが、ビルドが必要な言語はビルド時間のオーバーヘッドが気になる。バイナリを配布すれば良いが、バイナリ配布のツールでバイナリ配布を考えなければいけないのは世話がない。
結果的にほぼJavaScriptアクションしか選択肢がなかったので、TypeScriptを選択した。
TypeScriptが書けないのでAIで書いた
TypeScriptはたまに必要があれば書いていて、過去にdenopsを使ったNeovimプラグインを書いたりしていたけど、あまり日常的に使っていないので不慣れ。node全くわからん。
というわけで、今回はほとんどをAIコーディング拡張のClineに任せて書いてみた。というか、どちらかというと因果関係が逆で、AIによるコーディングをちゃんとしてみたかったので、題材としてGitHub Actionを作ってみたというのが正しい。
結果的に、AIの頭の良さに感激した*3。今回のようなかなり尖ったドメインでも十二分にコーディングができることが実証できた。
今回の話はここからが見どころだけど、長くなるので次の記事で。
Artifact Bundleを配布しよう!!!
このツールで世の中のSwift製ツールのArtifact Bundle対応が進めば、全部nestでビルド済みバイナリとして入れられるようになって幸せ。どうぞご利用ください。