mirror of
https://github.com/google/nomulus.git
synced 2025-07-05 18:53:34 +02:00
* Create a flyway index file and verify correctness Create an index file (flyway.txt) containing the names of all of the flyway files and verify that it is ordered and in sync with the actual contents of the flyway directory. Also provide a target (generateFlywayIndex) to automatically generate it. The purpose of flyway.txt is to cause a merge conflict in the event that two different developers add a flyway file with the same sequence number, an event which has occurred multiple times.
245 lines
7.6 KiB
Groovy
245 lines
7.6 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')
|
|
}
|
|
|
|
task generateFlywayIndex {
|
|
def flywayBase = "$projectDir/src/main/resources/sql/flyway"
|
|
def filenamePattern = /V(\d+)__.*\.sql/
|
|
|
|
def getSeqNum = { file ->
|
|
def match = file.getName() =~ filenamePattern
|
|
if (match.size() != 1) {
|
|
throw new IllegalArgumentException("Bad Flyway filename: $file")
|
|
}
|
|
return match[0][1] as int
|
|
}
|
|
|
|
doLast {
|
|
def files = new File(flywayBase).listFiles()
|
|
def indexFile = new File("${flywayBase}.txt")
|
|
indexFile.write ''
|
|
for (def file : files.sort{a, b -> getSeqNum(a) <=> getSeqNum(b)}) {
|
|
indexFile << "${file.name}\n"
|
|
}
|
|
}
|
|
}
|
|
|
|
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'
|
|
}
|
|
}
|