Skip to content

Commit a351b55

Browse files
committed
chore(library): add Detekt rule for forbidding enums
1 parent 3906965 commit a351b55

7 files changed

Lines changed: 111 additions & 0 deletions

File tree

github-workflows-kt/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ dependencies {
3535
testImplementation(kotlin("compiler"))
3636
testImplementation(kotlin("reflect"))
3737
testImplementation(projects.testUtils)
38+
detektPlugins(project(":github-workflows-kt:detekt-rules"))
3839

3940
// GitHub action bindings
4041
testImplementation("actions:checkout:v4")
@@ -85,3 +86,7 @@ tasks.withType<FormatTask> {
8586
dokka {
8687
moduleName.set("github-workflows-kt")
8788
}
89+
90+
apiValidation {
91+
ignoredProjects.addAll(listOf("detekt-rules"))
92+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
plugins {
2+
buildsrc.convention.`kotlin-jvm`
3+
}
4+
5+
dependencies {
6+
compileOnly("io.gitlab.arturbosch.detekt:detekt-api:1.23.8")
7+
8+
testImplementation("io.gitlab.arturbosch.detekt:detekt-test:1.23.8")
9+
testImplementation("org.jetbrains.kotlin:kotlin-compiler-embeddable")
10+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package io.github.typesafegithub.workflows.detekt.rules
2+
3+
import io.gitlab.arturbosch.detekt.api.CodeSmell
4+
import io.gitlab.arturbosch.detekt.api.Config
5+
import io.gitlab.arturbosch.detekt.api.Debt
6+
import io.gitlab.arturbosch.detekt.api.Entity
7+
import io.gitlab.arturbosch.detekt.api.Issue
8+
import io.gitlab.arturbosch.detekt.api.Rule
9+
import io.gitlab.arturbosch.detekt.api.Severity
10+
import org.jetbrains.kotlin.psi.KtClass
11+
import org.jetbrains.kotlin.psi.KtClassOrObject
12+
13+
public class NoEnumRule(
14+
config: Config,
15+
) : Rule(config) {
16+
override val issue: Issue =
17+
Issue(
18+
id = "NoEnum",
19+
severity = Severity.Style,
20+
description =
21+
"Enums are forbidden. Use sealed interfaces/classes instead. " +
22+
"GitHub Actions' API may require or return values that weren't anticipated when this library was published. " +
23+
"Sealed interfaces/classes allow adding a class that accepts an arbitrary value as an escape hatch.",
24+
debt = Debt.FIVE_MINS,
25+
)
26+
27+
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
28+
if (classOrObject is KtClass && classOrObject.isEnum()) {
29+
report(
30+
CodeSmell(
31+
issue = issue,
32+
entity = Entity.from(classOrObject),
33+
message =
34+
"Enum class '${classOrObject.name}' is forbidden. Use a sealed interface/class instead. " +
35+
"GitHub Actions' API may require or return values that weren't anticipated when this library was published. " +
36+
"Sealed interfaces/classes allow adding a class that accepts an arbitrary value as an escape hatch.",
37+
),
38+
)
39+
}
40+
super.visitClassOrObject(classOrObject)
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.github.typesafegithub.workflows.detekt.rules
2+
3+
import io.gitlab.arturbosch.detekt.api.Config
4+
import io.gitlab.arturbosch.detekt.api.RuleSet
5+
import io.gitlab.arturbosch.detekt.api.RuleSetProvider
6+
7+
public class NoEnumRuleSetProvider : RuleSetProvider {
8+
override val ruleSetId: String = "custom-style"
9+
10+
override fun instance(config: Config): RuleSet =
11+
RuleSet(
12+
id = ruleSetId,
13+
rules = listOf(NoEnumRule(config)),
14+
)
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.github.typesafegithub.workflows.detekt.rules.NoEnumRuleSetProvider
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package io.github.typesafegithub.workflows.detekt.rules
2+
3+
import io.gitlab.arturbosch.detekt.test.TestConfig
4+
import io.gitlab.arturbosch.detekt.test.compileAndLint
5+
import io.kotest.core.spec.style.FunSpec
6+
import io.kotest.matchers.shouldBe
7+
8+
class NoEnumRuleTest :
9+
FunSpec({
10+
test("reports enum class") {
11+
val code = """
12+
enum class Color { RED, GREEN, BLUE }
13+
"""
14+
val findings = NoEnumRule(TestConfig()).compileAndLint(code)
15+
findings.size shouldBe 1
16+
}
17+
18+
test("does not report sealed class") {
19+
val code = """
20+
sealed class Color {
21+
data object RED : Color()
22+
data object GREEN : Color()
23+
data object BLUE : Color()
24+
}
25+
"""
26+
val findings = NoEnumRule(TestConfig()).compileAndLint(code)
27+
findings.size shouldBe 0
28+
}
29+
30+
test("does not report regular class") {
31+
val code = """
32+
class Foo
33+
"""
34+
val findings = NoEnumRule(TestConfig()).compileAndLint(code)
35+
findings.size shouldBe 0
36+
}
37+
})

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ include(
1111
"shared-internal",
1212
"code-generator",
1313
"test-utils",
14+
"github-workflows-kt:detekt-rules",
1415
)
1516

1617
plugins {

0 commit comments

Comments
 (0)