Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit d349bf6

Browse files
authored
Merge branch '9.0.x' into renovate/com.gradle.common-custom-user-data-gradle-plugin-2.x
2 parents 0163c8b + 2a9fa9f commit d349bf6

File tree

174 files changed

+10561
-88
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

174 files changed

+10561
-88
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,6 @@ gradle-app.setting
2121
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
2222
# gradle/wrapper/gradle-wrapper.properties
2323
.DS_Store
24+
25+
# Database Migration Test Database File
26+
*.db

build.gradle

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ buildscript {
44
maven { url "https://plugins.gradle.org/m2/" }
55
}
66
dependencies {
7+
classpath platform("org.grails:grails-bom:$grailsVersion")
78
classpath "io.github.gradle-nexus:publish-plugin:$gradleNexusPublishPluginVersion"
8-
classpath "org.grails:grails-gradle-plugin:$grailsGradlePluginVersion"
9-
classpath "org.grails.plugins:views-gradle:$viewsGradleVersion"
9+
classpath "org.grails:grails-gradle-plugin"
10+
classpath "org.grails.plugins:views-gradle"
1011
classpath "org.asciidoctor:asciidoctor-gradle-jvm:$asciidoctorGradleVersion"
1112
}
1213
}
@@ -23,7 +24,7 @@ ext {
2324
nexusUsername = System.getenv("SONATYPE_USERNAME") ?: project.hasProperty("sonatypeOssUsername") ? project.sonatypeOssUsername : ''
2425
nexusPassword = System.getenv("SONATYPE_PASSWORD") ?: project.hasProperty("sonatypeOssPassword") ? project.sonatypeOssPassword : ''
2526
isSnapshot = project.projectVersion.endsWith("-SNAPSHOT")
26-
groovyVersion = System.getenv('CI_GROOVY_VERSION') ?: project.groovyVersion
27+
groovyVersion = System.getenv('CI_GROOVY_VERSION')
2728
}
2829

2930
ext."signing.keyId" = System.getenv("SIGNING_KEY") ?: project.hasProperty("signing.keyId") ? project.getProperty('signing.keyId') : null
@@ -51,7 +52,7 @@ if (isReleaseVersion) {
5152

5253
allprojects {
5354

54-
ext.groovyVersion = System.getenv('CI_GROOVY_VERSION') ?: project.groovyVersion
55+
ext.groovyVersion = System.getenv('CI_GROOVY_VERSION')
5556

5657
repositories {
5758
mavenCentral()

docs/build.gradle

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ dependencies {
3838
}
3939

4040
asciidoctor {
41+
inputs.dir layout.projectDirectory.dir('src/docs/asciidoc')
42+
outputs.dir layout.buildDirectory.dir('docs/manual')
4143
baseDirFollowsSourceDir()
4244
resources {
4345
from("${project.projectDir}/src/docs/asciidoc/images")
@@ -51,7 +53,13 @@ asciidoctor {
5153
'reproducible' : '',
5254
'version' : project.version,
5355
'pluginVersion' : project.version,
54-
'sourcedir' : "${project.projectDir}/src/main/groovy"
56+
'groupId' : project.group,
57+
'artifactId' : project.name,
58+
'sourcedir' : "${project.projectDir}/src/main/groovy",
59+
'migrationPluginExamplesDir' : rootProject.layout.projectDirectory.dir('grails-database-migration/src/integration-test/resources').asFile.absolutePath,
60+
'migrationPluginGroupId' : rootProject.findProject(':database-migration').group,
61+
'migrationPluginArtifactId' : rootProject.findProject(':database-migration').name,
62+
'liquibaseHibernate5Version': liquibaseHibernate5Version
5563
}
5664

5765
task fetchSource {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
=== Configuration
2+
3+
There are a few configuration options for the plugin. All configurations are prefixed with `grails.plugin.databasemigration`:
4+
5+
[options="header"]
6+
|==================================
7+
|Property |Default |Meaning
8+
|changelogLocation |`grails-app/migrations` |the folder containing the main changelog file (which can include one or more other files)
9+
|changelogFileName |`changelog.groovy` |the name of the main changelog file
10+
|changelogProperties |none |a map of properties to use for property substitution in Groovy DSL changelogs
11+
|contexts |none |A comma-delimited list of http://www.liquibase.org/manual/contexts[context] names. If specified, only changesets tagged with one of the context names will be run
12+
|dbDocLocation |`target/dbdoc` |the directory where the output from the <<ref-documentation-scripts-dbm-db-doc,dbm-db-doc>> script is written
13+
|dbDocController.enabled |`true` in dev mode |whether the /dbdoc/ url is accessible at runtime
14+
|dropOnStart |`false` |if `true` then drops all tables before auto-running migrations (if updateOnStart is true)
15+
|updateOnStart |`false` |if `true` then changesets from the specified list of names will be run at startup
16+
|updateOnStartFileName |none |the file name (relative to `changelogLocation`) to run at startup if `updateOnStart` is `true`
17+
|updateOnStartDefaultSchema |none |the default schema to use when running auto-migrate on start
18+
|updateOnStartContexts |none |A comma-delimited list of http://www.liquibase.org/manual/contexts[context] names. If specified, only changesets tagged with one of the context names will be run
19+
|updateAllOnStart |false |if `true` then changesets from the specified list of names will be run at startup for all dataSources. Useful for Grails Multitenancy with Multiple Databases (same db schema)
20+
|autoMigrateScripts |['RunApp'] |the scripts when running auto-migrate. Useful to run auto-migrate during test phase with: ['RunApp', 'TestApp']
21+
|excludeObjects |none |A comma-delimited list of database object names to ignore while performing a dbm-gorm-diff or dbm-generate-gorm-changelog
22+
|includeObjects |none |A comma-delimited list of database object names to look for while performing a dbm-gorm-diff or dbm-generate-gorm-changelog
23+
|databaseChangeLogTableName |'databasechangelog' |the Liquibase changelog record table name
24+
|databaseChangeLogLockTableName |'databasechangeloglock' |the Liquibase lock table name
25+
|==================================
26+
27+
NOTE: All the above configs can be used for multiple datasources
28+
29+
30+
*Multiple DataSource Example:*
31+
32+
If secondary dataSource named "second" is configured in application.yml
33+
[source,yaml]
34+
----
35+
include::{migrationPluginExamplesDir}/application-multiple-datasource.yml[lines=11..29]
36+
----
37+
38+
The configuration for this data source would be:
39+
[source,groovy]
40+
----
41+
grails.plugin.databasemigration.reports.updateOnStart = true
42+
grails.plugin.databasemigration.reports.changelogFileName = changelog-second.groovy
43+
----
44+
The configuration for all data sources with same db schema would be:
45+
[source,groovy]
46+
----
47+
grails.plugin.databasemigration.updateAllOnStart = true
48+
grails.plugin.databasemigration.changelogFileName = changelog.groovy
49+
----
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== DbDoc Controller
2+
3+
You can use the <<ref-documentation-scripts-dbm-db-doc,dbm-db-doc>> script to generate static HTML files to view changelog information, but another option is to use the `DbDocController` at runtime. By default this controller is mapped to `/appname/dbdoc/` but this can be customized with `UrlMappings` like any controller.
4+
5+
You probably don't want to expose this information to all of your application's users so by default the controller is only enabled in the development environment. But you can enable or disable it for any environment in `application.groovy` with the `dbDocController.enabled` config option. For example to enable for all environments (be sure to guard the URL with a security plugin in prod):
6+
7+
[source,groovy]
8+
----
9+
grails.plugin.databasemigration.dbDocController.enabled = true
10+
----
11+
12+
or to enable in the production environment:
13+
14+
[source,groovy]
15+
----
16+
environments {
17+
production {
18+
grails.plugin.databasemigration.dbDocController.enabled = true
19+
}
20+
...
21+
}
22+
----
23+
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
=== General Usage
2+
3+
After creating the initial changelog, the typical workflow will be along the lines of:
4+
5+
* make domain class changes that affect the schema
6+
* add changes to the changelog for them
7+
* backup your database in case something goes wrong
8+
* run `grails dbm-update` to update your development environment (or wherever you're applying the changes)
9+
* check the updated domain class(es) and changelog(s) into source control
10+
11+
[WARNING]
12+
=====
13+
1. When running migration scripts on non-development databases, it's important that you backup the database before running the migration in case anything goes wrong. You could also make a copy of the database and run the script against that, and if there's a problem the real database will be unaffected.
14+
2. Setting the dbCreate setting to "none" is recommended when executing the dbm migration commands. Otherwise you might run into troubles and the commands could not be executed.
15+
=====
16+
17+
To create the changelog additions, you can either manually create the changes or with the <<ref-diff-scripts-dbm-gorm-diff,dbm-gorm-diff>> script (you can also use the <<ref-diff-scripts-dbm-diff,dbm-diff>> script but it's far less convenient and requires a 2nd temporary database).
18+
19+
You have a few options with `dbm-gorm-diff`:
20+
21+
* `dbm-gorm-diff` will dump to the console if no filename is specified, so you can copy/paste from there
22+
* if you include the `--add` parameter when running the script with a filename it will register an include for the filename in the main changelog for you
23+
24+
Regardless of which approach you use, be sure to inspect generated changes and adjust as necessary.
25+
26+
27+
==== Autorun on start
28+
29+
30+
Since Liquibase maintains a record of changes that have been applied, you can avoid manually updating the database by taking advantage of the plugin's auto-run feature. By default this is disabled, but you can enable it by adding
31+
32+
[source,groovy]
33+
----
34+
grails.plugin.databasemigration.updateOnStart = true
35+
----
36+
37+
to application.groovy. In addition you must specify the file containing changes; specify the name using the `updateOnStartFileName` property, e.g.:
38+
39+
[source,groovy]
40+
----
41+
grails.plugin.databasemigration.updateOnStartFileName = 'changelog.groovy'
42+
----
43+
44+
Since changelogs can contain changelogs you'll most often just specify the root changelog, changelog.groovy by convention. Any changes that haven't been executed (in the specified file(s) or files included by them) will be run in the order specified.
45+
46+
You may optionally limit the plugin's auto-run feature to run only specific contexts. If this configuration parameter is empty or omitted, all contexts will be run.
47+
48+
[source,groovy]
49+
----
50+
grails.plugin.databasemigration.updateOnStartContexts = ['context1,context2']
51+
----
52+
53+
You can be notified when migration are run (for example to do some work before and/or after the migrations execute) by registering a "callback" class as a Spring bean. The class can have any name and package and doesn't have to implement any interface since its methods will be called using Groovy duck-typing.
54+
55+
The bean name is "migrationCallbacks" and there are currently three callback methods supported (all are optional):
56+
57+
* `beforeStartMigration` will be called (if it exists) for each datasource before any migrations have run; the method will be passed a single argument, the Liquibase `Database` for that datasource
58+
* `onStartMigration` will be called (if it exists) for each migration script; the method will be passed three arguments, the Liquibase `Database`, the `Liquibase` instance, and the changelog file name
59+
* `afterMigrations` will be called (if it exists) for each datasource after all migrations have run; the method will be passed a single argument, the Liquibase `Database` for that datasource
60+
61+
An example class will look like this:
62+
63+
[source,groovy]
64+
----
65+
package com.mycompany.myapp
66+
67+
import liquibase.Liquibase
68+
import liquibase.database.Database
69+
70+
class MigrationCallbacks {
71+
72+
void beforeStartMigration(Database Database) {
73+
...
74+
}
75+
76+
void onStartMigration(Database database, Liquibase liquibase, String changelogName) {
77+
...
78+
}
79+
80+
void afterMigrations(Database Database) {
81+
...
82+
}
83+
}
84+
----
85+
86+
Register it in resources.groovy:
87+
88+
[source,groovy]
89+
----
90+
import com.mycompany.myapp.MigrationCallbacks
91+
92+
beans = {
93+
migrationCallbacks(MigrationCallbacks)
94+
}
95+
----
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
=== Getting Started
2+
3+
*The first step is to add a dependency for the plugin in `build.gradle`:*
4+
5+
[source,groovy,subs="attributes"]
6+
----
7+
buildscript {
8+
dependencies {
9+
...
10+
classpath '{migrationPluginGroupId}:{migrationPluginArtifactId}:{version}'
11+
}
12+
}
13+
14+
dependencies {
15+
...
16+
implementation '{migrationPluginGroupId}:{migrationPluginArtifactId}:{version}'
17+
}
18+
----
19+
20+
It is also recommended to add a direct dependency to liquibase because Spring Boot overrides the one provided by this plugin
21+
22+
[source,groovy,subs="attributes"]
23+
----
24+
dependencies {
25+
...
26+
implementation "org.liquibase:liquibase-core:{liquibaseHibernate5Version}"
27+
implementation "org.liquibase.ext:liquibase-hibernate5:{liquibaseHibernate5Version}"
28+
}
29+
----
30+
31+
You should also tell Gradle about the migrations folder. If using Grails 4 or above, make sure the configuration below is BEFORE the
32+
`dependencies` configuration, so that the `sourceSets` declaration takes effect.
33+
34+
[source,groovy,subs="attributes"]
35+
----
36+
sourceSets {
37+
main {
38+
resources {
39+
srcDir 'grails-app/migrations'
40+
}
41+
}
42+
}
43+
----
44+
45+
*Typical initial workflow*
46+
47+
Next you'll need to create an initial changelog. You can use Liquibase XML or the plugin's Groovy DSL for individual files. You can even mix and match; Groovy files can include other Groovy files and Liquibase XML files (but XML files can't include Groovy files).
48+
49+
Depending on the state of your database and code, you have two options; either create a changelog from the database or create it from your domain classes. The decision tends to be based on whether you prefer to design the database and adjust the domain classes to work with it, or to design your domain classes and use Hibernate to create the corresponding database structure.
50+
51+
To create a changelog from the database, use the <<ref-rollback-scripts-dbm-generate-changelog,dbm-generate-changelog>> script:
52+
[source,groovy]
53+
----
54+
grails dbm-generate-changelog changelog.groovy
55+
----
56+
57+
or
58+
59+
[source,groovy]
60+
----
61+
grails dbm-generate-changelog changelog.xml
62+
----
63+
64+
depending on whether you prefer the Groovy DSL or XML. The filename is relative to the changelog base folder, which defaults to `grails-app/migrations`.
65+
66+
NOTE: If you use the XML format (or use a non-default Groovy filename), be sure to change the name of the file in `application.groovy` so `dbm-update` and other scripts find the file:
67+
[source,groovy]
68+
----
69+
grails.plugin.databasemigration.changelogFileName = 'changelog.xml'
70+
----
71+
72+
Since the database is already correct, run the <<ref-maintenance-scripts-dbm-changelog-sync,dbm-changelog-sync>> script to record that the changes have already been applied:
73+
[source,groovy]
74+
----
75+
grails dbm-changelog-sync
76+
----
77+
78+
Running this script is primarily a no-op except that it records the execution(s) in the Liquibase DATABASECHANGELOG table.
79+
80+
To create a changelog from your domain classes, use the <<ref-rollback-scripts-dbm-generate-gorm-changelog,dbm-generate-gorm-changelog>> script:
81+
82+
[source,groovy]
83+
----
84+
grails dbm-generate-gorm-changelog changelog.groovy
85+
----
86+
87+
or
88+
89+
[source,groovy]
90+
----
91+
grails dbm-generate-gorm-changelog changelog.xml
92+
----
93+
94+
If you haven't created the database yet, run the <<ref-update-scripts-dbm-update,dbm-update>> script to create the corresponding tables:
95+
96+
[source,groovy]
97+
----
98+
grails dbm-update
99+
----
100+
101+
or the <<ref-maintenance-scripts-dbm-changelog-sync,dbm-changelog-sync>> script if the database is already in sync with your code:
102+
103+
[source,groovy]
104+
----
105+
grails dbm-changelog-sync
106+
----
107+
108+
*Source control*
109+
110+
Now you can commit the changelog and the corresponding application code to source control. Other developers can then update and synchronize their databases, and start doing migrations themselves.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
=== GORM Support
2+
3+
The plugin's support for GORM is one feature that differentiates it from using Liquibase directly. Typically, when using Liquibase you make changes to a database yourself, and then create changesets manually, or use a diff script to compare your updated database to one that hasn't been updated yet. This is a decent amount of work and is rather error-prone. It's easy to forget some changes that aren't required but help performance, for example creating an index on a foreign key when using MySQL.
4+
5+
*create-drop, create, and update*
6+
7+
On the other end of the spectrum, Hibernate's `create-drop` mode (or `create`) will create a database that matches your domain model, but it's destructive since all previous data is lost when it runs. This works well in the very early stages of development but gets frustrating quickly. Unfortunately Hibernate's `update` mode seems like a good compromise since it only makes changes to your existing schema, but it's very limited in what it will do. It's very pessimistic and won't make any changes that could lose data. So it will add new tables and columns, but won't drop anything. If you remove a not-null domain class property you'll find you can't insert anymore since the column is still there. And it will create not-null columns as nullable since otherwise existing data would be invalid. It won't even widen a column e.g. from `VARCHAR(100)` to `VARCHAR(200)`.
8+
9+
*dbm-gorm-diff*
10+
11+
The plugin provides a script that will compare your GORM current domain model with a database that you specify, and the result is a Liquibase changeset - `dbm-gorm-diff`. This is the same changeset you would get if you exported your domain model to a scratch database and diffed it with the other database, but it's more convenient.
12+
13+
So a good workflow would be:
14+
15+
* make whatever domain class changes you need (add new ones, delete unneeded ones, add/change/remove properties, etc.)
16+
* once your tests pass, and you're ready to commit your changes to source control, run the script to generate the changeset that will bring your database back in line with your code
17+
* add the changeset to an existing changelog file, or use the `include` tag to include the whole file
18+
* run the changeset on your functional test database
19+
* assuming your functional tests pass, check everything in as one commit
20+
* the other members of your team will get both the code and database changes when they next update, and will know to run the update script to sync their database with the latest code
21+
* once you're ready to deploy to QA for testing (or staging or production), you can run all the un-run changes since the last deployment
22+
23+
*dbm-generate-gorm-changelog*
24+
25+
The <<ref-rollback-scripts-dbm-generate-gorm-changelog,dbm-generate-gorm-changelog>> script is useful for when you want to switch from `create-drop` mode to doing proper migrations. It's not very useful if you already have a database that's in sync with your code, since you can just use the <<ref-rollback-scripts-dbm-generate-changelog,dbm-generate-changelog>> script that creates a changelog from your database.

0 commit comments

Comments
 (0)