Skip to content

ci: build release artifacts in a tag-scoped workflow - #11

Merged
furedea merged 3 commits into
mainfrom
ci/release-artifacts-workflow
Oct 20, 2026
Merged

furedea merged 3 commits into
mainfrom
ci/release-artifacts-workflow

Conversation

@furedea-agent

@furedea-agent furedea-agent Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

概要

  • Release PR chore(main): release apple-mail-cli 0.1.1 #10(0.1.1)はこの PR より先にマージしないこと.main の現行ワークフローのままリリースすると,以下の問題を抱えたまま 0.1.1 が出る.
  • 成果物のビルドを release_artifacts.yml に分け,release-please がタグ上で起動する.自動でも手動でも同じ経路を通るため,draft が取り残されなくなる.成果物ワークフローは draft の Release にしか触れない.
  • 公開は REST API で draft を boolean の false,make_latest を legacy として送り,古いタグの実行が後から終わっても新しい版の latest を奪わない.
flowchart LR
  A[main へ push] --> B[release-please]
  B -->|Release PR のマージ後| C[タグと draft Release]
  C --> W[gh workflow run release_artifacts.yml --ref タグ]
  M[失敗した draft の再開] --> W
  W --> V[ref,HEAD,draft の検証]
  V --> D[テスト,ビルド,スモークテスト,attestation,アップロード]
  D --> P[gh api PATCH -F draft=false -f make_latest=legacy で公開]
Loading
項目 変更前(#8 時点の main) 変更後
成果物のビルド release_please.yml 内の後続ジョブ release_artifacts.yml をタグ上で workflow_dispatch 起動
自動と手動の経路 自動は push の実行内,手動は release_please.yml の workflow_dispatch どちらも gh workflow run release_artifacts.yml --ref <tag> -f tag_name=<tag>
後続 push との競合 マージコミットの実行が後続 push に置き換わると,ガードで失敗して draft が残る タグ上で動くので GITHUB_SHA は常にタグのコミット
公開済み Release の再ビルド --clobber で上書きできてしまう ビルド前に isDraft を確認し,draft でなければ失敗
公開と latest gh release edit --draft=false(make_latest は true 扱い) gh api -X PATCH .../releases/<id> -F draft=false -f make_latest=legacy(draft は boolean)

受け入れ条件

  • この PR をマージしてから Release PR chore(main): release apple-mail-cli 0.1.1 #10 をマージする
  • chore(main): release apple-mail-cli 0.1.1 #10 のマージ後,release_please.yml が release_artifacts.yml をタグ上で起動し,成果物のアップロード後に Release が公開される
  • 公開後の latest が最新の版を指し,README の releases/latest/download のインストーラーが最新版を配る
  • release_artifacts.yml はタグ以外の ref,HEAD と GITHUB_SHA の不一致,公開済みの Release でビルド前に失敗する
  • 公開ステップは draft を boolean(-F draft=false),make_latest を legacy として送り,gh release edit を使わない
  • CONTRIBUTING.md に draft の再開手順を記載し,公開済みの Release は作り直さないことを明記する
詳細

経緯

#8 のレビュー(Codex)で見つかった 2 件と,この PR のレビューで見つかった 2 件の修正.#8 は修正前の eee0747 の時点で squash マージされたため,修正コミットを main の上に cherry-pick して出し直した.

1. [high] 公開済み Release の作り直し

  • gh release upload --clobber は各アセットを消してから上げ直す.公開済みの Release を手動で作り直すと,途中のネットワーク障害でファイルが欠けたまま公開状態になり,README の releases/latest のインストーラー URL が壊れる
  • Verify release target ステップで gh release view "$TAG_NAME" --json isDraft --jq .isDraft が true でなければ失敗する

2. [medium] draft の取り残し

  • 一つのワークフロー内では,Release PR のマージコミット R の待機中の実行が後続の push S に置き換わると,S の実行は HEAD=R,GITHUB_SHA=S となってガードで失敗する.release-please は PR を tagged 済みにしているため以後 release_created は立たず,draft が残る
  • release_please.yml は draft とタグを作るだけにし,release_created のときに gh workflow run release_artifacts.yml --ref "$TAG_NAME" -f tag_name="$TAG_NAME" を実行する.ジョブには既存の権限に加えて actions: write を付け,GITHUB_TOKEN で起動する(workflow_dispatch は GITHUB_TOKEN からでも新しい実行を作れる)
  • release_artifacts.yml は workflow_dispatch のみで,concurrency はタグごと.ref と SHA のガードは維持する

3. [medium] 古い版が latest を奪う問題(ef18660)

  • タグごとの concurrency では,v0.1.1 の実行が v0.1.2 の公開後に終わりうる.make_latest を指定せずに公開すると true 扱いになり,古い版が latest になって README のインストーラーが古い版を配る
  • Publish release ステップで gh release view "$TAG_NAME" --json databaseId から ID を取り,REST API の PATCH で make_latest=legacy を指定して公開する.legacy では GitHub が作成日時と semver から latest を選ぶ

4. [high] draft が文字列で送られる問題(814caa9)

  • gh api -f draft=false は JSON の文字列 "false" を送るが,Release API は boolean を要求する
  • draft は typed の -F draft=false で送る(gh api の -F は true,false,null,整数を JSON の型に変換する).make_latest は文字列なので -f make_latest=legacy のまま

変更ファイル

  • .github/workflows/release_please.yml:成果物ジョブを外し,起動ステップを追加
  • .github/workflows/release_artifacts.yml:新規(ガード,-F draft=false -f make_latest=legacy の公開ステップを含む)
  • CONTRIBUTING.md:Release 節

ローカル検証

  • Verify release target の本体をコミット済みのワークフローから取り出し,/bin/bash 3.2 と偽の gh で 6 ケース検証(ref が main,別タグ,SHA 不一致,公開済み,draft 状態が空は失敗,タグ上で SHA 一致かつ draft は成功)
  • Publish release の本体を同様に取り出し,呼び出しを記録する偽の gh で 4 ケース検証(終了コード 0,api -X PATCH repos/furedea/apple-mail-cli/releases/4242 -F draft=false -f make_latest=legacy が 1 回,release edit は 0 回,-f draft= は 0 回).-f draft=false の時点では 2 件失敗,修正後は 4 件成功
  • actionlint,zizmor --offline:指摘なし

CI や実リリースでしか確認できないこと

  • GITHUB_TOKEN による gh workflow run --ref <tag> の起動
  • draft Release への gh release view/upload と gh api PATCH による公開,make_latest=legacy での latest の選ばれ方

その他

  • RELEASE_PLEASE_TOKEN は登録済み(chore(main): release apple-mail-cli 0.1.1 #10 が作られている).この PR で必要な権限の追加はない
  • 古いリモートブランチ ci/release-packaged-cli は不要で,削除してよい

Refs #7, #8, #10

🤖 Generated with Claude Code

furedea and others added 3 commits October 20, 2026 13:15
Release Please now only creates the draft release and dispatches the new
Release Artifacts workflow on the tag, so a later push replacing a
pending run can no longer strand the draft behind a ref/SHA mismatch.
Automatic and manual runs share that single tag-scoped path.

The artifact workflow refuses to run unless the release is still a
draft, because --clobber deletes assets before re-uploading and would
break a published release on failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Per-tag concurrency lets an older tag's artifact run finish after a newer
release is published. Publishing with gh release edit implies
make_latest=true, so the older release would take latest and the README
installer would serve it. Publish through the REST API with
make_latest=legacy so GitHub picks latest by date and semantic version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gh api -f sends draft=false as the JSON string "false", but the Release
API requires a boolean. Use the typed -F flag for draft and keep
make_latest as a string field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@furedea
furedea merged commit 96a397d into main Oct 20, 2026
16 checks passed
@furedea
furedea deleted the ci/release-artifacts-workflow branch October 20, 2026 04:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant