Files
nomulus/db/build.gradle
T
gbrodmanandGitHub d1e895c46b Create a "testing" subproject for faster recompilation (#3246)
This is another instance of a grouping of code that is frequently used and
referred to, but infrequently changed. If it's part of the same
compilation unit as core, then it'll need to get recompiled every time
but if we move it out into a different project we won't need to

Also moves some utility classes (required by testing) from util to
common, and removes the unnecessary core:testJar task
2026-10-07 17:58:24 +00:00

260 lines
8.5 KiB
Groovy

import org.gradle.process.internal.ExecException
// 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.
buildscript {
dependencies {
def deps = rootProject.dependencyMap
classpath deps['org.flywaydb:flyway-database-postgresql']
}
}
plugins {
id "org.flywaydb.flyway" version "12.2.0"
id 'maven-publish'
}
ext {
Set restrictedDbEnv =
[ 'sandbox', 'production' ].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).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 (rootProject.projects.keySet().contains(dbServer)) {
return getSocketFactoryAccessInfo(dbServer)
} else if (!dbServer.isEmpty()) {
return getAccessInfoByHostPort(dbServer)
} else {
// Not running flyway tasks. Return a dummy object for Flyway config.
return [ url: '', user: '', password: '' ]
}
}
// Retrieves the Cloud SQL credential for the schema deployer. Result is in
// the form of 'instancename username password'.
//
// The env parameter may be one of the following: alpha, crash, sandbox, or
// production.
//
// User must make sure that the nomulus tool can be found on PATH. An alias
// will not work.
getCloudSqlCredential = { env ->
try {
execInBash('which nomulus', '/tmp')
} catch (ExecException e) {
throw new IllegalStateException(
'nomulus not found. Make sure it is on PATH, not just an alias.')
}
def command =
"nomulus -e ${env} get_sql_credential --user schema_deployer"
return execInBash(command, project.rootDir)
}
}
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 implementation, without
// leaking unnecessary dependencies to the release artifacts through ':core'.
// Jar is put in the 'implementationApi' configuration.
task implementationApiJar(type: Jar) {
archiveBaseName = 'implementation'
from(sourceSets.main.output) {
include 'google/registry/persistence/NomulusPostgreSql**'
}
}
configurations {
implementationApi
schema
integration
}
artifacts {
implementationApi implementationApiJar
schema schemaJar
}
// Adds flyway tasks such as: flywayInfo, flywayValidate, flywayMigrate (
// deploying the schema in local repository), and flywayClean (dropping all data
// in the database). The latter two commands are disallowed in environments
// listed in ext.restrictedDbEnv.
//
// Examples:
// Get info in alpha: nom_build :db:flywayInfo --dbServer=alpha
// Deploy schema to a local test instance and override the database name:
// nom_build :db:flywayMigrate --dbServer=localhost:5432 --dbName=not-default \
// --dbUser=... --dbPassword=...
flyway {
def accessInfo = project.ext.getJdbcAccessInfo()
// Below config is required when adding an index concurrently using the
// `flywayMigrate` Gradle task. However it is currently broken and an
// `unknonw property` exception is thrown. Disabling it for now since we
// do not expect adding indexes concurrently very often.
// See also: https://github.com/flyway/flyway/issues/3858
//
// pluginConfiguration = [
// postgresqlTransactionalLock: 'false'
// ]
url = accessInfo.url
user = accessInfo.user
password = accessInfo.password
schemas = [ 'public' ]
locations = [ "classpath:sql/flyway" ]
}
dependencies {
def deps = rootProject.dependencyMap
implementation deps['org.flywaydb:flyway-core']
implementation deps['org.flywaydb:flyway-database-postgresql']
compileOnly deps['org.testcontainers:testcontainers']
runtimeOnly deps['com.google.cloud.sql:postgres-socket-factory']
runtimeOnly deps['org.postgresql:postgresql']
testImplementation deps['com.google.flogger:flogger']
testRuntimeOnly deps['com.google.flogger:flogger-system-backend']
testImplementation deps['com.google.guava:guava']
testImplementation deps['com.google.truth:truth']
testRuntimeOnly deps['io.github.java-diff-utils:java-diff-utils']
testImplementation deps['org.junit.jupiter:junit-jupiter-api']
testImplementation deps['org.junit.jupiter:junit-jupiter-engine']
testImplementation deps['org.junit.platform:junit-platform-launcher']
testImplementation deps['org.testcontainers:junit-jupiter']
testImplementation deps['org.testcontainers:postgresql']
testImplementation project(':testing')
}
test {
// When set, run FlywayDeadlockTest#validNewScript.
def deadlock_check = 'do_flyway_deadlock_check'
if (findProperty(deadlock_check)) {
systemProperty deadlock_check, findProperty(deadlock_check)
}
}
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.schemaTestArtifactsDir != '') {
dependencies {
// For schemaIncrementalDeployTest, which only uses sandbox schema
integration files("${project.schemaTestArtifactsDir}/schema.sandbox.jar")
}
// 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: processTestResources, 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'
}
}