モノレポで複数言語対応&柔軟バージョニングを自動化するCDツール cd-tools

この度、cd-toolsというライブラリをリリースしました。 この記事では、cd-toolsについて、その使い方を説明していきます。

著者

高角 樹

ソフトウェアエンジニア

2025-7-31

2025-7-31

高角 樹

モノレポで複数言語対応&柔軟バージョニングを自動化するCDツール cd-tools

#OSS

#CI/CD


cd-toolsの概要

cd-toolsはモノレポで複数言語&複数レジストリ対応の柔軟バージョニングデプロイを自動化するライブラリです。
モノレポだけでなく単一リポジトリでも利用でき、生成されたワークフローはユーザーが自由に編集することができます。現状デフォルトではnpmレジストリとGitHub Container Registryのみ対応していますが、Docker HubやJSRなどへの拡張も数行の修正で実現できます。
また、各言語用のバージョン更新関数を追加するだけで他言語サポートも可能な柔軟性を備えています。

使い方

セットアップ

インストール

一応インストールから説明します。npmで話を進めますが、yarnやpnpmなどを用いている方は適宜読み替えてください。

インストール手順は2通りあります。どちらでも構いません。
個人開発をたくさんする方なら以下(yarnやpnpmなどを用いている方は適宜読み替えてください)。

> npm install -g cd-tools

チーム開発でcd-toolsを使うという方は各リポジトリで以下を実行してリポジトリで管理するのがよいでしょう。

> npm install -D cd-tools

グローバルにインストールした場合は以下。

> cd-tools <command>

リポジトリにインストールした場合は以下でcd-toolsのコマンドを実行できます。

> npx cd-tools <command>

実行環境構築

READMEに記載しています。

一応こちらにも記載すると、Node.js(v20以上)、GitHub CLIが必要です。各自公式ドキュメントを参照してください。

また、GitHub CLIはインストール後、以下コマンドでログインする必要があります。

> gh auth login

コマンド実行

一応ヘルプコマンドも実装しています。

# 以下の実行結果はすべて同じ
# cd-tools
# cd-tools -h
# cd-tools --help
> cd-tools help
Usage: cd-tools <command>
Commands:
init Initialize cd-tools configuration
start-pr Start a new release PR
push-pr Update versions and create/update PR
end-pr Finalize release and merge PR

ヘルプコマンドの出力にあるように、cd-toolsで使うコマンドはたったの4つです。

それぞれについて解説していきます。

initコマンド

初期設定のコマンドです。
具体的には以下を行います。

  1. cd-toolsの設定ファイル(.cdtools/config.json)をデフォルトの設定で生成する
  2. プロジェクトをリリースする予定のレジストリを対話式でユーザーに選択してもらう
  3. Github Actionsで各プロジェクトをリリースするためのymlを生成する

本当は設定ファイルもnpm initみたいに対話式で最初からユーザー最適化されたjsonを生成したかったのですが、とりあえずMVP段階では要件から削りました。

実行画面は以下のような感じです。

レジストリを選択

init完了

それでは、生成されたファイルについてそれぞれ具体的に見ていきましょう。
少し長いですが、もちろんすべて理解する必要はありません。必要に応じて読んでください。

.cdtools/config.json

デフォルトで生成されるのは以下です。

https://github.com/LunaInsidious/cd-tools/blob/main/default-files/config.json

今のところjsonSchemaもありませんが、直近で対応する予定です。
さて、それぞれのフィールドについて解説していきます。

versioningStrategy

モノレポにおけるバージョニング戦略を選択します。

fixedまたはindependentのenumです。自分が知っているバージョニング戦略がこの2つでしたが、もし他にもあれば教えていただけると嬉しいです。

fixedはモノレポのプロジェクトすべてのバージョンを統一するバージョニング戦略です。大半のモノレポはこのバージョニング戦略の認識です。

具体的には、以下の例を考えます。

  • モノレポのプロジェクトとしてproject-a(v1.0.0),project-b(v1.0.0),project-c(v1.0.0)がある
  • project-aproject-bに依存している

このとき、project-aのみに差分を持つminor update(v1.0.0→v1.1.0)がされるとproject-b,project-cも同様にv1.1.0へ更新されます。

このバージョニング戦略を採用しているOSSは例えば以下などがあります(多分。git tagだけ見て判断してます)。

independentはリリースするプロジェクトと、リリースする差分に対しての依存を持つプロジェクトのみがリリースされます。また、プロジェクト自身に差分がなく、依存関係のみに差分がある場合は必ずpatch updateとなります。

fixedの時と同様の例で考えると、independentの場合はpackage-bがv1.0.1でリリースされ、package-cはリリースされません。

このバージョニング戦略を採用しているOSSは例えば以下などがあります。

versionTags

リリースしたいtagの一覧を設定します。
tagというのは1.0.0-rc.01.0.0-canary.0などのrc,canaryの部分のことです。
1.0.0などのtagなし(俗にいうstableリリース)は「stable」として予約語で登録しています。
それぞれ、versionSuffixStrategynext(optional)というフィールドを設定できます。

versionSuffixStrategy1.0.0-rc.0などで、tag名の後ろに付く番号をどのように採番するかを決定するフィールドです。
現状timestampincrementのenumです。
timestampの場合は1.0.0-rc.20250722135520のように、YYYYMMDDhhmmss形式のtimestampをsuffixとして付けます。
incrementの場合は、リリースのたびにgit tagをfetchしてきて、リリースする予定のバージョン、tagの最新の番号を取得して、その番号に+1した値をリリースします。
具体的には、ベースバージョンが1.0.0でtagがrcの最新のバージョンが1.0.0-rc.10だった場合、次は1.0.0-rc.11をリリースします。

nextは、そのtagをリリースするPRをマージした際にリリースするtagを決定するフィールドです。
例えば一般に、rc(Release Candidate)をリリースして検証した後、そのPRをマージした際にはstableリリースされることを想定されます。そういう時にrc tagのnextフィールドにstableを設定するとそのようにリリースできます。

projects

プロジェクトを管理します。プロジェクトというのは要するにリリースを分割する単位です。

pathtypebaseVersiondepsregistriesの5つのフィールドがあります。

pathにはそのプロジェクトのルートディレクトリからの相対パスを記載します。

typeにはそのプロジェクトでリリースする予定の言語を記載します。2025/7/22現在ではTypeScriptしかサポートしていませんが、対応言語を増やすのは割と簡単なので順次増やしていく予定です。

baseVersionにはそのプロジェクトの最新のstableリリースが記載されます。stableリリースのたびに自動で書き換わるので、利用者が触ることはあまりないでしょう。

registriesにはリリース対象のレジストリを記載します。複数記載できるので、npmjsrに同時にリリースも可能です。

.github/scripts/analyze-workspaces.sh

後述するGithub Actionsのワークフローで用いるシェルスクリプトです。

後ほどstart-prコマンドでブランチ情報ファイルというものを生成します。そこにはpushした際に「このpushではこのprojectをこのバージョン、このタグでリリースする予定です」という情報が入っています。

そのファイルを解析して、Github Actionsのワークフローにそれらの情報をmatrixで並列処理できるような形に整形して渡すためのシェルスクリプトです。

デフォルトで生成されるのは以下です。

https://github.com/LunaInsidious/cd-tools/blob/main/default-files/analyze-workspaces.sh

.github/workflows/release-\*.yml

\*にはリリース対象のレジストリが入ります。
initコマンドの際に選択したレジストリ用のリリースymlが生成されます。
先述のブランチ情報ファイルに差分が発生した際に呼び出され、リリースymlはレジストリにpublishするワークフローを並列処理するためのymlです。

今のところnpmとghcr.io(docker)が選択可能です。
デフォルトで生成されるのは以下です(npm版)。

https://github.com/LunaInsidious/cd-tools/blob/main/default-files/release-npm.yml

.github/workflows/publish-\*.yml

release-\*.ymlから呼び出されるymlです。
各レジストリにpublishするための処理が書いてあります。
ここはそこそこ触ることがある人もいるでしょう。もしjsrやGitHub npm registryにpublishしたい人はここを書き換える必要があります。
といっても、10行ほどのnpmにpublishするための処理をしている箇所があるので、そこをそのレジストリ用に書き換えるだけです。

https://github.com/LunaInsidious/cd-tools/blob/main/default-files/publish-npm.yml#L60-L73

デフォルトで生成されるのは以下です(npm版)。

https://github.com/LunaInsidious/cd-tools/blob/main/default-files/publish-npm.yml

start-prコマンド

initコマンドでcd-toolsの初期化を終わらせると、次は`start-pr`でリリース用のブランチを作りましょう。

具体的には以下を行います。

  • これから作る予定のブランチでリリースするタグをユーザーに選択してもらう
  • リリース用ブランチのブランチ名をユーザーに入力してもらう
  • ブランチ情報ファイルを生成する
  • リリース用ブランチにcheckoutする

実行画面は以下のような感じです。

リリースタグを選択

ブランチ名を記入

start-pr完了

特別言及することはありませんが、一応以下には言及しておきます。

  • ブランチ情報ファイル
  • リリース用ブランチ名

ブランチ情報ファイル

{
"tag": "rc",
"parentBranch": "main"
}

こんな形式で生成されます。ファイル名は[選択したタグ名]-[入力したブランチ名(/などは-でescapeされる)].jsonとなります。
例えばタグとしてrcを選び、ブランチ名にrelease/1.1.7を入力したとすると、rc-release-1.1.7.jsonというブランチ情報ファイルが生成されます。
tagstart-prで選択したタグ名ですし、parentBranchstart-prを実行したブランチです。見たままですね。リリース時にこれらの情報を使います。

リリース用ブランチ名

ユーザーが入力したままのブランチ名にはならないことに注意です。
選択したタグと組み合わせて、[入力したブランチ名]([選択したタグ名])になります。
例えばタグとしてrcを選び、ブランチ名にrelease/1.1.7を入力したとすると、release/1.1.7(rc)というブランチ名となります。

push-prコマンド

start-prでリリース用ブランチを作成し、リリースする修正などをcommitしたら、次はpush-prで変更をpushして、PRを作成しましょう。
具体的には以下を行います。

  1. 変更種別を選択(patch,minor,major,(skip))
    1. config.jsonversioningStrategyによって、複数のプロジェクトに対して1つ1つのプロジェクトに対して種別を選択するか、一括で選択するかが変わる
  2. 各プロジェクトのバージョン管理フィールドを更新する
  3. ブランチ情報ファイルにリリースする予定のプロジェクトを記載する
  4. これまでの変更をcommit, pushする
  5. PRがまだ作られていなければPRを作成する

実行画面は以下のような感じです。

version bumpの種別を選択(versioningStrategyがfixed)

version bumpの種別を選択(versioningStrategyがindependent)

PRのbase branchを選択(PRを作成する場合)

push-pr完了

これも特別言及することはありませんが、一応以下には言及しておきます。

  • ブランチ情報ファイルに記載されるリリースする予定のプロジェクトのフィールド

ブランチ情報ファイルに記載されるリリースする予定のプロジェクトのフィールド

{
"tag": "rc",
"parentBranch": "main",
"projectUpdated": {
".": "1.1.7-rc.5"
}
}

こんな感じになります。projectUpdatedというフィールドが追加されます。
オブジェクトで、中にはリリースするprojectのパスとバージョンが載っています。

end-pr

push-prで必要な修正などをpushし終わったら、次はPRをマージしましょう。
具体的には以下を行います。

  1. config.jsonで、現在リリースしているタグに`next`タグが設定されていればそのtagのリリースバージョンを算出する。
  2. そのリリースバージョンに各プロジェクトのバージョン管理フィールドを更新、commit、pushする
  3. ブランチ情報ファイルを削除する
  4. PRをマージする

実行画面は以下のような感じです。

本当にマージしていいか確認

end-pr完了

本当に特別言及することはありません。以上です。

おわりに

長くなりましたが、これさえ読めばcd-toolsについては完璧というくらいにはまとめられたのではないでしょうか。

この記事でcd-toolsいいなと少しでも思った方がいれば嬉しいです。

ぜひcd-toolsを使ってみてください!

Share


xのアイコンfacebookのアイコンこのエントリーをはてなブックマークに追加

Author


著者

高角 樹

ソフトウェアエンジニア

株式会社Digeon3年目の大学生エンジニア。フルスタックに業務を担当。


共に働く仲間を募集しています

Digeonは意欲のある方を積極的に採用しています。
神戸発のAIベンチャーでAIの社会実装を一緒に進めませんか?

採用ページはこちら
logo
Engineering Portal
ディジョンのエンジニア情報ポータルサイト
©株式会社Digeon All Rights Reserved.