Skip to content

Commit 193be16

Browse files
committed
feat: deprecatedUntilVersion ktlint rule
1 parent 9677f96 commit 193be16

File tree

10 files changed

+149
-7
lines changed

10 files changed

+149
-7
lines changed

gradle/libs.versions.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,21 @@ smithy-version = "1.60.2"
99
smithy-gradle-plugin-version = "1.3.0"
1010
junit-version = "5.10.1"
1111
coroutines-version = "1.10.2"
12+
slf4j = "2.0.17"
1213

1314
[libraries]
1415
aws-sdk-cloudwatch = { module = "aws.sdk.kotlin:cloudwatch", version.ref = "aws-sdk-version" }
1516
aws-sdk-s3 = { module = "aws.sdk.kotlin:s3", version.ref = "aws-sdk-version" }
1617
ktlint-cli = { module = "com.pinterest.ktlint:ktlint-cli", version.ref = "ktlint" }
1718
ktlint-cli-ruleset-core = { module = "com.pinterest.ktlint:ktlint-cli-ruleset-core", version.ref = "ktlint" }
19+
ktlint-rule-engine = { module = "com.pinterest.ktlint:ktlint-rule-engine", version.ref = "ktlint" }
1820
nexus-publish-plugin = { module = "io.github.gradle-nexus:publish-plugin", version.ref = "nexus-plugin-version" }
1921
jreleaser-plugin = { module = "org.jreleaser:jreleaser-gradle-plugin", version.ref = "jreleaser-plugin-version" }
2022
smithy-model = { module = "software.amazon.smithy:smithy-model", version.ref = "smithy-version" }
2123
smithy-gradle-base-plugin = { module = "software.amazon.smithy.gradle:smithy-base", version.ref = "smithy-gradle-plugin-version" }
2224
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-version" }
2325
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines-version" }
26+
slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" }
2427

2528
[plugins]
2629
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-version" }

ktlint/minor-version-rules/src/main/kotlin/software/aws/ktlint/rules/DeprecatedApiRule.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ internal fun deprecatedUntilVersionRegex(major: Int, minor: Int): Regex =
2323
/**
2424
* Creates a ktlint rule that detects APIs annotated with @DeprecatedUntilVersion for the upcoming minor version.
2525
*/
26-
class DeprecatedApiRule : Rule(RuleId("minor-version-strategy-rules:deprecated-apis"), About()) {
26+
class DeprecatedApiRule : Rule(RuleId("$ruleSetId:deprecated-apis"), About()) {
2727
override fun beforeVisitChildNodes(
2828
node: ASTNode,
2929
autoCorrect: Boolean,
@@ -43,7 +43,7 @@ class DeprecatedApiRule : Rule(RuleId("minor-version-strategy-rules:deprecated-a
4343
emit(
4444
node.startOffset,
4545
"The deprecated API is scheduled for removal, please remove it before releasing the next minor version.",
46-
true,
46+
false,
4747
)
4848
}
4949
}

ktlint/minor-version-rules/src/main/kotlin/software/aws/ktlint/rules/MinorVersionRuleSetProvider.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3
88
import com.pinterest.ktlint.rule.engine.core.api.RuleProvider
99
import com.pinterest.ktlint.rule.engine.core.api.RuleSetId
1010

11-
class MinorVersionRuleSetProvider : RuleSetProviderV3(RuleSetId("minor-version-strategy-rules")) {
11+
internal const val ruleSetId = "aws-kotlin-repo-tools-rules"
12+
13+
class MinorVersionRuleSetProvider : RuleSetProviderV3(RuleSetId(ruleSetId)) {
1214
override fun getRuleProviders() = setOf(
1315
RuleProvider { DeprecatedApiRule() },
1416
)

ktlint/style-rules/build.gradle.kts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,23 @@ kotlin {
1919
implementation(libs.ktlint.cli.ruleset.core)
2020
}
2121
}
22+
test {
23+
dependencies {
24+
implementation(kotlin("test"))
25+
implementation(libs.ktlint.rule.engine)
26+
implementation(libs.slf4j.simple) // Required by ktlint rule engine tests
27+
}
28+
}
29+
}
30+
}
31+
32+
tasks.test {
33+
testLogging {
34+
events("passed", "skipped", "failed")
35+
showStandardStreams = true
36+
showStackTraces = true
37+
showExceptions = true
38+
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
2239
}
2340
}
2441

ktlint/style-rules/src/main/kotlin/software/aws/ktlint/rules/CopyrightHeaderRule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiCommentImpl
1111
import org.jetbrains.kotlin.lexer.KtTokens
1212
import org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType
1313

14-
class CopyrightHeaderRule : Rule(RuleId("aws-kotlin-repo-tools-rules:copyright-header"), About()) {
14+
class CopyrightHeaderRule : Rule(RuleId("$ruleSetId:copyright-header"), About()) {
1515
companion object {
1616
private val header = """
1717
/*
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package software.aws.ktlint.rules
2+
3+
import com.pinterest.ktlint.rule.engine.core.api.ElementType
4+
import com.pinterest.ktlint.rule.engine.core.api.Rule
5+
import com.pinterest.ktlint.rule.engine.core.api.RuleId
6+
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
7+
8+
/**
9+
* Creates a ktlint rule that forces APIs annotated with @DeprecatedUntilVersion to also be annotated with @Deprecated.
10+
*/
11+
class DeprecatedUntilVersionRule : Rule(RuleId("$ruleSetId:deprecated-until-version"), About()) {
12+
override fun beforeVisitChildNodes(
13+
node: ASTNode,
14+
autoCorrect: Boolean,
15+
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit,
16+
) {
17+
if (node.elementType == ElementType.MODIFIER_LIST) {
18+
val annotations = node.getChildren(null).filter { it.elementType == ElementType.ANNOTATION_ENTRY }
19+
val deprecated = annotations.any { it.text == "@Deprecated" }
20+
val deprecatedUntilVersion = annotations.any { it.text.startsWith("@DeprecatedUntilVersion") }
21+
22+
if (deprecatedUntilVersion && !deprecated) {
23+
emit(
24+
node.startOffset,
25+
"APIs annotated with @DeprecatedUntilVersion must also be annotated with @Deprecated",
26+
false,
27+
)
28+
}
29+
}
30+
}
31+
}

ktlint/style-rules/src/main/kotlin/software/aws/ktlint/rules/ExpressionBodyRule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.psi.KtBlockExpression
1111
import org.jetbrains.kotlin.psi.KtNamedFunction
1212
import org.jetbrains.kotlin.psi.KtReturnExpression
1313

14-
class ExpressionBodyRule : Rule(RuleId("aws-kotlin-repo-tools-rules:expression-body"), About()) {
14+
class ExpressionBodyRule : Rule(RuleId("$ruleSetId:expression-body"), About()) {
1515
override fun beforeVisitChildNodes(
1616
node: ASTNode,
1717
autoCorrect: Boolean,

ktlint/style-rules/src/main/kotlin/software/aws/ktlint/rules/MultilineIfElseBlockRule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import com.pinterest.ktlint.rule.engine.core.api.Rule
99
import com.pinterest.ktlint.rule.engine.core.api.RuleId
1010
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
1111

12-
class MultilineIfElseBlockRule : Rule(RuleId("aws-kotlin-repo-tools-rules:multiline-if-else-block"), About()) {
12+
class MultilineIfElseBlockRule : Rule(RuleId("$ruleSetId:multiline-if-else-block"), About()) {
1313
override fun beforeVisitChildNodes(
1414
node: ASTNode,
1515
autoCorrect: Boolean,

ktlint/style-rules/src/main/kotlin/software/aws/ktlint/rules/StyleRuleSetProvider.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3
88
import com.pinterest.ktlint.rule.engine.core.api.RuleProvider
99
import com.pinterest.ktlint.rule.engine.core.api.RuleSetId
1010

11-
class StyleRuleSetProvider : RuleSetProviderV3(RuleSetId("aws-kotlin-repo-tools-rules")) {
11+
internal const val ruleSetId = "aws-kotlin-repo-tools-rules"
12+
13+
class StyleRuleSetProvider : RuleSetProviderV3(RuleSetId(ruleSetId)) {
1214
override fun getRuleProviders() = setOf(
1315
RuleProvider { CopyrightHeaderRule() },
1416
RuleProvider { ExpressionBodyRule() },
1517
RuleProvider { MultilineIfElseBlockRule() },
18+
RuleProvider { DeprecatedUntilVersionRule() },
1619
)
1720
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package software.aws.ktlint.rules
2+
3+
import com.pinterest.ktlint.rule.engine.api.Code
4+
import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine
5+
import com.pinterest.ktlint.rule.engine.core.api.RuleProvider
6+
import kotlin.test.Test
7+
import kotlin.test.assertEquals
8+
9+
class DeprecatedUntilVersionRuleTest {
10+
val ruleEngine = KtLintRuleEngine(
11+
setOf(
12+
RuleProvider { DeprecatedUntilVersionRule() },
13+
),
14+
)
15+
16+
private fun hasLintingErrors(codeSnippet: String): Boolean {
17+
val code = Code.fromSnippet(codeSnippet)
18+
var hasErrors = false
19+
ruleEngine.lint(code) {
20+
// Error callback function
21+
hasErrors = true
22+
}
23+
return hasErrors
24+
}
25+
26+
@Test
27+
fun testRule() {
28+
assertEquals(
29+
false,
30+
hasLintingErrors(
31+
"""
32+
@DeprecatedUntilVersion(1, 2)
33+
@Deprecated
34+
class Foo {}
35+
""".trimIndent(),
36+
)
37+
)
38+
39+
assertEquals(
40+
false,
41+
hasLintingErrors(
42+
"""
43+
@Deprecated
44+
@DeprecatedUntilVersion(1, 2)
45+
class Foo {}
46+
""".trimIndent(),
47+
)
48+
)
49+
50+
assertEquals(
51+
true,
52+
hasLintingErrors(
53+
"""
54+
@DeprecatedUntilVersion(1, 2)
55+
class Foo {}
56+
""".trimIndent(),
57+
)
58+
)
59+
60+
assertEquals(
61+
true,
62+
hasLintingErrors(
63+
"""
64+
@DeprecatedUntilVersion(1, 2)
65+
class Foo {}
66+
67+
@Deprecated
68+
class Bar {}
69+
""".trimIndent(),
70+
)
71+
)
72+
73+
assertEquals(
74+
true,
75+
hasLintingErrors(
76+
"""
77+
@DeprecatedUntilVersion(1, 2)
78+
class Foo {}
79+
80+
@DeprecatedUntilVersion(1, 2)
81+
class Bar {}
82+
""".trimIndent(),
83+
)
84+
)
85+
}
86+
}

0 commit comments

Comments
 (0)