Skip to content

Commit d5c52b5

Browse files
authored
New rules for unified Backbase API specs (#957)
1 parent 1c3651a commit d5c52b5

File tree

7 files changed

+286
-2
lines changed

7 files changed

+286
-2
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ It currently consists of
1414

1515
# Release Notes
1616
BOAT is still under development and subject to change.
17+
## 0.17.53
18+
* Added 2 Lint rules `B007U` and `B009U` for Unified Backbase API specs:
19+
* `B007U` checks whether paths do not contain `client-api`, `service-api` and `integration-api` prefixes. Any prefix is not allowed for Unified Backbase API.
20+
* `B009U` checks whether paths do not contain any version number. Any version number is not allowed for Unified Backbase API.
21+
* These rules are ignored by default, but if you redefine the list of ignored rules in your project, then you need to add these two rules to your list.
1722
## 0.17.52
1823
* Lint rule `B014` fix reference link to component examples
1924
## 0.17.46

boat-maven-plugin/src/main/java/com/backbase/oss/boat/AbstractLintMojo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public abstract class AbstractLintMojo extends InputMavenArtifactMojo {
4040
@Parameter(name = "ignoreRules")
4141
protected String[] ignoreRules = new String[]{"150","219","215","218","166","136","174","235","107","171","224","143",
4242
"151","129","146","147","172","145","115","132","120", "134","183","154","105","104","130","118","110","153",
43-
"101","176","116","M009","H002","M010","H001","M008","S005","S006","S007","M011"};
43+
"101","176","116","M009","H002","M010","H001","M008","S005","S006","S007","M011","B007U","B009U"};
4444

4545
protected List<BoatLintReport> lint() throws MojoExecutionException, MojoFailureException {
4646

boat-maven-plugin/src/test/java/com/backbase/oss/boat/LintMojoTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class LintMojoTests {
2121
@Test
2222
void testFailOnWarningNoWarnings() throws MojoFailureException, MojoExecutionException {
2323
LintMojo lintMojo = new LintMojo();
24-
lintMojo.setIgnoreRules(Arrays.array("219", "105", "104", "151", "134", "115","M0012", "224", "B013", "B014"));
24+
lintMojo.setIgnoreRules(Arrays.array("219", "105", "104", "151", "134", "115","M0012", "224", "B013", "B014", "B007U", "B009U"));
2525
lintMojo.setInput(getFile("/oas-examples/no-lint-warnings.yaml"));
2626
lintMojo.setFailOnWarning(true);
2727
lintMojo.execute();
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.backbase.oss.boat.quay.ruleset
2+
3+
import com.typesafe.config.Config
4+
import org.zalando.zally.rule.api.*
5+
import kotlin.collections.map
6+
import kotlin.collections.orEmpty
7+
8+
@Rule(
9+
ruleSet = BoatRuleSet::class,
10+
id = "B007U",
11+
severity = Severity.MUST,
12+
title = "Unified Backbase API specs do NOT expect any prefix in paths"
13+
)
14+
class NoPrefixPathRule(config: Config) {
15+
16+
private val validPathPrefixes = config
17+
.getStringList("PrefixPathRule.validPathPrefixes")
18+
.toSet()
19+
20+
@Check(Severity.MUST)
21+
fun validate(context: Context): List<Violation> =
22+
23+
context.api.paths.orEmpty()
24+
.map {
25+
val extractParts = it.key.split("/")
26+
val prefix = if (extractParts.size > 1) extractParts[1] else ""
27+
Pair(prefix, it.value)
28+
}
29+
.filter {
30+
validPathPrefixes.contains(it.first)
31+
}
32+
.map {
33+
context.violation("Incorrect path prefix: ${it.first}", it.second)
34+
}
35+
36+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.backbase.oss.boat.quay.ruleset
2+
3+
import io.swagger.v3.oas.models.OpenAPI
4+
import io.swagger.v3.oas.models.PathItem
5+
import org.zalando.zally.rule.api.*
6+
7+
@Rule(
8+
ruleSet = BoatRuleSet::class,
9+
id = "B009U",
10+
severity = Severity.MUST,
11+
title = "Unified Backbase API specs do NOT expect a version prefix in paths"
12+
)
13+
class NoVersionInUriRule {
14+
15+
private val description = "URL should not contain version number"
16+
private val versionRegex = "(.*)v[0-9]+(.*)".toRegex()
17+
18+
@Check(severity = Severity.MUST)
19+
fun validate(context: Context): List<Violation> =
20+
(violatingPaths(context.api))
21+
.map { context.violation(description, it) }
22+
23+
24+
private fun violatingPaths(api: OpenAPI): Collection<PathItem> =
25+
api.paths.orEmpty().entries
26+
.filter { (path, _) -> path.matches(versionRegex) }
27+
.map { (_, pathEntry) -> pathEntry }
28+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package com.backbase.oss.boat.quay.ruleset
2+
3+
import com.backbase.oss.boat.quay.ruleset.test.ZallyAssertions
4+
import org.intellij.lang.annotations.Language
5+
import org.junit.jupiter.api.Test
6+
import org.zalando.zally.core.DefaultContextFactory
7+
import org.zalando.zally.core.rulesConfig
8+
9+
class NoPrefixPathRuleTest {
10+
11+
private val cut = NoPrefixPathRule(rulesConfig)
12+
13+
@Test
14+
fun `correct path prefix`() {
15+
@Language("YAML")
16+
val context = DefaultContextFactory().getOpenApiContext(
17+
"""
18+
openapi: 3.0.3
19+
info:
20+
title: Thing API
21+
version: 1.0.0
22+
paths:
23+
/foo:
24+
get:
25+
description: Lorem Ipsum
26+
operationId: foo
27+
responses:
28+
202:
29+
description: Lorem Ipsum
30+
headers:
31+
Location: # should not violate since not called `Link`
32+
type: string
33+
format: url
34+
/bar:
35+
get:
36+
description: Lorem Ipsum
37+
operationId: foo
38+
responses:
39+
202:
40+
description: Lorem Ipsum
41+
headers:
42+
Location: # should not violate since not called `Link`
43+
type: string
44+
format: url
45+
""".trimIndent()
46+
)
47+
48+
val violations = cut.validate(context)
49+
50+
ZallyAssertions
51+
.assertThat(violations)
52+
.isEmpty()
53+
}
54+
55+
@Test
56+
fun `incorrect path prefix`() {
57+
@Language("YAML")
58+
val context = DefaultContextFactory().getOpenApiContext(
59+
"""
60+
openapi: 3.0.3
61+
info:
62+
title: Thing API
63+
version: 1.0.0
64+
paths:
65+
/client-api/foo:
66+
get:
67+
description: Lorem Ipsum
68+
operationId: foo
69+
responses:
70+
202:
71+
description: Lorem Ipsum
72+
headers:
73+
Location: # should not violate since not called `Link`
74+
type: string
75+
format: url
76+
/service-api/bar:
77+
get:
78+
description: Lorem Ipsum
79+
operationId: bar
80+
responses:
81+
202:
82+
description: Lorem Ipsum
83+
headers:
84+
Location: # should not violate since not called `Link`
85+
type: string
86+
format: url
87+
/integration-api/bar2:
88+
get:
89+
description: Lorem Ipsum 2
90+
operationId: bar2
91+
responses:
92+
202:
93+
description: Lorem Ipsum 2
94+
headers:
95+
Location: # should not violate since not called `Link`
96+
type: string
97+
format: url
98+
""".trimIndent()
99+
)
100+
101+
val violations = cut.validate(context)
102+
103+
ZallyAssertions
104+
.assertThat(violations)
105+
.isNotEmpty
106+
}
107+
108+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package com.backbase.oss.boat.quay.ruleset
2+
3+
import com.backbase.oss.boat.quay.ruleset.test.ZallyAssertions
4+
import org.intellij.lang.annotations.Language
5+
import org.junit.jupiter.api.Test
6+
import org.zalando.zally.core.DefaultContextFactory
7+
8+
class NoVersionInUriRuleTest {
9+
10+
private val cut = NoVersionInUriRule()
11+
12+
@Test
13+
fun `correct path prefix without version`() {
14+
@Language("YAML")
15+
val context = DefaultContextFactory().getOpenApiContext(
16+
"""
17+
openapi: 3.0.3
18+
info:
19+
title: Thing API
20+
version: 1.0.0
21+
paths:
22+
/api/foo:
23+
get:
24+
description: Lorem Ipsum
25+
operationId: foo
26+
responses:
27+
202:
28+
description: Lorem Ipsum
29+
headers:
30+
Location: # should not violate since not called `Link`
31+
type: string
32+
format: url
33+
/api/bar:
34+
get:
35+
description: Lorem Ipsum
36+
operationId: foo
37+
responses:
38+
202:
39+
description: Lorem Ipsum
40+
headers:
41+
Location: # should not violate since not called `Link`
42+
type: string
43+
format: url
44+
""".trimIndent()
45+
)
46+
47+
val violations = cut.validate(context)
48+
49+
ZallyAssertions
50+
.assertThat(violations)
51+
.isEmpty()
52+
}
53+
54+
@Test
55+
fun `incorrect path prefix with version`() {
56+
@Language("YAML")
57+
val context = DefaultContextFactory().getOpenApiContext(
58+
"""
59+
openapi: 3.0.3
60+
info:
61+
title: Thing API
62+
version: 1.0.0
63+
paths:
64+
/api/foo/v1true:
65+
get:
66+
description: Lorem Ipsum
67+
operationId: foo
68+
responses:
69+
202:
70+
description: Lorem Ipsum
71+
headers:
72+
Location: # should not violate since not called `Link`
73+
type: string
74+
format: url
75+
/api/v1/bar:
76+
get:
77+
description: Lorem Ipsum
78+
operationId: bar
79+
responses:
80+
202:
81+
description: Lorem Ipsum
82+
headers:
83+
Location: # should not violate since not called `Link`
84+
type: string
85+
format: url
86+
/v2/bar2:
87+
get:
88+
description: Lorem Ipsum 2
89+
operationId: bar2
90+
responses:
91+
202:
92+
description: Lorem Ipsum 2
93+
headers:
94+
Location: # should not violate since not called `Link`
95+
type: string
96+
format: url
97+
""".trimIndent()
98+
)
99+
100+
val violations = cut.validate(context)
101+
102+
ZallyAssertions
103+
.assertThat(violations)
104+
.isNotEmpty
105+
}
106+
107+
}

0 commit comments

Comments
 (0)