20.7K Views
April 09, 24
スライド概要
https://cybozu.connpass.com/event/311067/
Engineering Productivity Meetup #2 in 大阪 での発表資料
渋谷のWeb系企業で働くエンジニア 最近はテストや自動化関係に興味があります
OSSのリリース作業をなるべく簡単にする Engineering Productivity Meetup #2 in 大阪 サイボウズ株式会社 開発本部 生産性向上チーム 加瀬 健太(@Kesin11)
自己紹介 ▌加瀬 健太(@Kesin11) ▌経歴 ◼ ~2023/06 株式会社DeNA SWET第二グループ @Kesin11 ◼ 2023/07 サイボウズ株式会社 生産性向上チーム @Kesin11 ▌業務 ◼ Github Actionsセルフホストランナーの運用など ▌日課はgithub.blog/changelogを見ること @kesin11.bsky.soci al
Productivity Weekly ▌「1週間の間に発見された開発者の 生産性向上に関するネタを共有する 会」を社内で開催した内容をzennで 公開 ▌100回を突破して現在147回! ▌CI/CD関連のネタが多いのでぜひ
自己紹介(OSS) ▌有名ではないがそれなりに継続してメンテしてる自信あり ◼ Kesin11/Firestore-simple: 2019 – 2021(Archived) ◼ Kesin11/danger-textlint: 2019 – 2022(Archived) ◼ Kesin11/ts-junit2json: 2020 - 2024 ◼ Kesin11/CIAnalyzer: 2020 – 2024 ◼ Kesin11/actions-timeline: 2023 - 2024 @Kesin11
OSSを細く長くメンテを続けるコツ
目次 ▌周辺環境のアップデートについていく ▌リリース作業の手間を極力減らす ▌自分の事例(release-drafter)
周辺環境のアップデートについていく
「何もしていないから壊れる」時代へ https://speakerdeck.com/twada/strategy-and-tactics-of-building-automated-testing-culture-into-organization-2020-autumnedition?slide=27
「何もしていないから壊れる」時代へ ▌これは本当 ▌周辺技術のアップデートに取り残されるといつの間にか動かなくなる ▌言語のLTSも2-3年経過すれば更新される ▌LTS更新に連動して依存パッケージに破壊的変更が入ってくることも
パッケージの自動更新と自動テスト ▌依存パッケージ、ランタイムの更新はRenovate, Dependabotに 任せられる時代 ▌リリース作業のたびに手動テストしてられないのでテストコードを書く ◼ 自分がリリースに自信を持てる程度のテストをちゃんと書く ◼ もしくはmainブランチでドッグフーディングする ◼ 最悪、CLI系のツールなら起動テストだけでも用意しておくと安心 ▌OSSほど自動テストがちゃんと書かれている理由の一つだと思う
リリース作業の手間を極力減らす
リリース作業のイメージ ▌リリースノート作成 ▌次のバージョン番号決め ▌gitタグ打ち ▌パッケージのpublish ▌ドキュメントやサンプルコードのバージョン更新 それぞれの工程に流派がある
リリースノート作成の流派 ▌どこに置くか ◼ GitHub Releases ◼ CHANGELOG.md ▌何を書くかは大体似てる ◼ カテゴリ ◼ 修正内容 ◼ pull-req番号 ◼ author https://github.com/goreleaser/goreleaser/releases/tag/v1.25.1 のリリースノート
次のバージョン番号決め ▌大枠としてはいつmajorバージョンを上げるかという話 ▌有名なのはSemantic Versioning(SemVer) 破壊的変更(BREAKING CHANGES) 後方互換性 なし major 機能追加(Feature) 後方互換性 あり minor バグ修正(Bugfix) 後方互換性 あり patch セキュリティ修正(Security) 後方互換性 あり patch ▌v1.2.3の例:major=1, minor=2, patch=3
次のバージョン番号決め ▌現代ではSemVerにするべき ▌一番重要なのは破壊的変更(=後方互換がない)が分かること ▌後方互換性がある間は安心してアップデートできる ◼ RenovateやDependabotで後方互換性があるバージョンまでは オートマージするアップデート戦略 ◼ 全てがSemVerに従っている前提だと設定が簡単になる
次バージョン自動決定の流派 ▌SemVerに従えば次バージョンも機械的に決定可能 Conventional commit 流派 PRのラベル流派 コミットメッセージに規則をもたせる ラベルに規則を持たせる • BREAKING CHANGE: major • “!”を末尾に付ける(feat!など): major • feat: minor • fix: patch • その他(chore, ci, docsなど): patch
リリース作業自動化ツールの流派 ▌特定の言語に特化した一気通貫派 ▌言語に非依存の一部自動化派
特定の言語に特化した一気通貫派 ▌publishまで全て完結するツール ▌リリースノート作成 ▌goreleaser/goreleaser ▌次のバージョン番号決め ▌algolia/shipjs ▌gitタグ打ち ▌パッケージのpublish ▌ドキュメントやサンプルコードの バージョン更新
言語に非依存の一部自動化派 ▌言語に依存しない作業までを自動 化するツール ◼ release-drafter/releasedrafter ◼ songmu/tagpr ◼ googleapis/release-please ▌リリースノート作成 ▌次のバージョン番号決め ▌gitタグ打ち ▌パッケージのpublish ▌ドキュメントやサンプルコードの バージョン更新
自分の事例 release-drafterを全面的に採用
自分の事例 ▌ほぼ全てのOSSでrelease-drafterを利用 ◼ +publish部分は言語に応じてコマンド手書き ◼ +リリースはworkflow_dispatchで手動トリガー https://github.com/release-drafter/release-drafter
自分の事例 ▌リリースノート作成 + 次バージョン決定 ◼ mainにpushするとrelease-drafterが ドラフト版Releasesを自動生成 ◼ 次バージョン(タグ)はpull-reqのラベル からsemverで自動的に決まる
実際のリリース作業 ▌何かしら修正したら即時 OR 月初にメンテしているパッケージを巡回 ▌workflow_dispatchのボタンを ポチってリリース開始 手書きで追加した部分 ▌BREAKING CHANGESなどの大きな 変更があればリリース後にGitHub Releasesの文章を手書きで追記する ▌終わり https://github.com/Kesin11/gh-workflow-ls/releases/tag/v2.0.0
自分の事例 ▌昔は一気通貫のshipjsを利用していたがやめた ▌npm publishの代わりにdocker pushに置き換えるのに苦労した ▌言語やリリースの形式は作るOSSの種類によって様々 ◼ publish部分だけ手書きで頑張れば、前段のrelease-drafter 部分はほぼコピペで済む ◼ 新しいリリースツールを覚える手間や言語サポートの確認が不要 ▌回り回って言語に依存しないツールが一番コスパが良い
当日はスキップ 自分の事例 ▌どの言語のOSSでもrelease-drafter関係の設定は共通になる ▌一発でテンプレからコピーする自分専用のスクリプトを自作した ▌Kesin11/gh-setup-release-drafter ◼ release-drafter.ymlのコピー(release-drafter自体の設定) ◼ workflows/release.ymlのコピー(リリースジョブのテンプレ) ◼ issue/prラベルのコピー ◼ BREAKING CHANGES, fix, securityなどsemver用のラベル
当日はスキップ publish部分のコマンド手書きの例 言語やリリース形式ごとのサンプル
当日はスキップ javascript/TypeScript ▌npm version ${release-drafterが決めた次バージョン} ◼ package.jsonのversionフィールドが更新される ◼ git commitとgit tagも自動で実行される ▌npm publish ▌git push origin main
当日はスキップ docker(コンテナを提供するタイプ) ▌docker buildx build でコンテナビルド ▌release-drafterが決めた次バージョンから3つのdocker tag打ち ◼ v${major} ◼ v${major.minor} ◼ v${major.minor.patch} ▌tag 3回分のdocker push ◼ 現在は docker/metadata-action で3つのタグを生成、 docker/build-push-actionでbuildしてまとめてdocker pushしてくれるので楽 参考:https://docs.docker.com/build/ci/github-actions/manage-tags-labels/
当日はスキップ Github Actions(js action) ▌1. release-drafterが決めた次バージョンから3パターン生成 ◼ v${major} ◼ v${major.minor} ◼ v${major.minor.patch} ◼ actions/github-scriptを使ってjsの正規表現で手書きで実現
当日はスキップ Github Actions(js action) ▌2. 3パターン分のgit tagをgit push -fで上書き ◼ 工夫するとgit tagコマンドは不要でgit pushだけで可能 ◼ git push -f origin “refs/tags/v${major.minor.patch}:refs/tags/v${major}” ◼ git push -f origin “refs/tags/v${major.minor.patch}:refs/tags/v${major.minor}” 参考:https://github.com/Kesin11/actions-timeline/blob/main/.github/workflows/release.yml
当日はスキップ Rust(GitHub Releasesにバイナリをアップロードするタイプ) ▌ビルドしてバイナリ生成 ▌release-drafterが生成したGitHub Releases(=git tag)に バイナリをアップロード ◼ gh release upload ${release-drafterが決めた次バージョン番号} ${バイ ナリへのパス} ◼ これをリリースするアーキテクチャ分だけ行う (matrixで並列化してもよい) 参考:https://github.com/Kesin11/junit2json-rs/blob /main/.github /workflows/release.yml
まとめ ▌OSSのリリース作業の各工程の流派を紹介 ▌自分はrelease-drafterを中心に据えたフローで統一 ▌リリース作業コストがほぼ0なので細く長く続けられている ▌大前提:自動テストとDependabotやRenovateの整備
謝辞 ▌自分が今の運用にたどり着いたのはazuさんのリリース関連の記事のおかげです この場をお借りして感謝いたします。 ◼ Git tagとGitHub ReleasesとCHANGELOG.mdの自動化について ◼ lernaでのmonorepoにおけるリリースフロー(Fixed/Independent) ◼ lernaからlerna-lite + turborepoに移行する ◼ 時期を決めて定期的に更新するnpmパッケージをChangesetsで管理す る ◼ GitHubのリリースノートを自動化する仕組み