Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
* @author Dan Zheng
* @author András Deák
* @author Semyon Danilov
* @author Chris Bono
* @since 1.1.0
*/
@Configuration(proxyBeanMethods = false)
Expand Down Expand Up @@ -245,6 +246,15 @@ private void configureProperties(FluentConfiguration configuration, FlywayProper
// No method reference for compatibility with Flyway 6.x
map.from(properties.getSkipExecutingMigrations()).whenNonNull()
.to((skipExecutingMigrations) -> configuration.skipExecutingMigrations(skipExecutingMigrations));
// Teams secrets management properties (all non-method reference for
// compatibility with Flyway 6.x)
map.from(properties.getConjurUrl()).whenNonNull().to((conjurUrl) -> configuration.conjurUrl(conjurUrl));
map.from(properties.getConjurToken()).whenNonNull()
.to((conjurToken) -> configuration.conjurToken(conjurToken));
map.from(properties.getVaultUrl()).whenNonNull().to((vaultUrl) -> configuration.vaultUrl(vaultUrl));
map.from(properties.getVaultToken()).whenNonNull().to((vaultToken) -> configuration.vaultToken(vaultToken));
map.from(properties.getVaultSecrets()).whenNonNull()
.to((vaultSecrets) -> configuration.vaultSecrets(vaultSecrets));
}

private void configureCreateSchemas(FluentConfiguration configuration, boolean createSchemas) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
* @author Dave Syer
* @author Eddú Meléndez
* @author Stephane Nicoll
* @author Chris Bono
* @since 1.1.0
*/
@ConfigurationProperties(prefix = "spring.flyway")
Expand Down Expand Up @@ -328,6 +329,33 @@ public class FlywayProperties {
*/
private Boolean skipExecutingMigrations;

/**
* The REST API URL of the Conjur server. Requires Flyway teams.
Copy link
Member

Choose a reason for hiding this comment

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

Configuration properties documentation don't start with "The" or "A". Please look at other description in this file (and others) for inspiration and this section of the reference guide.

*/
private String conjurUrl;

/**
* The Conjur token required to access secrets. Requires Flyway teams.
*/
private String conjurToken;

/**
* The REST API URL of the Vault server. Requires Flyway teams.
*/
private String vaultUrl;

/**
* The Vault token required to access secrets. Requires Flyway teams.
*/
private String vaultToken;

/**
* A comma-separated list of paths to secrets that contain Flyway configurations. Each
* path must start with the name of the engine and end with the name of the secret
* such 'kv/test/1/config'. Requires Flyway teams.
*/
private String vaultSecrets;
Copy link
Member

Choose a reason for hiding this comment

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

If that's a comma separated list, it can't be a String. We should offer a way for users to also use yaml list if they want to.


public boolean isEnabled() {
return this.enabled;
}
Expand Down Expand Up @@ -772,4 +800,44 @@ public void setSkipExecutingMigrations(Boolean skipExecutingMigrations) {
this.skipExecutingMigrations = skipExecutingMigrations;
}

public String getConjurUrl() {
return conjurUrl;
}

public void setConjurUrl(String conjurUrl) {
this.conjurUrl = conjurUrl;
}

public String getConjurToken() {
return conjurToken;
}

public void setConjurToken(String conjurToken) {
this.conjurToken = conjurToken;
}

public String getVaultUrl() {
return vaultUrl;
}

public void setVaultUrl(String vaultUrl) {
this.vaultUrl = vaultUrl;
}

public String getVaultToken() {
return vaultToken;
}

public void setVaultToken(String vaultToken) {
this.vaultToken = vaultToken;
}

public String getVaultSecrets() {
return vaultSecrets;
}

public void setVaultSecrets(String vaultSecrets) {
this.vaultSecrets = vaultSecrets;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
* @author Dominic Gunn
* @author András Deák
* @author Takaaki Shimbo
* @author Chris Bono
*/
@ExtendWith(OutputCaptureExtension.class)
class FlywayAutoConfigurationTests {
Expand Down Expand Up @@ -412,35 +413,19 @@ void configurationCustomizersAreConfiguredAndOrdered() {

@Test
void batchIsCorrectlyMapped() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.batch=true").run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" batch ");
});
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.batch=true", "batch");
}

@Test
void dryRunOutputIsCorrectlyMapped() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.dryRunOutput=dryrun.sql").run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" dryRunOutput ");
});
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.dryRunOutput=dryrun.sql",
"dryRunOutput");
}

@Test
void errorOverridesIsCorrectlyMapped() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.errorOverrides=D12345").run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" errorOverrides ");
});
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.errorOverrides=D12345",
"errorOverrides");
}

@Test
Expand All @@ -452,46 +437,25 @@ void licenseKeyIsCorrectlyMapped(CapturedOutput output) {

@Test
void oracleSqlplusIsCorrectlyMapped() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.oracle-sqlplus=true").run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" oracle.sqlplus ");
});
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.oracle-sqlplus=true",
"oracle.sqlplus");
}

@Test
void oracleSqlplusWarnIsCorrectlyMapped() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.oracle-sqlplus-warn=true").run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" oracle.sqlplusWarn ");
});
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.oracle-sqlplus-warn=true",
"oracle.sqlplusWarn");
}

@Test
void streamIsCorrectlyMapped() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.stream=true").run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" stream ");
});
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.stream=true", "stream");
}

@Test
void undoSqlMigrationPrefix() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.undo-sql-migration-prefix=undo").run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" undoSqlMigrationPrefix ");
});
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.undo-sql-migration-prefix=undo",
"undoSqlMigrationPrefix");
}

@Test
Expand Down Expand Up @@ -525,67 +489,77 @@ void initSqlsWithFlywayUrl() {

@Test
void cherryPickIsCorrectlyMapped() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.cherry-pick=1.1").run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" cherryPick ");
});
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.cherry-pick=1.1", "cherryPick");
}

@Test
void jdbcPropertiesAreCorrectlyMapped() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.jdbc-properties.prop=value").run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" jdbcProperties ");
});
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.jdbc-properties.prop=value",
"jdbcProperties");
}

@Test
void oracleKerberosCacheFileIsCorrectlyMapped() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.oracle-kerberos-cache-file=/tmp/cache").run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" oracle.kerberosCacheFile ");
});
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException(
"spring.flyway.oracle-kerberos-cache-file=/tmp/cache", "oracle.kerberosCacheFile");
}

@Test
void oracleKerberosConfigFileIsCorrectlyMapped() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.oracle-kerberos-config-file=/tmp/config").run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" oracle.kerberosConfigFile ");
});
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException(
"spring.flyway.oracle-kerberos-config-file=/tmp/config", "oracle.kerberosConfigFile");
}

@Test
void outputQueryResultsIsCorrectlyMapped() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.output-query-results=false").run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" outputQueryResults ");
});
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.output-query-results=false",
"outputQueryResults");
}

@Test
void skipExecutingMigrationsIsCorrectlyMapped() {
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.skip-executing-migrations=true",
"skipExecutingMigrations");
}

@Test
void conjurUrlIsCorrectlyMapped() {
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException(
"spring.flyway.conjur-url=http://foo.com/secrets", "conjurUrl");
}

@Test
void conjurTokenIsCorrectlyMapped() {
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.conjur-token=5150",
"conjurToken");
}

@Test
void vaultUrlIsCorrectlyMapped() {
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.vault-url=http://foo.com/secrets",
"vaultUrl");
}

@Test
void vaultTokenIsCorrectlyMapped() {
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.vault-token=5150", "vaultToken");
}

@Test
void vaultSecretsIsCorrectlyMapped() {
assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException("spring.flyway.vault-secrets=kv/test/1/config",
"vaultSecrets");
}

@Test
Copy link
Member

Choose a reason for hiding this comment

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

This shouldn't be flagged with @Test.

private void assertThatPropertyResultsInFlywayTeamsUpgradeRequiredException(String propertyKeyAndValue,
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer that the setup remains in each test and that the thing that's shared is the real assertion in the form of a ContextConsumer.

A good example of what I am trying to convey is in EnvironmentEndpointAutoConfigurationTests.

String flywayPropertyNameInException) {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@snicoll thx for the suggestion. Keeping the setup in each test makes it easy to see what the test is doing from first glance. Sharing only the common validation reduces the duplicated lines (and that was the main goal of the first attempt). 👍🏻

.withPropertyValues("spring.flyway.skip-executing-migrations=true").run((context) -> {
.withPropertyValues(propertyKeyAndValue).run((context) -> {
assertThat(context).hasFailed();
Throwable failure = context.getStartupFailure();
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
assertThat(failure).hasMessageContaining(" skipExecutingMigrations ");
assertThat(failure).hasMessageContaining(String.format(" %s ", flywayPropertyNameInException));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
* Tests for {@link FlywayProperties}.
*
* @author Stephane Nicoll
* @author Chris Bono
*/
class FlywayPropertiesTests {

Expand Down Expand Up @@ -108,9 +109,7 @@ void expectedPropertiesAreManaged() {
// Handled by the conversion service
ignoreProperties(configuration, "baselineVersionAsString", "encodingAsString", "locationsAsStrings",
"targetAsString");
// Teams-only properties that we cannot detect as no exception is thrown and
// getters return null
Copy link
Member

Choose a reason for hiding this comment

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

This line should be deleted as well please.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, good catch @wilkinsona .

ignoreProperties(configuration, "conjurToken", "conjurUrl", "vaultSecrets", "vaultToken", "vaultUrl");
// Handled as initSql array
ignoreProperties(configuration, "initSql");
ignoreProperties(properties, "initSqls");
Expand Down