mirror of
https://github.com/google/nomulus.git
synced 2025-04-29 19:47:51 +02:00
* Enhance the test for forbidden Schema changes Current test is git-based. It is difficult to maintain and does not catch out-of-order version numbers. It is also more aggressive than necessary, failing on changes to submitted scripts that have not been deployed yet. The new test starts a database, deploys the current schema to it, then deploys the set of Flyway scripts in this repository to the database.
223 lines
7 KiB
Groovy
223 lines
7 KiB
Groovy
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
plugins {
|
|
id "org.flywaydb.flyway" version "6.0.1"
|
|
id 'maven-publish'
|
|
}
|
|
|
|
ext {
|
|
Set restrictedDbEnv =
|
|
[ 'sandbox', 'production' ].asUnmodifiable()
|
|
Set allDbEnv =
|
|
[ 'alpha', 'crash' ].plus(restrictedDbEnv).asUnmodifiable()
|
|
|
|
def dbServerProperty = 'dbServer'
|
|
def dbNameProperty = 'dbName'
|
|
|
|
def dbServer = findProperty(dbServerProperty).toString().toLowerCase()
|
|
def dbName = findProperty(dbNameProperty)
|
|
|
|
isRestricted = {
|
|
return restrictedDbEnv.contains(dbServer)
|
|
}
|
|
|
|
getAccessInfoByHostPort = { hostAndPort ->
|
|
println "Database set to ${hostAndPort}."
|
|
return [
|
|
url: "jdbc:postgresql://${hostAndPort}/${dbName}",
|
|
user: findProperty('dbUser'),
|
|
password: findProperty('dbPassword')]
|
|
}
|
|
|
|
getSocketFactoryAccessInfo = { env ->
|
|
def cred = getCloudSqlCredential(env, 'admin').split(' ')
|
|
def sqlInstance = cred[0]
|
|
println "Database set to Cloud SQL instance ${sqlInstance}."
|
|
return [
|
|
url: """\
|
|
jdbc:postgresql://google/${dbName}?cloudSqlInstance=
|
|
${sqlInstance}&socketFactory=
|
|
com.google.cloud.sql.postgres.SocketFactory"""
|
|
.stripIndent()
|
|
.replaceAll(System.lineSeparator(), '') ,
|
|
user: cred[1],
|
|
password: cred[2]]
|
|
}
|
|
|
|
getJdbcAccessInfo = {
|
|
if (allDbEnv.contains(dbServer)) {
|
|
return getSocketFactoryAccessInfo(dbServer)
|
|
} else if (!dbServer.isEmpty()) {
|
|
return getAccessInfoByHostPort(dbServer)
|
|
} else {
|
|
// Not connecting to a database. Return a dummy object for Flyway config.
|
|
return [ url: '', user: '', password: '' ]
|
|
}
|
|
}
|
|
|
|
// Retrieves Cloud SQL credential for a given role. Result is in the form of
|
|
// 'instancename username password'.
|
|
//
|
|
// The env parameter may be one of the following: alpha, crash, sandbox, or
|
|
// production. The role parameter may be superuser. (More roles will be added
|
|
// later).
|
|
getCloudSqlCredential = { env, role ->
|
|
def devProject = project.hasProperty('devProject')
|
|
? project.getProperty('devProject') : rootProject.devProject
|
|
def gcpProject = project.hasProperty('gcpProject')
|
|
? project.getProperty('gcpProject') : rootProject.gcpProject
|
|
def keyProject = env in restrictedDbEnv? devProject : gcpProject
|
|
def command =
|
|
"""gsutil cp \
|
|
gs://${gcpProject}-beam/cloudsql/${role}_credential.enc - | \
|
|
base64 -d | \
|
|
gcloud kms decrypt --location global --keyring nomulus-tool-keyring \
|
|
--key nomulus-tool-key --plaintext-file=- \
|
|
--ciphertext-file=- \
|
|
--project=${keyProject}"""
|
|
|
|
return execInBash(command, '/tmp')
|
|
}
|
|
}
|
|
|
|
task schemaJar(type: Jar) {
|
|
archiveBaseName = 'schema'
|
|
from(sourceSets.main.resources) {
|
|
include 'sql/flyway/**'
|
|
include 'sql/schema/nomulus.golden.sql'
|
|
}
|
|
}
|
|
|
|
// Expose NomulusPostgreSql class to ':core' for compile, without leaking
|
|
// unnecessary dependencies to the release artifacts through ':core'.
|
|
// Jar is put in the 'compileApi' configuration.
|
|
task compileApiJar(type: Jar) {
|
|
archiveBaseName = 'compile'
|
|
from(sourceSets.main.output) {
|
|
include 'google/registry/persistence/NomulusPostgreSql**'
|
|
}
|
|
}
|
|
|
|
configurations {
|
|
compileApi
|
|
schema
|
|
integration
|
|
}
|
|
|
|
artifacts {
|
|
compileApi compileApiJar
|
|
schema schemaJar
|
|
}
|
|
|
|
publishing {
|
|
repositories {
|
|
maven {
|
|
url project.publish_repo
|
|
}
|
|
}
|
|
publications {
|
|
sqlSchemaPublication(MavenPublication) {
|
|
groupId 'google.registry'
|
|
artifactId 'schema'
|
|
version project.schema_version
|
|
artifact schemaJar
|
|
}
|
|
}
|
|
}
|
|
|
|
flyway {
|
|
def accessInfo = project.ext.getJdbcAccessInfo()
|
|
|
|
url = accessInfo.url
|
|
user = accessInfo.user
|
|
password = accessInfo.password
|
|
schemas = [ 'public' ]
|
|
|
|
locations = [ "classpath:sql/flyway" ]
|
|
}
|
|
|
|
dependencies {
|
|
def deps = rootProject.dependencyMap
|
|
|
|
compile deps['org.flywaydb:flyway-core']
|
|
|
|
runtimeOnly deps['com.google.cloud.sql:postgres-socket-factory']
|
|
runtimeOnly deps['org.postgresql:postgresql']
|
|
|
|
testCompile deps['com.google.flogger:flogger']
|
|
testRuntime deps['com.google.flogger:flogger-system-backend']
|
|
testCompile deps['com.google.guava:guava']
|
|
testCompile deps['com.google.truth:truth']
|
|
testRuntime deps['io.github.java-diff-utils:java-diff-utils']
|
|
testCompile deps['org.junit.jupiter:junit-jupiter-api']
|
|
testCompile deps['org.junit.jupiter:junit-jupiter-engine']
|
|
testCompile deps['org.testcontainers:postgresql']
|
|
testCompile deps['org.testcontainers:testcontainers']
|
|
testCompile deps['org.testcontainers:junit-jupiter']
|
|
testCompile deps['org.testcontainers:postgresql']
|
|
testCompile project(path: ':common', configuration: 'testing')
|
|
}
|
|
|
|
flywayInfo.dependsOn('buildNeeded')
|
|
flywayValidate.dependsOn('buildNeeded')
|
|
|
|
if (ext.isRestricted()) {
|
|
// Disable dangerous Flyway tasks in sandbox and production. Only allow info and validate.
|
|
tasks.findAll { task -> task.group.equals('Flyway')}.each {
|
|
if (it.name == 'flywayMigrate') {
|
|
it.doFirst {
|
|
throw new UnsupportedOperationException(
|
|
""" \
|
|
FlywayMigrate is disabled. See README.md for schema deployment
|
|
instructions.""".stripIndent())
|
|
}
|
|
} else if (it.name != 'flywayInfo' && it.name != 'flywayValidate') {
|
|
it.doFirst {
|
|
throw new UnsupportedOperationException(
|
|
"${it.name} from commandline is not allowed.")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (project.baseSchemaTag != '') {
|
|
repositories {
|
|
maven {
|
|
url project.publish_repo
|
|
}
|
|
}
|
|
dependencies {
|
|
integration "google.registry:schema:${project.baseSchemaTag}"
|
|
}
|
|
|
|
// Checks if Flyway scripts can be deployed to an existing database with
|
|
// an older release. Please refer to SchemaTest.java for more information.
|
|
task schemaIncrementalDeployTest(dependsOn: processResources, type: Test) {
|
|
useJUnitPlatform()
|
|
include 'google/registry/sql/flyway/SchemaTest.*'
|
|
classpath = configurations.testRuntimeClasspath
|
|
.plus(configurations.integration)
|
|
.plus(files(sourceSets.test.output.classesDirs))
|
|
.plus(files(sourceSets.test.output.resourcesDir))
|
|
.plus(files(sourceSets.main.output.classesDirs))
|
|
|
|
// Declare test-runtime dependency on Flyway scripts in the resources dir.
|
|
// They are not on classpath since they conflict with the base schema.
|
|
inputs.dir sourceSets.main.output.resourcesDir
|
|
|
|
// Specifies which test to run using the following property
|
|
systemProperty 'deploy_to_existing_db', 'true'
|
|
}
|
|
}
|