Skip to content

Commit 684ed83

Browse files
authored
feat: minor version strategy rules (#132)
1 parent e9c1fc6 commit 684ed83

File tree

17 files changed

+241
-12
lines changed

17 files changed

+241
-12
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Minor version bump
2+
description: Verifies branch is ready to merge before minor version bump
3+
runs:
4+
using: composite
5+
steps:
6+
- name: Checkout repository
7+
uses: actions/checkout@v4
8+
9+
- name: Configure Gradle
10+
uses: awslabs/aws-kotlin-repo-tools/.github/actions/configure-gradle@main
11+
12+
- name: Verify minor version bump
13+
shell: bash
14+
run: ./gradlew verifyMinorVersionBump

build-plugins/build-support/src/main/kotlin/aws/sdk/kotlin/gradle/dsl/CodeStyle.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ fun Project.configureLinting(lintPaths: List<String>) {
4040
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.SHADOWED))
4141
}
4242
}
43-
ktlint("aws.sdk.kotlin.gradle:ktlint-rules:$repoToolsVersion")
43+
ktlint("aws.sdk.kotlin.gradle:style-rules:$repoToolsVersion")
4444
}
4545

4646
// add the buildscript classpath which should pick up our custom ktlint-rules (via runtimeOnly dep on this plugin)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package aws.sdk.kotlin.gradle.dsl
7+
8+
import aws.sdk.kotlin.gradle.util.verifyRootProject
9+
import org.gradle.api.Project
10+
import org.gradle.api.artifacts.VersionCatalogsExtension
11+
import org.gradle.api.attributes.Bundling
12+
import org.gradle.api.tasks.JavaExec
13+
import org.gradle.kotlin.dsl.*
14+
import org.gradle.kotlin.dsl.getByType
15+
import org.gradle.language.base.plugins.LifecycleBasePlugin
16+
17+
/**
18+
* Configures Gradle task for minor-version-bump-specific Ktlint rules.
19+
*/
20+
fun Project.configureMinorVersionStrategyRules(lintPaths: List<String>) {
21+
verifyRootProject { "Task configuration is expected to be configured on the root project" }
22+
23+
val ktlintVersion = object {} // Can't use Project.javaClass because that's using the Gradle classloader
24+
.javaClass
25+
.getResource("ktlint-version.txt")
26+
?.readText()
27+
?: error("Missing ktlint-version.txt")
28+
29+
val repoToolsVersion = extensions
30+
.getByType<VersionCatalogsExtension>()
31+
.named("libs")
32+
.findVersion("aws-kotlin-repo-tools-version")
33+
.get()
34+
.requiredVersion
35+
36+
val minorVersionBumpKtlint by configurations.creating
37+
38+
dependencies {
39+
minorVersionBumpKtlint("com.pinterest.ktlint:ktlint-cli:$ktlintVersion") {
40+
attributes {
41+
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.SHADOWED))
42+
}
43+
}
44+
minorVersionBumpKtlint("aws.sdk.kotlin.gradle:minor-version-rules:$repoToolsVersion")
45+
}
46+
47+
tasks.register<JavaExec>("verifyMinorVersionBump") {
48+
group = LifecycleBasePlugin.VERIFICATION_GROUP
49+
description = "Check minor version bump rules"
50+
classpath = minorVersionBumpKtlint
51+
mainClass.set("com.pinterest.ktlint.Main")
52+
args = lintPaths
53+
}
54+
}

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ dependencies {
5959
}
6060
}
6161

62-
ktlint(project(":ktlint-rules"))
62+
ktlint(project(":ktlint:style-rules"))
6363
}
6464

6565
val lintPaths = listOf(

gradle/libs.versions.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ aws-sdk-cloudwatch = { module = "aws.sdk.kotlin:cloudwatch", version.ref = "aws-
1515
aws-sdk-s3 = { module = "aws.sdk.kotlin:s3", version.ref = "aws-sdk-version" }
1616
ktlint-cli = { module = "com.pinterest.ktlint:ktlint-cli", version.ref = "ktlint" }
1717
ktlint-cli-ruleset-core = { module = "com.pinterest.ktlint:ktlint-cli-ruleset-core", version.ref = "ktlint" }
18-
ktlint-test = {module = "com.pinterest.ktlint:ktlint-test", version.ref = "ktlint" }
1918
nexus-publish-plugin = { module = "io.github.gradle-nexus:publish-plugin", version.ref = "nexus-plugin-version" }
2019
jreleaser-plugin = { module = "org.jreleaser:jreleaser-gradle-plugin", version.ref = "jreleaser-plugin-version" }
2120
smithy-model = { module = "software.amazon.smithy:smithy-model", version.ref = "smithy-version" }
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
6+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
7+
8+
description = "Lint rules for minor version bumps"
9+
10+
plugins {
11+
`maven-publish`
12+
kotlin("jvm")
13+
}
14+
15+
kotlin {
16+
sourceSets {
17+
main {
18+
dependencies {
19+
implementation(libs.ktlint.cli.ruleset.core)
20+
}
21+
}
22+
23+
test {
24+
dependencies {
25+
implementation(kotlin("test"))
26+
}
27+
}
28+
}
29+
}
30+
31+
tasks.test {
32+
testLogging {
33+
events("passed", "skipped", "failed")
34+
showStandardStreams = true
35+
showStackTraces = true
36+
showExceptions = true
37+
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
38+
}
39+
}
40+
41+
tasks.withType<KotlinCompile> {
42+
compilerOptions {
43+
jvmTarget.set(JvmTarget.JVM_1_8)
44+
freeCompilerArgs.add("-Xjdk-release=1.8")
45+
}
46+
}
47+
48+
tasks.withType<JavaCompile> {
49+
sourceCompatibility = JavaVersion.VERSION_1_8.toString()
50+
targetCompatibility = JavaVersion.VERSION_1_8.toString()
51+
}
52+
53+
publishing {
54+
publications {
55+
create<MavenPublication>("ktlintRules") {
56+
from(components["kotlin"])
57+
}
58+
}
59+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package software.aws.ktlint.rules
7+
8+
import com.pinterest.ktlint.rule.engine.core.api.ElementType
9+
import com.pinterest.ktlint.rule.engine.core.api.Rule
10+
import com.pinterest.ktlint.rule.engine.core.api.RuleId
11+
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
12+
import java.io.File
13+
import java.util.Properties
14+
15+
/**
16+
* Matches @DeprecatedUntilVersion with either named args (major=x, minor=y) or positional args (x, y)
17+
*/
18+
internal fun deprecatedUntilVersionRegex(major: Int, minor: Int): Regex =
19+
Regex(
20+
"""@DeprecatedUntilVersion\s*\(\s*(?:major\s*=\s*$major\s*,\s*minor\s*=\s*$minor\s*|\s*$major\s*,\s*$minor\s*)\s*\)""",
21+
)
22+
23+
/**
24+
* Creates a ktlint rule that detects APIs annotated with @DeprecatedUntilVersion for the upcoming minor version.
25+
*/
26+
class DeprecatedApiRule : Rule(RuleId("minor-version-strategy-rules:deprecated-apis"), About()) {
27+
override fun beforeVisitChildNodes(
28+
node: ASTNode,
29+
autoCorrect: Boolean,
30+
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit,
31+
) {
32+
if (node.elementType == ElementType.ANNOTATION_ENTRY) {
33+
val gradleProperties = Properties().apply {
34+
load(File("gradle.properties").inputStream())
35+
}
36+
37+
val sdkVersion = gradleProperties.getProperty("sdkVersion").split(".")
38+
val majorVersion = sdkVersion[0].toInt()
39+
val minorVersion = sdkVersion[1].toInt()
40+
41+
val regex = deprecatedUntilVersionRegex(majorVersion, minorVersion + 1)
42+
if (regex.containsMatchIn(node.text)) {
43+
emit(
44+
node.startOffset,
45+
"The deprecated API is scheduled for removal, please remove it before releasing the next minor version.",
46+
true,
47+
)
48+
}
49+
}
50+
}
51+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package software.aws.ktlint.rules
6+
7+
import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3
8+
import com.pinterest.ktlint.rule.engine.core.api.RuleProvider
9+
import com.pinterest.ktlint.rule.engine.core.api.RuleSetId
10+
11+
class MinorVersionRuleSetProvider : RuleSetProviderV3(RuleSetId("minor-version-strategy-rules")) {
12+
override fun getRuleProviders() = setOf(
13+
RuleProvider { DeprecatedApiRule() },
14+
)
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
software.aws.ktlint.rules.MinorVersionRuleSetProvider
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package software.aws.ktlint.rules
7+
8+
import kotlin.test.Test
9+
import kotlin.test.assertFalse
10+
import kotlin.test.assertTrue
11+
12+
class DeprecatedApiRuleTest {
13+
fun runRegexTestCases(minor: Int, major: Int) {
14+
val regex = deprecatedUntilVersionRegex(major, minor)
15+
16+
assertTrue(regex.containsMatchIn("@DeprecatedUntilVersion($major,$minor)"))
17+
assertTrue(regex.containsMatchIn("@DeprecatedUntilVersion($major,$minor )"))
18+
assertTrue(regex.containsMatchIn("@DeprecatedUntilVersion($major, $minor)"))
19+
assertTrue(regex.containsMatchIn("@DeprecatedUntilVersion($major ,$minor)"))
20+
assertTrue(regex.containsMatchIn("@DeprecatedUntilVersion( $major,$minor)"))
21+
assertTrue(regex.containsMatchIn("@DeprecatedUntilVersion( $major , $minor )"))
22+
assertTrue(regex.containsMatchIn("@DeprecatedUntilVersion(major=$major,minor=$minor)"))
23+
assertTrue(regex.containsMatchIn("@DeprecatedUntilVersion( major= $major , minor= $minor )"))
24+
25+
assertFalse(regex.containsMatchIn("@DeprecatedUntilVersion"))
26+
assertFalse(regex.containsMatchIn("@DeprecatedUntilVersion()"))
27+
assertFalse(regex.containsMatchIn("@DeprecatedUntilVersion($minor,$minor)"))
28+
assertFalse(regex.containsMatchIn("@DeprecatedUntilVersion($major,$major)"))
29+
assertFalse(regex.containsMatchIn("@DeprecatedUntilVersion($minor,$major)"))
30+
}
31+
32+
@Test
33+
fun testRegex() {
34+
runRegexTestCases(0, 1)
35+
runRegexTestCases(1, 70)
36+
runRegexTestCases(100, 1_000_000)
37+
}
38+
}

0 commit comments

Comments
 (0)