Skip to content

Commit 4fb1dd5

Browse files
committed
Added Environment Resolver
1 parent d40afae commit 4fb1dd5

7 files changed

Lines changed: 216 additions & 26 deletions

File tree

src/org/ods/orchestration/InitStage.groovy

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import org.ods.orchestration.usecase.JiraUseCaseSupport
1313
import org.ods.orchestration.usecase.JiraUseCaseZephyrSupport
1414
import org.ods.orchestration.usecase.LeVADocumentUseCase
1515
import org.ods.orchestration.usecase.OpenIssuesException
16+
import org.ods.orchestration.util.EnvironmentResolver
1617
import org.ods.orchestration.util.GitTag
1718
import org.ods.orchestration.util.MROPipelineUtil
1819
import org.ods.orchestration.util.PDFUtil
@@ -529,7 +530,9 @@ class InitStage extends Stage {
529530
def gitReleaseBranch = GitService.getReleaseBranch(buildParams.version)
530531
logger.debug("Release Manager branch to checkout: ${gitReleaseBranch}")
531532
if (Project.isPromotionMode(buildParams.targetEnvironmentToken)) {
532-
checkOutRepoInPromotionMode(git, buildParams, gitReleaseBranch, logger)
533+
def resolver = new EnvironmentResolver(script.env.ENVIRONMENTS_ENABLED as String)
534+
def sourceEnvToken = resolver.getSourceEnvTokenFor(buildParams.targetEnvironment as String)
535+
checkOutRepoInPromotionMode(git, buildParams, gitReleaseBranch, sourceEnvToken, logger)
533536
} else {
534537
checkOutRepoInNotPromotionMode(git, buildParams, gitReleaseBranch, false, logger)
535538
}
@@ -575,21 +578,22 @@ class InitStage extends Stage {
575578
private Exception checkOutRepoInPromotionMode(GitService git,
576579
Map buildParams,
577580
String gitReleaseBranch,
581+
String sourceEnvToken,
578582
Logger logger) {
579583
def tagList = git.readBaseTagList(
580584
buildParams.version,
581585
buildParams.changeId,
582-
buildParams.targetEnvironmentToken
586+
sourceEnvToken
583587
)
584588
def baseTag = GitTag.readLatestBaseTag(
585589
tagList,
586590
buildParams.version,
587591
buildParams.changeId,
588-
buildParams.targetEnvironmentToken
592+
sourceEnvToken
589593
)?.toString()
590594
if (!baseTag) {
591595
throw new RuntimeException(
592-
"Error: unable to find latest tag for version ${buildParams.version}/${buildParams.changeId}."
596+
"Error: unable to find latest tag *-${sourceEnvToken} for version ${buildParams.version}/${buildParams.changeId}."
593597
)
594598
}
595599
logger.info("Checkout release manager repository @ ${baseTag}")
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package org.ods.orchestration.util
2+
3+
import com.cloudbees.groovy.cps.NonCPS
4+
5+
class EnvironmentResolver {
6+
7+
static final String DEFAULT_ENVIRONMENTS = 'dev,qa,prod'
8+
9+
static final List<List<String>> ALLOWED_ENVIRONMENT_SETS = [
10+
['dev', 'qa', 'prod'],
11+
['dev', 'prod'],
12+
]
13+
14+
private final List<String> enabledEnvironments
15+
16+
EnvironmentResolver(String rawEnvironments) {
17+
this.enabledEnvironments = resolveEnabledEnvironments(rawEnvironments)
18+
}
19+
20+
@NonCPS
21+
private List<String> resolveEnabledEnvironments(String raw) {
22+
if (!raw?.trim()) {
23+
raw = DEFAULT_ENVIRONMENTS
24+
}
25+
List<String> environments = raw.split(',').collect { it.trim() }.findAll { it }
26+
validateEnvironments(environments)
27+
return environments
28+
}
29+
30+
@NonCPS
31+
private void validateEnvironments(List<String> environments) {
32+
boolean valid = ALLOWED_ENVIRONMENT_SETS.any { allowed -> allowed == environments }
33+
if (!valid) {
34+
String allowedStr = ALLOWED_ENVIRONMENT_SETS.collect { it.join(',') }.join(' | ')
35+
throw new IllegalArgumentException(
36+
"Invalid value for ENVIRONMENTS_ENABLED: '${environments.join(',')}'. " +
37+
"Allowed values are: ${allowedStr}"
38+
)
39+
}
40+
}
41+
42+
@NonCPS
43+
List<String> getEnabledEnvironments() {
44+
return enabledEnvironments
45+
}
46+
47+
/**
48+
* Returns the source environment for the given target environment.
49+
* The source is the previous environment in the enabled list, or 'dev' if
50+
* the target is first in the list or not present (e.g. 'qa' when only dev/prod are enabled).
51+
*/
52+
@NonCPS
53+
String getSourceEnvFor(String targetEnvironment) {
54+
int idx = enabledEnvironments.indexOf(targetEnvironment)
55+
if (idx <= 0) {
56+
return enabledEnvironments.first()
57+
}
58+
return enabledEnvironments[idx - 1]
59+
}
60+
61+
/**
62+
* Returns the Environment token for the source environment of the given target.
63+
* Values: D, Q, P
64+
*/
65+
@NonCPS
66+
String getSourceEnvTokenFor(String targetEnvironment) {
67+
return getSourceEnvFor(targetEnvironment)[0].toUpperCase() as String
68+
}
69+
70+
}

src/org/ods/orchestration/util/GitTag.groovy

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,14 @@ class GitTag {
2929
this.envToken = envToken
3030
}
3131

32-
static GitTag readLatestBaseTag(String tagList, String version, String changeId, String envToken) {
33-
def previousEnvToken = 'D'
34-
if (envToken == 'P') {
35-
previousEnvToken = 'Q'
36-
}
32+
static GitTag readLatestBaseTag(String tagList, String version, String changeId, String sourceEnvToken) {
3733
if (tagList) {
3834
def tags = tagList.split("\n")
3935

4036
def highestIteration = -1
4137
def highestBuildNumber = '0'
4238
tags.each {
43-
def iterationInfo = extractIterationInfo(it, version, changeId, previousEnvToken)
39+
def iterationInfo = extractIterationInfo(it, version, changeId, sourceEnvToken)
4440
if (iterationInfo) {
4541
def iterationCandidate = iterationInfo.first().toInteger()
4642
def buildNumberCandidate = iterationInfo.last()
@@ -51,7 +47,7 @@ class GitTag {
5147
}
5248
}
5349
if (highestIteration > -1 ) {
54-
return new GitTag(version, changeId, highestIteration, highestBuildNumber, previousEnvToken)
50+
return new GitTag(version, changeId, highestIteration, highestBuildNumber, sourceEnvToken)
5551
}
5652
}
5753
return null

src/org/ods/orchestration/util/Project.groovy

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ class Project {
300300
protected String targetProject
301301
protected Boolean isVersioningEnabled = false
302302
private String _gitReleaseBranch
303+
private EnvironmentResolver environmentResolver
303304

304305
private TestResults aggregatedTestResults;
305306

@@ -321,6 +322,8 @@ class Project {
321322
Project init() {
322323
this.data.buildParams = this.loadBuildParams(steps)
323324
this.data.metadata = this.loadMetadata(METADATA_FILE_NAME)
325+
this.environmentResolver = new EnvironmentResolver(steps.env.ENVIRONMENTS_ENABLED as String)
326+
logger.info("Deployment environments: ${environmentResolver.enabledEnvironments.join('->')}")
324327

325328
return this
326329
}
@@ -336,11 +339,14 @@ class Project {
336339
def version = this.data.buildParams.version
337340
def changeId = this.data.buildParams.changeId
338341
def targetEnvironmentToken = this.data.buildParams.targetEnvironmentToken
342+
def sourceEnvToken = environmentResolver.getSourceEnvTokenFor(
343+
this.data.buildParams.targetEnvironment as String
344+
)
339345
def baseTag = null
340346
def targetTag = null
341347
if (!getIsWorkInProgress()) {
342-
def tagList = git.readBaseTagList(version, changeId, targetEnvironmentToken)
343-
baseTag = GitTag.readLatestBaseTag(tagList, version, changeId, targetEnvironmentToken)
348+
def tagList = git.readBaseTagList(version, changeId, sourceEnvToken)
349+
baseTag = GitTag.readLatestBaseTag(tagList, version, changeId, sourceEnvToken)
344350

345351
if (getIsAssembleMode()) {
346352
if (baseTag) {
@@ -760,7 +766,7 @@ class Project {
760766
}
761767

762768
String getSourceEnv() {
763-
['dev': 'dev', 'qa': 'dev', 'prod': 'qa'].get(buildParams.targetEnvironment)
769+
environmentResolver.getSourceEnvFor(buildParams.targetEnvironment as String)
764770
}
765771

766772
String getBaseTag() {

src/org/ods/services/GitService.groovy

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -352,16 +352,12 @@ class GitService {
352352
)
353353
}
354354

355-
String readBaseTagList(String version, String changeId, String envToken) {
356-
def previousEnvToken = 'D'
357-
if (envToken == 'P') {
358-
previousEnvToken = 'Q'
359-
}
360-
def tagPattern = "${ODS_GIT_TAG_PREFIX}v${version}-${changeId}-*-${previousEnvToken}"
355+
String readBaseTagList(String version, String changeId, String sourceEnvToken) {
356+
def tagPattern = "${ODS_GIT_TAG_PREFIX}v${version}-${changeId}-*-${sourceEnvToken}"
361357
script.sh(
362358
script: "git tag --list '${tagPattern}'",
363359
returnStdout: true,
364-
label: "list tags for version ${version}-${changeId}-*-${previousEnvToken}"
360+
label: "list tags for version ${version}-${changeId}-*-${sourceEnvToken}"
365361
).trim()
366362
}
367363

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package org.ods.orchestration.util
2+
3+
import util.SpecHelper
4+
5+
class EnvironmentResolverSpec extends SpecHelper {
6+
7+
// -------------------------------------------------------------------------
8+
// Constructor / resolveEnabledEnvironments
9+
// -------------------------------------------------------------------------
10+
11+
def "uses default environments when raw value is null"() {
12+
when:
13+
def resolver = new EnvironmentResolver(null)
14+
15+
then:
16+
resolver.getEnabledEnvironments() == ['dev', 'qa', 'prod']
17+
}
18+
19+
def "uses default environments when raw value is empty"() {
20+
when:
21+
def resolver = new EnvironmentResolver('')
22+
23+
then:
24+
resolver.getEnabledEnvironments() == ['dev', 'qa', 'prod']
25+
}
26+
27+
def "uses default environments when raw value is blank"() {
28+
when:
29+
def resolver = new EnvironmentResolver(' ')
30+
31+
then:
32+
resolver.getEnabledEnvironments() == ['dev', 'qa', 'prod']
33+
}
34+
35+
def "parses dev,qa,prod correctly"() {
36+
when:
37+
def resolver = new EnvironmentResolver('dev,qa,prod')
38+
39+
then:
40+
resolver.getEnabledEnvironments() == ['dev', 'qa', 'prod']
41+
}
42+
43+
def "parses dev,prod correctly"() {
44+
when:
45+
def resolver = new EnvironmentResolver('dev,prod')
46+
47+
then:
48+
resolver.getEnabledEnvironments() == ['dev', 'prod']
49+
}
50+
51+
def "trims whitespace around environment names"() {
52+
when:
53+
def resolver = new EnvironmentResolver(' dev , prod ')
54+
55+
then:
56+
resolver.getEnabledEnvironments() == ['dev', 'prod']
57+
}
58+
59+
// -------------------------------------------------------------------------
60+
// validateEnvironments
61+
// -------------------------------------------------------------------------
62+
63+
def "throws IllegalArgumentException for unknown environment set"() {
64+
when:
65+
new EnvironmentResolver(raw)
66+
67+
then:
68+
def ex = thrown(IllegalArgumentException)
69+
ex.message.contains('Allowed values are: dev,qa,prod | dev,prod')
70+
71+
where:
72+
raw << ['dev', 'prod,qa', 'dev,staging,prod', 'dev,qa,prod,staging']
73+
}
74+
75+
// -------------------------------------------------------------------------
76+
// getSourceEnvFor
77+
// -------------------------------------------------------------------------
78+
79+
def "getSourceEnvFor returns correct source environment"() {
80+
given:
81+
def resolver = new EnvironmentResolver(raw)
82+
83+
expect:
84+
resolver.getSourceEnvFor(target) == expected
85+
86+
where:
87+
raw | target || expected
88+
'dev,qa,prod' | 'dev' || 'dev'
89+
'dev,qa,prod' | 'qa' || 'dev'
90+
'dev,qa,prod' | 'prod' || 'qa'
91+
'dev,prod' | 'dev' || 'dev'
92+
'dev,prod' | 'qa' || 'dev' // qa not in list → fallback to first
93+
'dev,prod' | 'prod' || 'dev'
94+
}
95+
96+
// -------------------------------------------------------------------------
97+
// getSourceEnvTokenFor
98+
// -------------------------------------------------------------------------
99+
100+
def "getSourceEnvTokenFor returns correct token"() {
101+
given:
102+
def resolver = new EnvironmentResolver(raw)
103+
104+
expect:
105+
resolver.getSourceEnvTokenFor(target) == expectedToken
106+
107+
where:
108+
raw | target || expectedToken
109+
'dev,qa,prod' | 'dev' || 'D'
110+
'dev,qa,prod' | 'qa' || 'D'
111+
'dev,qa,prod' | 'prod' || 'Q'
112+
'dev,prod' | 'dev' || 'D'
113+
'dev,prod' | 'qa' || 'D' // qa not in list → fallback to dev → D
114+
'dev,prod' | 'prod' || 'D'
115+
}
116+
117+
}
118+

test/groovy/org/ods/orchestration/util/GitTagSpec.groovy

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ class GitTagSpec extends SpecHelper {
3535

3636
where:
3737
tagList | version | changeId | envToken || result
38-
"${GitService.ODS_GIT_TAG_PREFIX}v1-A-0-D" | "1" | "A" | "Q" || "${GitService.ODS_GIT_TAG_PREFIX}v1-A-0b0-D"
39-
"${GitService.ODS_GIT_TAG_PREFIX}v1-A-0-D\n${GitService.ODS_GIT_TAG_PREFIX}v1-A-1-D" | "1" | "A" | "Q" || "${GitService.ODS_GIT_TAG_PREFIX}v1-A-1b0-D"
38+
"${GitService.ODS_GIT_TAG_PREFIX}v1-A-0-D" | "1" | "A" | "D" || "${GitService.ODS_GIT_TAG_PREFIX}v1-A-0b0-D"
4039
"${GitService.ODS_GIT_TAG_PREFIX}v1-A-0-D\n${GitService.ODS_GIT_TAG_PREFIX}v1-A-1-D" | "1" | "A" | "D" || "${GitService.ODS_GIT_TAG_PREFIX}v1-A-1b0-D"
41-
"${GitService.ODS_GIT_TAG_PREFIX}v1-A-0-Q\n${GitService.ODS_GIT_TAG_PREFIX}v1-A-1-Q" | "1" | "A" | "P" || "${GitService.ODS_GIT_TAG_PREFIX}v1-A-1b0-Q"
42-
"${GitService.ODS_GIT_TAG_PREFIX}v1-A-0-D\n${GitService.ODS_GIT_TAG_PREFIX}v1-A-1b99-D" | "1" | "A" | "Q" || "${GitService.ODS_GIT_TAG_PREFIX}v1-A-1b99-D"
43-
"" | "1" | "A" | "P" || "null"
40+
"${GitService.ODS_GIT_TAG_PREFIX}v1-A-0-D\n${GitService.ODS_GIT_TAG_PREFIX}v1-A-1-D" | "1" | "A" | "D" || "${GitService.ODS_GIT_TAG_PREFIX}v1-A-1b0-D"
41+
"${GitService.ODS_GIT_TAG_PREFIX}v1-A-0-Q\n${GitService.ODS_GIT_TAG_PREFIX}v1-A-1-Q" | "1" | "A" | "Q" || "${GitService.ODS_GIT_TAG_PREFIX}v1-A-1b0-Q"
42+
"${GitService.ODS_GIT_TAG_PREFIX}v1-A-0-D\n${GitService.ODS_GIT_TAG_PREFIX}v1-A-1b99-D" | "1" | "A" | "D" || "${GitService.ODS_GIT_TAG_PREFIX}v1-A-1b99-D"
43+
"" | "1" | "A" | "Q" || "null"
4444
}
4545

4646
}

0 commit comments

Comments
 (0)