Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@ smithy-version = "1.60.2"
smithy-gradle-plugin-version = "1.3.0"
junit-version = "5.10.1"
coroutines-version = "1.10.2"
slf4j = "2.0.17"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

naming: slf4j-version


[libraries]
aws-sdk-cloudwatch = { module = "aws.sdk.kotlin:cloudwatch", version.ref = "aws-sdk-version" }
aws-sdk-s3 = { module = "aws.sdk.kotlin:s3", version.ref = "aws-sdk-version" }
ktlint-cli = { module = "com.pinterest.ktlint:ktlint-cli", version.ref = "ktlint" }
ktlint-cli-ruleset-core = { module = "com.pinterest.ktlint:ktlint-cli-ruleset-core", version.ref = "ktlint" }
ktlint-rule-engine = { module = "com.pinterest.ktlint:ktlint-rule-engine", version.ref = "ktlint" }
nexus-publish-plugin = { module = "io.github.gradle-nexus:publish-plugin", version.ref = "nexus-plugin-version" }
jreleaser-plugin = { module = "org.jreleaser:jreleaser-gradle-plugin", version.ref = "jreleaser-plugin-version" }
smithy-model = { module = "software.amazon.smithy:smithy-model", version.ref = "smithy-version" }
smithy-gradle-base-plugin = { module = "software.amazon.smithy.gradle:smithy-base", version.ref = "smithy-gradle-plugin-version" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-version" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines-version" }
slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" }

[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-version" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal fun deprecatedUntilVersionRegex(major: Int, minor: Int): Regex =
/**
* Creates a ktlint rule that detects APIs annotated with @DeprecatedUntilVersion for the upcoming minor version.
*/
class DeprecatedApiRule : Rule(RuleId("minor-version-strategy-rules:deprecated-apis"), About()) {
class DeprecatedApiRule : Rule(RuleId("$RULE_SET:deprecated-apis"), About()) {
override fun beforeVisitChildNodes(
node: ASTNode,
autoCorrect: Boolean,
Expand All @@ -43,7 +43,7 @@ class DeprecatedApiRule : Rule(RuleId("minor-version-strategy-rules:deprecated-a
emit(
node.startOffset,
"The deprecated API is scheduled for removal, please remove it before releasing the next minor version.",
true,
false,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3
import com.pinterest.ktlint.rule.engine.core.api.RuleProvider
import com.pinterest.ktlint.rule.engine.core.api.RuleSetId

class MinorVersionRuleSetProvider : RuleSetProviderV3(RuleSetId("minor-version-strategy-rules")) {
internal const val RULE_SET = "aws-kotlin-repo-tools-rules"

class MinorVersionRuleSetProvider : RuleSetProviderV3(RuleSetId(RULE_SET)) {
override fun getRuleProviders() = setOf(
RuleProvider { DeprecatedApiRule() },
)
Expand Down
17 changes: 17 additions & 0 deletions ktlint/style-rules/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ kotlin {
implementation(libs.ktlint.cli.ruleset.core)
}
}
test {
dependencies {
implementation(kotlin("test"))
implementation(libs.ktlint.rule.engine)
implementation(libs.slf4j.simple) // Required by ktlint rule engine tests
}
}
}
}

tasks.test {
testLogging {
events("passed", "skipped", "failed")
showStandardStreams = true
showStackTraces = true
showExceptions = true
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiCommentImpl
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType

class CopyrightHeaderRule : Rule(RuleId("aws-kotlin-repo-tools-rules:copyright-header"), About()) {
class CopyrightHeaderRule : Rule(RuleId("$RULE_SET:copyright-header"), About()) {
companion object {
private val header = """
/*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.aws.ktlint.rules

import com.pinterest.ktlint.rule.engine.core.api.ElementType
import com.pinterest.ktlint.rule.engine.core.api.Rule
import com.pinterest.ktlint.rule.engine.core.api.RuleId
import org.jetbrains.kotlin.com.intellij.lang.ASTNode

/**
* Creates a ktlint rule that forces APIs annotated with @DeprecatedUntilVersion to also be annotated with @Deprecated.
*/
class DeprecatedUntilVersionRule : Rule(RuleId("$RULE_SET:deprecated-until-version"), About()) {
override fun beforeVisitChildNodes(
node: ASTNode,
autoCorrect: Boolean,
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit,
) {
if (node.elementType == ElementType.MODIFIER_LIST) {
val annotations = node.getChildren(null).filter { it.elementType == ElementType.ANNOTATION_ENTRY }
val deprecated = annotations.any { it.text.startsWith("@Deprecated") }
val deprecatedUntilVersion = annotations.any { it.text.startsWith("@DeprecatedUntilVersion") }

if (deprecatedUntilVersion && !deprecated) {
emit(
node.startOffset,
"APIs annotated with @DeprecatedUntilVersion must also be annotated with @Deprecated",
false,
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtReturnExpression

class ExpressionBodyRule : Rule(RuleId("aws-kotlin-repo-tools-rules:expression-body"), About()) {
class ExpressionBodyRule : Rule(RuleId("$RULE_SET:expression-body"), About()) {
override fun beforeVisitChildNodes(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import com.pinterest.ktlint.rule.engine.core.api.Rule
import com.pinterest.ktlint.rule.engine.core.api.RuleId
import org.jetbrains.kotlin.com.intellij.lang.ASTNode

class MultilineIfElseBlockRule : Rule(RuleId("aws-kotlin-repo-tools-rules:multiline-if-else-block"), About()) {
class MultilineIfElseBlockRule : Rule(RuleId("$RULE_SET:multiline-if-else-block"), About()) {
override fun beforeVisitChildNodes(
node: ASTNode,
autoCorrect: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3
import com.pinterest.ktlint.rule.engine.core.api.RuleProvider
import com.pinterest.ktlint.rule.engine.core.api.RuleSetId

class StyleRuleSetProvider : RuleSetProviderV3(RuleSetId("aws-kotlin-repo-tools-rules")) {
internal const val RULE_SET = "aws-kotlin-repo-tools-rules"

class StyleRuleSetProvider : RuleSetProviderV3(RuleSetId(RULE_SET)) {
override fun getRuleProviders() = setOf(
RuleProvider { CopyrightHeaderRule() },
RuleProvider { ExpressionBodyRule() },
RuleProvider { MultilineIfElseBlockRule() },
RuleProvider { DeprecatedUntilVersionRule() },
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.aws.ktlint.rules

import com.pinterest.ktlint.rule.engine.api.Code
import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine
import com.pinterest.ktlint.rule.engine.core.api.RuleProvider
import kotlin.test.Test
import kotlin.test.assertEquals

class DeprecatedUntilVersionRuleTest {
val ruleEngine = KtLintRuleEngine(
setOf(
RuleProvider { DeprecatedUntilVersionRule() },
),
)

private fun hasLintingErrors(codeSnippet: String): Boolean {
val code = Code.fromSnippet(codeSnippet)
var hasErrors = false
ruleEngine.lint(code) {
// Error callback function
hasErrors = true
}
return hasErrors
}

@Test
fun testRule() {
assertEquals(
false,
hasLintingErrors(
"""
@DeprecatedUntilVersion(1, 2)
@Deprecated
class Foo {}
""".trimIndent(),
),
)

assertEquals(
false,
hasLintingErrors(
"""
@Deprecated
@DeprecatedUntilVersion(1, 2)
class Foo {}
""".trimIndent(),
),
)

assertEquals(
false,
hasLintingErrors(
"""
@Deprecated
class Foo {}
""".trimIndent(),
),
)

assertEquals(
true,
hasLintingErrors(
"""
@DeprecatedUntilVersion(1, 2)
class Foo {}
""".trimIndent(),
),
)

assertEquals(
true,
hasLintingErrors(
"""
@DeprecatedUntilVersion(1, 2)
class Foo {}

@Deprecated
class Bar {}
""".trimIndent(),
),
)

assertEquals(
true,
hasLintingErrors(
"""
@DeprecatedUntilVersion(1, 2)
class Foo {}

@DeprecatedUntilVersion(1, 2)
class Bar {}
""".trimIndent(),
),
)
}
}
Loading