Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# 依存の version updates(マニフェスト = version catalog / ビルドスクリプト / ワークフロー由来)。
# Kotlin の更新 PR は catalog 経由で配布版 <KotlinVersion>-<自版> の導出まで自動で追随し、CI が検証する。
# README / docs / .idea 中の現行バージョン表記はマニフェスト更新では変わらないため、
# CI(ルートの checkVersionMentions)が乖離を検出したら、./gradlew syncVersionMentions の
# 実行結果を更新 PR へコミットして追随させる。
# 解決済み依存グラフ(推移依存含む)に対する alerts は build.yml の dependency-submission ジョブが補完する
#
# npm(kotlin-js-store/yarn.lock)は version updates の対象に含めない。lockfile は KGP が
Expand Down
29 changes: 28 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ name: build
# 本ファイル自身は列挙し、この CI 定義の変更では起動させる。
# .gitattributes は LF 正規化経由でフィクスチャの挙動に影響しうるため入力に含める
# (.editorconfig はビルドが読まないため列挙しない)。
# 列挙パス内でもビルドに影響しない種別(.md)は個別に除外する。
# 列挙パス内でもビルドに影響しない種別(.md)は個別に除外する。ただし現行バージョン表記の検証は
# README / docs を入力に持つため、PR では changes ジョブの専用フィルタで version-mentions ジョブを起動する。
# .txt は TestKit フィクスチャの入力種別のため、除外の対象にしてはならない。
#
# PR では起動条件に paths を置かない。paths でスキップされたワークフローのチェックは pending のまま残り、
Expand Down Expand Up @@ -60,6 +61,9 @@ jobs:
pull-requests: read
outputs:
build: ${{ github.event_name != 'pull_request' || steps.filter.outputs.build }}
# push はビルド入力の変更でしか起動せず、そちらは build ジョブの check が版表記検証を含むため、
# このフィルタは PR のみ評価する(push では常に false = ジョブをスキップ)
versionMentions: ${{ github.event_name == 'pull_request' && steps.filter.outputs.versionMentions }}
steps:
- uses: dorny/paths-filter@4711b7a31b4aa89103d8c6ffab2e3b8e7b6381c7 # master(v4.0.2 + some-with-excludes)
id: filter
Expand All @@ -81,6 +85,10 @@ jobs:
- ".gitattributes"
- ".github/workflows/build.yml"
- "!**/*.md"
versionMentions:
- "README.md"
- "docs/**"
- ".idea/kotlinc.xml"

build:
needs: changes
Expand Down Expand Up @@ -211,6 +219,24 @@ jobs:
key: konan-${{ runner.os }}-${{ hashFiles('gradle/libs.versions.toml') }}
- run: ./gradlew.bat -p integration-test :mpp-producer:mingwX64Test

# 現行バージョン表記と単一情報源の一致検証(ルートの checkVersionMentions。乖離時は
# ./gradlew syncVersionMentions の結果をコミットして追随する)。ビルド入力を変更する PR
# (Dependabot の版更新を含む)は build ジョブの check が同じ検証を含むため、このジョブは
# ビルド入力の allowlist から除外されている .md など、表記側だけを変更する PR を拾う
version-mentions:
needs: changes
if: needs.changes.outputs.versionMentions == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
with:
distribution: temurin
java-version: 17
- uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
- run: ./gradlew :checkVersionMentions

# 必須チェックはこの 1 本へ集約する(docs/チェックリスト.md §8 R-6)。
# matrix を含む個別のジョブ名を必須チェックとして列挙すると、shard 数の変更で保護設定側が
# 存在しない名前を要求し、マージ不能または無防備のどちらかへ静かに倒れるため。
Expand All @@ -225,6 +251,7 @@ jobs:
- integration-maven
- build-macos
- native-windows
- version-mentions
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
Expand Down
90 changes: 90 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,96 @@ allprojects {
version = enumizerFullVersion
}

// README / docs / .idea 中の「現行バージョン」表記を単一情報源(Kotlin / Maven = version catalog・
// 自版 = enumizerVersion・Gradle = wrapper properties)から導出した値へ揃える。
// Dependabot 等の版更新はマニフェストしか書き換えず表記が置き去りになるため、
// checkVersionMentions(check へ紐付け。CI では version-mentions ジョブ)が乖離を検出し、
// syncVersionMentions が書き換える。
// 置換は「現行版を指す表記」に限る。サポート下限("Kotlin 2.4" / "Gradle 9+" / "Maven 3.9+")・
// 特定版に固定した実測エビデンス(設計00 の "Kotlin 2.4.0 実測")・別版での版形式の例示は
// 書き換えてはならないため、対象ファイルの許可リストと文脈付きパターンの両方で絞る
fun minorOf(version: String) = version.split(".").take(2).joinToString(".")

val kotlinCurrent = libs.versions.kotlin.get()
val mavenCurrent = libs.versions.maven.get()
val enumizerReleaseVersion =
providers.gradleProperty("enumizerVersion").get().removeSuffix("-SNAPSHOT")
val gradleWrapperVersion =
providers
.fileContents(layout.projectDirectory.file("gradle/wrapper/gradle-wrapper.properties"))
.asText
.map { checkNotNull(Regex("""/gradle-(\d+(?:\.\d+)+)-""").find(it)).groupValues[1] }
.get()

// 3 成分(パッチ付き)と 2 成分(マイナーまで)の表記は、それぞれの粒度を保ったまま現行値へ置換する
val versionMentionRules: List<Pair<Regex, String>> =
listOf(
// 配布版のフル形式 <KotlinVersion>-<自版>(README のセットアップ例・版形式の現行例)
Regex("""(?<![\d.])\d+\.\d+\.\d+-\d+\.\d+\.\d+(?![\d.-])""") to
"$kotlinCurrent-$enumizerReleaseVersion",
// README のセットアップ例が指定する KGP 版
Regex("""(?<=kotlin\("(?:multiplatform|jvm)"\) version ")\d+\.\d+\.\d+(?=")""") to
kotlinCurrent,
// .idea/kotlinc.xml(IDE が同期時に書き戻す Kotlin 版。PR 側で揃え、同期後の作業ツリー差分を防ぐ)
Regex("""(?<=name="version" value=")\d+\.\d+\.\d+(?=")""") to kotlinCurrent,
// 文中の現行 Kotlin 版(3 成分のみ。2 成分のサポート下限 "Kotlin 2.4" には一致しない)
Regex("""(?<=Kotlin )\d+\.\d+\.\d+(?![\d.-])""") to kotlinCurrent,
// 対応マイナーの表記(README の互換表の "2.4.x")
Regex("""\d+\.\d+\.x""") to "${minorOf(kotlinCurrent)}.x",
// Gradle / Maven。下限表記("9+" / "3.9+")は後置の + により対象外となる
Regex("""(?<=Gradle )\d+\.\d+\.\d+(?![\d.+])""") to gradleWrapperVersion,
Regex("""(?<=Gradle )\d+\.\d+(?![\d.+])""") to minorOf(gradleWrapperVersion),
Regex("""(?<=Maven )\d+\.\d+\.\d+(?![\d.+])""") to mavenCurrent,
Regex("""(?<=Maven )\d+\.\d+(?![\d.+])""") to minorOf(mavenCurrent),
)

// 対象箇所: README(セットアップ例・互換表・検証済みビルド環境)・概要 §7(版形式の現行例)・
// 実装ノート / テスト戦略 / エッジケースへの対応方針(実測・テスト環境の宣言)・kotlinc.xml。
// 現行版への言及を持つ資料を増やした場合はここへ追加する
val versionMentionTargets =
listOf(
"README.md",
"docs/概要.md",
"docs/実装ノート.md",
"docs/test/テスト戦略.md",
"docs/エッジケースへの対応方針.md",
".idea/kotlinc.xml",
)
.map { it to layout.projectDirectory.file(it).asFile }

tasks.register("syncVersionMentions") {
val targets = versionMentionTargets
val rules = versionMentionRules
doLast {
targets.forEach { (_, file) ->
val current = file.readText()
val synced = rules.fold(current) { text, (regex, value) -> regex.replace(text, value) }
if (synced != current) file.writeText(synced)
}
}
}

val checkVersionMentions =
tasks.register("checkVersionMentions") {
val targets = versionMentionTargets
val rules = versionMentionRules
doLast {
val stale = targets.filter { (_, file) ->
val current = file.readText()
rules.fold(current) { text, (regex, value) -> regex.replace(text, value) } !=
current
}
if (stale.isNotEmpty()) {
throw GradleException(
"現行バージョンとズレた表記があります: ${stale.joinToString { it.first }}。" +
"./gradlew syncVersionMentions で追随してください"
)
}
}
}

tasks.named("check") { dependsOn(checkVersionMentions) }

// gradle.properties の kotlin.code.style=official に合わせ、ktfmt も Kotlin 公式スタイル
// (ブロック・継続ともインデント 4、末尾カンマ付与)で揃える
allprojects {
Expand Down