Skip to content

Commit e20ff76

Browse files
authored
Merge pull request #367 from kmanning/issue_365
Issue 365: Make flyway configuration more generic
2 parents 1994939 + db4b5c7 commit e20ff76

File tree

6 files changed

+185
-72
lines changed

6 files changed

+185
-72
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* [Issue #354](https://github.com/manheim/terraform-pipeline/issues/354) Feature: Add TerraformTaintPlugin - Allows performing `terraform taint` or `terraform untaint` prior to the plan phase.
88
* [Issue #21](https://github.com/manheim/terraform-pipeline/issues/21) Feature: Plugin to run database migration scripts
99
* [Issue #363](https://github.com/manheim/terraform-pipeline/issues/363) Feature: Optionally disable echo on flyway CLI commands
10+
* [Issue #365](https://github.com/manheim/terraform-pipeline/issues/365) Feature: Optionally configure flyway username/password through CLI options
1011

1112
# v5.15
1213

docs/FlywayMigrationPlugin.md

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,42 @@ validate.then(deployQa)
2121
.build()
2222
```
2323

24-
If needed, flyway configuration can be set through the Plugin, or FlywayCommand.
24+
If needed, flyway configuration can be set through the FlywayCommand.
2525

2626
```
2727
@Library(['terraform-pipeline']) _
2828
Jenkinsfile.init(this, Customizations)
29-
// Use the FlywayCommand to modify specific options like `locations` and `url`
30-
FlywayCommand.withLocations("filesystem:`pwd`/migrations")
29+
// Use the FlywayCommand to modify specific options like `user`, `password`, `locations`, and `url`
30+
FlywayCommand.withUser("\$TF_VAR_USER")
31+
.withPassword("\$TF_VAR_PASSWORD")
32+
.withLocations("filesystem:`pwd`/migrations")
3133
.withUrl("`terraform output jdbc_url`")
32-
// Flyway automatically picks up specific enviornment variables (FLYWAY_USER, FLYWAY_PASSWORD)
33-
// Sets FLYWAY_USER to the value of $TF_VAR_MIGRATION_USER
34-
// Sets FLYWAY_PASSWORD to the value of $TF_VAR_MIGRATION_PASSWORD
35-
FlywayMigrationPlugin.withUserVariable('TF_VAR_MIGRATION_USER')
36-
.withPasswordVariable('TF_VAR_MIGRATION_PASSWORD')
34+
FlywayMigrationPlugin.init()
35+
36+
def validate = new TerraformValidateStage()
37+
// For each environment
38+
// Run the `flyway info` command after a successful `terraform plan`
39+
// Run the `flyway migrate` command after a successful `terraform apply`
40+
def deployQa = new TerraformEnvironmentStage('qa')
41+
def deployUat = new TerraformEnvironmentStage('uat')
42+
def deployProd = new TerraformEnvironmentStage('prod')
43+
44+
validate.then(deployQa)
45+
.then(deployUat)
46+
.then(deployProd)
47+
.build()
48+
```
49+
50+
Or through existing environment variables and the FlywayMigrationPlugin.
51+
52+
```
53+
@Library(['terraform-pipeline']) _
54+
Jenkinsfile.init(this, Customizations)
55+
// Allow flyway to be configured through standard environment variables
56+
FlywayMigrationPlugin.withMappedEnvironmentVariable('TF_VAR_USER', 'FLYWAY_USER')
57+
.withMappedEnvironmentVariable('TF_VAR_PASSWORD', 'FLYWAY_PASSWORD')
58+
.withMappedEnvironmentVariable('JDBC_URL', 'FLYWAY_URL')
59+
.withMappedEnvironmentVariable('LOCATIONS', 'FLYWAY_LOCATIONS')
3760
.init()
3861
3962
def validate = new TerraformValidateStage()

src/FlywayCommand.groovy

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ class FlywayCommand implements Resettable {
33
private String binary = "flyway"
44
private static String locations
55
private static String url
6+
private static String user
7+
private static String password
8+
private static Collection additionalParameters = []
69

710
public FlywayCommand(String command) {
811
this.command = command
@@ -21,9 +24,29 @@ class FlywayCommand implements Resettable {
2124
pieces << "-url=${url}"
2225
}
2326

27+
if (user) {
28+
pieces << "-user=${user}"
29+
}
30+
31+
if (password) {
32+
pieces << "-password=${password}"
33+
}
34+
35+
pieces.addAll(additionalParameters)
36+
2437
return pieces.join(' ')
2538
}
2639

40+
public static withUser(String user) {
41+
this.user = user
42+
return this
43+
}
44+
45+
public static withPassword(String password) {
46+
this.password = password
47+
return this
48+
}
49+
2750
public static withLocations(String locations) {
2851
this.locations = locations
2952
return this
@@ -34,8 +57,17 @@ class FlywayCommand implements Resettable {
3457
return this
3558
}
3659

60+
public static withAdditionalParameter(String parameter) {
61+
this.additionalParameters << parameter
62+
println "withAdditionalParameter: ${parameter}, ${this.additionalParameters}"
63+
return this
64+
}
65+
3766
public static reset() {
3867
this.locations = null
3968
this.url = null
69+
this.user = null
70+
this.password = null
71+
this.additionalParameters = []
4072
}
4173
}

src/FlywayMigrationPlugin.groovy

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
class FlywayMigrationPlugin implements TerraformEnvironmentStagePlugin, Resettable {
2-
public static String passwordVariable
3-
public static String userVariable
2+
public static Map<String,String> variableMap = [:]
43
public static boolean echoEnabled = false
54

65
public static void init() {
@@ -37,16 +36,10 @@ class FlywayMigrationPlugin implements TerraformEnvironmentStagePlugin, Resettab
3736
}
3837

3938
public Collection buildEnvironmentVariableList(env) {
40-
def list = []
41-
if (passwordVariable) {
42-
list << "FLYWAY_PASSWORD=${env[passwordVariable]}"
39+
variableMap.inject([]) { list, key, value ->
40+
list << "${key}=${env[value]}"
41+
list
4342
}
44-
45-
if (userVariable) {
46-
list << "FLYWAY_USER=${env[userVariable]}"
47-
}
48-
49-
return list
5043
}
5144

5245
public String buildFlywayCommand(FlywayCommand command) {
@@ -62,24 +55,18 @@ class FlywayMigrationPlugin implements TerraformEnvironmentStagePlugin, Resettab
6255
return pieces.join('\n')
6356
}
6457

65-
public static withPasswordFromEnvironmentVariable(String passwordVariable) {
66-
this.passwordVariable = passwordVariable
67-
return this
68-
}
69-
70-
public static withUserFromEnvironmentVariable(String userVariable) {
71-
this.userVariable = userVariable
58+
public static withEchoEnabled(boolean trueOrFalse = true) {
59+
this.echoEnabled = trueOrFalse
7260
return this
7361
}
7462

75-
public static withEchoEnabled(boolean trueOrFalse = true) {
76-
this.echoEnabled = trueOrFalse
63+
public static withMappedEnvironmentVariable(String from, String to) {
64+
variableMap[to] = from
7765
return this
7866
}
7967

8068
public static reset() {
81-
passwordVariable = null
82-
userVariable = null
69+
variableMap = [:]
8370
echoEnabled = false
8471
}
8572
}

test/FlywayCommandTest.groovy

Lines changed: 103 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,56 @@ import org.junit.jupiter.api.extension.ExtendWith
88

99
@ExtendWith(ResetStaticStateExtension.class)
1010
class FlywayCommandTest {
11+
@Nested
12+
public class WithUser {
13+
@Test
14+
void isfluent() {
15+
def result = FlywayCommand.withUser('someUser')
16+
17+
assertThat(result, equalTo(FlywayCommand.class))
18+
}
19+
}
20+
21+
@Nested
22+
public class WithPassword {
23+
@Test
24+
void isfluent() {
25+
def result = FlywayCommand.withPassword('somePassword')
26+
27+
assertThat(result, equalTo(FlywayCommand.class))
28+
}
29+
}
30+
31+
@Nested
32+
public class WithLocations {
33+
@Test
34+
void isFluent() {
35+
def result = FlywayCommand.withLocations('someLocations')
36+
37+
assertThat(result, equalTo(FlywayCommand.class))
38+
}
39+
}
40+
41+
@Nested
42+
public class WithUrl {
43+
@Test
44+
void isFluent() {
45+
def result = FlywayCommand.withUrl('someUrl')
46+
47+
assertThat(result, equalTo(FlywayCommand.class))
48+
}
49+
}
50+
51+
@Nested
52+
public class WithAdditionalParameter {
53+
@Test
54+
void isFluent() {
55+
def result = FlywayCommand.withAdditionalParameter('-someParam=someValue')
56+
57+
assertThat(result, equalTo(FlywayCommand.class))
58+
}
59+
}
60+
1161
@Nested
1262
public class ToString {
1363
@Test
@@ -20,14 +70,35 @@ class FlywayCommandTest {
2070
}
2171

2272
@Nested
23-
public class WithLocations {
73+
public class WithUser {
74+
@Test
75+
void includesTheUserParameter() {
76+
def expectedUser = 'someUser'
77+
FlywayCommand.withUser(expectedUser)
78+
def command = new FlywayCommand('blah')
79+
80+
def result = command.toString()
81+
82+
assertThat(result, containsString("-user=${expectedUser}"))
83+
}
84+
}
85+
86+
@Nested
87+
public class WithPassword {
2488
@Test
25-
void isFluent() {
26-
def result = FlywayCommand.withLocations('someLocations')
89+
void includesThePasswordParameter() {
90+
def expectedPassword = 'somePassword'
91+
FlywayCommand.withPassword(expectedPassword)
92+
def command = new FlywayCommand('blah')
2793

28-
assertThat(result, equalTo(FlywayCommand.class))
94+
def result = command.toString()
95+
96+
assertThat(result, containsString("-password=${expectedPassword}"))
2997
}
98+
}
3099

100+
@Nested
101+
public class WithLocations {
31102
@Test
32103
void includesTheLocationsParameter() {
33104
def expectedLocations = 'filesystem:/some/dir'
@@ -42,13 +113,6 @@ class FlywayCommandTest {
42113

43114
@Nested
44115
public class WithUrl {
45-
@Test
46-
void isFluent() {
47-
def result = FlywayCommand.withUrl('someUrl')
48-
49-
assertThat(result, equalTo(FlywayCommand.class))
50-
}
51-
52116
@Test
53117
void includesTheUrlParameter() {
54118
def expectedUrl = 'jdbc:mysql://someurl'
@@ -60,5 +124,33 @@ class FlywayCommandTest {
60124
assertThat(result, containsString("-url=${expectedUrl}"))
61125
}
62126
}
127+
128+
@Nested
129+
public class WithAdditionalParameters {
130+
@Test
131+
void addsTheAdditionalParameter() {
132+
def expectedParameter = "-someParam=someValue"
133+
FlywayCommand.withAdditionalParameter(expectedParameter)
134+
def command = new FlywayCommand('blah')
135+
136+
def result = command.toString()
137+
138+
assertThat(result, containsString(expectedParameter))
139+
}
140+
141+
@Test
142+
void addsMultipleAdditionalParameters() {
143+
def param1 = '-param1=value1'
144+
def param2 = '-param2=value2'
145+
FlywayCommand.withAdditionalParameter(param1)
146+
.withAdditionalParameter(param2)
147+
def command = new FlywayCommand('blah')
148+
149+
def result = command.toString()
150+
151+
assertThat(result, containsString(param1))
152+
assertThat(result, containsString(param2))
153+
}
154+
}
63155
}
64156
}

test/FlywayMigrationPluginTest.groovy

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -54,20 +54,10 @@ class FlywayMigrationPluginTest {
5454
}
5555

5656
@Nested
57-
public class WithPasswordFromEnvironmentVariable {
57+
public class WithMappedEnvironmentVariable {
5858
@Test
5959
void isFluent() {
60-
def result = FlywayMigrationPlugin.withPasswordFromEnvironmentVariable('MY_PASSWORD')
61-
62-
assertThat(result, equalTo(FlywayMigrationPlugin.class))
63-
}
64-
}
65-
66-
@Nested
67-
public class WithUserFromEnvironmentVariable {
68-
@Test
69-
void isFluent() {
70-
def result = FlywayMigrationPlugin.withUserFromEnvironmentVariable('MY_USER')
60+
def result = FlywayMigrationPlugin.withMappedEnvironmentVariable('TF_VAR_MY_USER', 'FLYWAY_USER')
7161

7262
assertThat(result, equalTo(FlywayMigrationPlugin.class))
7363
}
@@ -155,29 +145,17 @@ class FlywayMigrationPluginTest {
155145
}
156146

157147
@Test
158-
void setsPasswordWhenVariableProvided() {
159-
def expectedVariable = 'MY_PASSWORD_VARIABLE'
160-
def expectedValue = 'somePass'
161-
FlywayMigrationPlugin.withPasswordFromEnvironmentVariable(expectedVariable)
162-
def plugin = new FlywayMigrationPlugin()
163-
def env = [(expectedVariable): expectedValue]
164-
165-
def result = plugin.buildEnvironmentVariableList(env)
166-
167-
assertThat(result, equalTo(["FLYWAY_PASSWORD=${expectedValue}"]))
168-
}
169-
170-
@Test
171-
void setsUserWhenVariableProvided() {
172-
def expectedVariable = 'MY_USER_VARIABLE'
173-
def expectedValue = 'someUser'
174-
FlywayMigrationPlugin.withUserFromEnvironmentVariable(expectedVariable)
148+
void mapsEnvironmentVariable() {
149+
def toVariable = 'FLYWAY_USER'
150+
def fromVariable = 'MY_USER_VARIABLE'
151+
def fromValue = 'someUser'
152+
FlywayMigrationPlugin.withMappedEnvironmentVariable(fromVariable, toVariable)
175153
def plugin = new FlywayMigrationPlugin()
176-
def env = [(expectedVariable): expectedValue]
154+
def env = [(fromVariable): fromValue]
177155

178156
def result = plugin.buildEnvironmentVariableList(env)
179157

180-
assertThat(result, equalTo(["FLYWAY_USER=${expectedValue}"]))
158+
assertThat(result, equalTo(["${toVariable}=${fromValue}"]))
181159
}
182160
}
183161

0 commit comments

Comments
 (0)