GithubHelp home page GithubHelp logo

liquibase / liquibase-groovy-dsl Goto Github PK

View Code? Open in Web Editor NEW

This project forked from tlberglund/groovy-liquibase

80.0 12.0 31.0 1.65 MB

The official Groovy DSL for Liquibase

License: Other

Groovy 100.00%

liquibase-groovy-dsl's Introduction

Groovy Liquibase

Maven Central Javadoc

A pluggable parser for Liquibase that allows the creation of changelogs in a Groovy DSL, rather than hurtful XML. If this DSL isn't reason enough to adopt Liquibase, then there is no hope for you. This project was started once upon a time by Tim Berglund, and is currently maintained by Steve Saliman.

Important note for Groovy 4 and build tools: This DSL is built with a transitive dependency on Groovy 3.0.15. This ensures that Gradle and Maven users don't need to include Groovy in the classpath for the DSL to work, but because Groovy moved into the Apache foundation for version 4, and changed the artifact group, users who want to use Groovy 4 need to exclude the transitive dependency. Here is an example of how users of the Liquibase Gradle plugin can do it:

  liquibaseRuntime('org.liquibase:liquibase-groovy-dsl:3.0.3') {
    exclude group: "org.codehaus.groovy", module: "groovy"
    exclude group: "org.codehaus.groovy", module: "groovy-sql"
  }
liquibaseRuntime "org.apache.groovy:groovy:4.0.5"
liquibaseRuntime "org.apache.groovy:groovy-sql:4.0.5"

News

March 12, 2023

Release 3.0.3 adds support for Liquibase up to version 4.16.1, and it adds support for Groovy 4 (#53), with thanks to Bjørn Vester (@bjornvester)

June 12, 2021

Release 3.0.2 Fixes a bug with change log parameters (#50)

April 16, 2021

Version 3.0.1 of the Liquibase Groovy DSL is now available with support for Liquibase 4.2.2.

September 5, 2020

Version 3.0.0 of the Liquibase Groovy DSL is now available with support for Liquibase 4.0.0.

As you might expect for a major release, this means some breaking changes. There are two breaking changes with this release.

Version 3.0.0 of the DSL no longer supports the 3.x releases of Liquibase. If you need to use an older version of Liquibase, you'll need an older version of the DSL.

Liquibase 4.0.0 no longer supports using absolute filenemes, so the DSL doesn't either. This change only affects changelogs that were using the include and includeAll elements with absolute paths.

June 6, 2020

Release 2.1.2 is a minor release that fixes an issue with include and includeAll changes nested inside change logs that used the previously added logicalFilePath support.

January 25, 2020

Added support for an undocumented ChangeSet attribute. The XML accepts an attribute named logicalFilePath. The actual ChangeSet property in the source code is named filePath. The Groovy DSL now supports both. The default is still to inherit the filePath from the DatabaseChangeLog. This resolves Issue #45. The bugs in Liquibase 3.7+ still remain as of Liquibase 3.8.5, so use those versions with care.

Usage

Simply include this project's jar file in your class path, along with a version of Liquibase, a version of Groovy, and your database driver, and Liquibase can parse elegant Groovy changelogs instead of ugly XML ones.

If you are running Liquibase directly from the command line using the binary distribution of Liquibase, you would need to copy the liquibase-groovy-dsl, groovy-x.y.z and database driver jar files into the lib directory of the Liquibase distribution. If you are running Liquibase using a Gradle plugin, Maven plugin, or Spring Boot, follow the documentation of the tool to add these artifacts to the classpath.

The DSL syntax is intended to mirror the Liquibase XML syntax directly, such that mapping elements and attributes from the Liquibase documentation to Groovy builder syntax will result in a valid changelog. Hence, this DSL is not documented separately from the Liquibase XML format. We will, however let you know about the minor differences or enhancements to the XML format, and help out with a couple of the gaping holes in Liquibase's documentation of the XML.

Note that wile the Groovy DSL fully supports using absolute paths for changelogs, we strongly recommend using relative paths instead. When Liquibase sees an absolute path for a changelog, all changes included by that changelog will also have absolute path names, even if the include or includeAll element used the relativeToChangeLog attribute. This will cause problems in multi-developer environments because the difference in the users' directories will cause Liquibase to think that the changes are new, and it will try to run them again.

Deprecated and Unsupported Items
  • Liquibase has a whereParam element for changes like the update change. It isn't documented in the Liquibase documentation, and I don't see any benefits of using it over the simpler where element, so it has been left out of the Groovy DSL.

  • In the Liquibase XML, you can set a sql attribute in a sqlFile change, but that doesn't make a lot of sense, so this has been disabled in the Groovy DSL.

  • The documentation mentions a referencesUniqueColumn attribute of the addForeignKeyConstraint change, but what it doesn't tell you is that it is ignored. In the code, Liquibase has marked this item as being deprecated, so we've deprecated it as well, and we let you know about it.

  • If you were using the DSL prior to version 1.0.0, a changeSet could have an alwaysRun property. This is inconsistent with Liquibase and has been replaced in 1.0.0 with runAlways

  • Prior to 1.0.0, the DSL allowed a path attribute in an include. This is no longer allowed. includeAll should be used instead.

  • Prior to 1.0.0, the DSL allowed createStoredProcedure changes. This has been replaced with createProcedure.

  • Prior to 1.0.0, the DSL allowed a File object to be passed as an attribute to loadData and loadUpdateData changes. This is no longer supported, the path to the file should be used instead.

  • Prior to 1.0.0, the DSL allowed constraint attributes to be set as methods in a constraint closure. This is inconsistent with the rest of the DSL and has been removed.

  • Prior to 2.0.0, the DSL used the resourceFilter attribute of the includeAll element to filter the changelogs included in a directory. This has been changed to filter to remain consistent with Liquibase itself.

Additions to the XML format:
  • In general, boolean attributes can be specified as either strings or booleans. For example, changeSet(runAlways: 'true') can also be written as changeSet(runAlways: true).

  • The Groovy DSL supports a simplified means of passing arguments to the executeCommand change. Instead of:

execute {
  arg(value: 'somevalue')
}

You can use this the simpler form:

execute {
  arg 'somevalue'
}
  • The sql change does not require a closure for the actual SQL. You can just pass the string like this: sql 'select some_stuff from some_table'. If you want to use the comments element of a sql change, you need to use the closure form, and the comment must be in the closure BEFORE the SQL, like this:
sql {
  comment('we should not have added this...')
  'delete from my_table'
}
  • The stop change can take a message as an argument as well as an attribute. In other words, stop 'message' works as well as the more XMLish stop(message: 'message')

  • A customPrecondition can take parameters. the XMLish way to pass them is with param(name: 'myParam', value: 'myValue') statements in the customPrecondition's closure. In the Groovy DSL, you can also have myParam('myValue')

  • The validChecksum element of a change set is not well documented. Basically you can use this when changeSet's current checksum will not match what is stored in the database. This might happen if you, for example want to reformat a changeSet to add white space. This doesn't change the functionality of the changeset, but it will cause Liquibase to generate new checksums for it. The validateChecksum element tells Liquibase to consider the checksums in the validChecksum element to be valid, even if it doesn't match what is in the database.

  • The Liquibase documentation tells you how to set a property for a databaseChangeLog by using the property element. What it doesn't tell you is that you can also set properties by loading a property file. To do this, you can have property(file: 'my_file.properties') in the closure for the databaseChangeLog.

  • Liquibase has an includeAll element in the databaseChangeLog that includes all the files in the given directory. The Groovy DSL implementation only includes groovy files, and it makes sure they are included in alphabetical order. This is really handy for keeping changes in a different file for each release. As long as the file names are named with the release numbers in mind, Liquibase will apply changes in the correct order.

  • Remember, the Groovy DSL is basically just Groovy closures, so you can use groovy code to do things you could never do in XML, such as this:

sql { """
  insert into some_table(data_column, date_inserted)
  values('some_data', '${new Date().toString()}')
"""
}
Items that were left out of the XML documentation
  • The createIndex and dropIndex changes have an undocumented associatedWith attribute. From an old Liquibase forum, it appears to be an attempt to solve the problem that occurs because some databases automatically create indexes on primary keys and foreign keys, and others don't. The idea is that you would have a change to create the primary key or foreign key, and another to create the index for it. The index change would use the associatedWith attribute to let Liquibase know that this index will already exist for some databases so that Liquibase can skip the change if we are in one of those databases. The Liquibase authors do say it is experimental, so use at your own risk...

  • The executeCommand change has an undocumented os attribute. The os attribute is a string with a list of operating systems under which the command should execute. If present, the os.name system property will be checked against this list, and the command will only run if the operating system is in the list.

  • The column element has some undocumented attributes that are pretty significant. They include:

    • valueSequenceNext, valueSequenceCurrent, and defaultValueSequenceNext, which appear to link values for a column to database sequences.
    • A column can be set auto-number if the autoIncrement attribute is set to true, but did you know that you can also control the starting number and the increment interval with the startWith and incrementBy attributes?
    • Since Liquibase 3.6, you can specify a defaultValueConstraintName.
  • The constraints element also has some hidden gems:

    • Some databases automatically create indexes for primary keys. The primaryKeyTablespace can be used to control the tablespace.
    • A foreign key can be made by using the references attribute like this: references: 'monkey(id)', It can also be done like this: referencedTableName: 'monkey', referencedColumnNames: 'id' for those who prefer to separate out the table from the column. Since Liquibase 3.5, this second form also has referencedTableCatalogName and referencedTableSchemaName attributes.
    • There is also a checkConstraint attribute, that appears to be useful for defining a check constraint, but I could not determine the proper syntax for it yet. For now, it may be best to stick to custom sql changes to define check constraints.
    • Since Liquibase 3.6, you can specify a name for a Not Null constraint with the notNullConstraintName attribute.
  • The createSequence change has n cacheSize attribute that sets how many numbers of the sequence will be fetched into memory for each query that accesses the sequence.

  • The documentation for version 3.1.1 of Liquibase mentions the new beforeColumn, afterColumn, and position attributes that you can put on a column statement to control where a new column is placed in an existing table. What the documentation leaves out is that these attributes don't work :-)

  • Version 3.4.0 of Liquibase introduced two new attributes to the includeAll element of a databaseChangeLog, both of which are undocumented. The first one is the errorIfMissingOrEmpty attribute. It defaults to true, but if it is set to false, Liquibase will ignore errors caused by invalid or empty directories and move on. The second one is the resourceFilter attribute. A resourceFilter is the name of a class that implements liquibase.changelog.IncludeAllFilter interface, which allows developers to implement sophisticated logic to decide what files from a directory should be included (in addition to the .groovy extension filter that the Groovy DSL imposes).

  • Liquibase 3.5.0 renamed the resourceFilter of includeAll to just filter. It also added resourceComparator, which lets you specify the name of a class that implements Comparator that will be used to determine how to sort files. The default is to just sort them by name.

  • Liquibase 3.4.0 added the undocumented forIndexCatalogName, forIndexSchemaName, and forIndexName attributes to the addPrimaryKey and addUniqueConstraint changes. These attributes allow you to specify the index that will be used to implement the primary key and unique constraint, respectively.

  • Liquibase 3.4.0 added the undocumented cacheSize and willCycle attributes to the alterSequence change. cacheSize sets how many numbers of the sequence will be fetched into memory for each query that accesses the sequence. willCycle determines if the sequence should start over when it reaches its maximum value.

  • Liquibase 3.5.0 changed the willCycle attribute of alterSequence to be cycle. It does the same thing, but it remains undocumented.

  • Liquibase added the context attribute to the include, includeAll, and changeLog elements. They work the same as the context attribute of a change set.

  • Liquibase 3.5 added runOrder and created attributes to the changeSet element. runOrder lets you specify that a change set should always be first or last. I have no idea what created does.

  • Liquibase 3.6 added the ignore attribute to a change set, which seems to be a way to ignore a change set.

  • Liquibase 3.6 added validate and clustered to the addUniqueConstraint change. validate tells the database to validate the constraint when it is first created, and clustered tells the database to use a clustered index.

  • Liquibase 3.6 added defaultValueConstraintName to the addDefaultValue change to give the constraint being created a name.

  • Liquibase 3.5 added commentLineStartsWith to the loadData change. By default, Liquibase treats lines in the loaded file that start with a # to be comments. commentLineStartsWith lets you change that.

  • Liquibase 3.6 added usePreparedStatements to the loadData change. When true, it tells Liquibase to use prepared statements in the inserts it generates.

  • Liquibase 3.6 added validate to the addForeignKeyConstraint change to tell the database whether to validate a new constraint when it is made.

  • Liquibase 3.6 added another way to create a view with the createView change. Previously, the SQL to create the view was in the closure of the createView element. Now you can specify a file with the SQL using the new path, encoding, and relativeToChangelogFile attributes. I have no idea what happens if you specify both a path to a file and a closure with SQL.

  • Liquibase 3.6 added a timeout to the executeCommand change. It lets you specify a command timeout in seconds, minutes, or hours. For example, to set a 2-minute timeout, you'd use 2m as the value of the timeout attribute.

  • The Liquibase XML accepts a logicalFilePath attribute for the changeSet element. The actual property in the ChangeSet class is named filePath. The Groovy DSL accepts both. The default is to inherit the file path from the DatabaseChangeLog that contains the ChangeSet.

License

This code is released under the Apache Public License 2.0, just like Liquibase 2.0.

TODOs

  • Support for the customChange. Using groovy code, liquibase changes and database SQL in a changeSet.
  • Support for extensions. modifyColumn is probably a good place to start.

liquibase-groovy-dsl's People

Contributors

carlos-hernandez avatar dsanch3z avatar dstine avatar erwinvanbrandwijk avatar ethanmdavidson avatar mbruner avatar nc-bmv avatar smulesoft avatar stevesaliman avatar tiny-dancer avatar tlberglund avatar valery1707 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

liquibase-groovy-dsl's Issues

No signature of method: liquibase.changelog.DatabaseChangeLog.include() is applicable for argument types

Trying to parse foo.groovy:

databaseChangeLog(logicalFilePath: 'foo') {
    includeAll path: 'bar/', relativeToChangelogFile: true
}

I'm getting:

groovy.lang.MissingMethodException: No signature of method: liquibase.changelog.DatabaseChangeLog.include() is applicable for argument types: (java.lang.String, java.lang.Boolean, liquibase.resource.ClassLoaderResourceAccessor, liquibase.ContextExpression, java.lang.Boolean) values: [bar/baz.groovy, true, liquibase.resource.ClassLoaderResourceAccessor(...), ...]
Possible solutions: include(java.lang.String, boolean, liquibase.resource.ResourceAccessor, liquibase.ContextExpression, liquibase.LabelExpression, java.lang.Boolean, boolean)

If I remove the logicalFilePath: 'foo' attribute it parses fine. It appears the 3.7.0+ support added in 7bffec0 misses one of the paths: the DatabaseChangeLogDelegate(Map params, databaseChangeLog) constructor. So the same appears to happen also with:

databaseChangeLog(context: 'foo') {
    includeAll path: 'bar/', relativeToChangelogFile: true
}

Property support in DSL

I'm trying to define a column in the DSL which has a defaultValueCompleted argument which will vary based on the SQL dialect chosen. In XML/Yaml change set definition this is handled with a property based on the dbms matching:

    <databaseChangeLog . . .>
        <property name="example" value="mysql-specific-statement" dbms="mysql" />
        <property name="example" value="some-other-specific-statement" dbms="h2,postgres" />
        . . .
    </databaseChangeLog>

When I convert this to Groovy DSL:

   databaseChangeLog {
       property(name: 'example', value: 'mysql-specific-statement', dbms: 'mysql')
       property(name: 'example', value: 'some-other-specific-statement', dbms: 'h2,postgres')
       // etc...
    }

Parsing fails to recognize the property entry: liquibase.exception.ChangeLogParseException: Unrecognized root element property

Ultimately, I don't need the property thing to work if there was some way to determine the dialect in use in the groovy-ness of this. For example, something like:

  databaseChangeLog {
      def myStatement
      if (someGlobal.dbms == 'mysql') {
          myStatement = 'mysql-specific-statement'
      } else {
          myStatement = 'generic-statement-that works-for-other-db-types'
      }
  }

So it feels like the support for the property element is either missing or perhaps the groovy substitution for it is just not documented (anywhere I looked).

use groovy class, declared in groovy changelog

currently next changeset would give an ClassNotFound exception

import blablabla.....

public class TaskChange implements CustomTaskChange {

private String param1;
    public String getParam1() {
      return param1;
    }

    public void setParam1(String file) {
       this.param1 = file;
     }
@Override
public void execute(Database db) throws CustomChangeException {
          doCoolStuff(db);
}

   .........other methods

}

databaseChangeLog() {

changeSet(author: 'dude', id: 'test-1') {

  customChange(class: 'TaskChange') {
    param(name: 'param1', value: 'absolutely new value')
}

}

}

it happens because ChangeSetDelegate pass liquibase classloader, but not groovy shell classloader

so class TaskChange wouldn't never be found, or I should take care to load my internal class into the parent classloader, which doesn't look nice

Support Groovy 4.0

Spring Boot 3.0 uses Groovy 4. This causes issues while using it together with liquibase-groovy-dsl which is still on Groovy 3.
To make the issue worse in Groovy 4.0, the groupId of the maven coordinates for Groovy have changed from org.codehaus.groovy to org.apache.groovy.

Where is the project's JAR?

I apologise if this is the wrong place, but I am trying to find the JAR that is mentioned in the 'usage' section ("Simply include this project's jar file in your class path").

Are you referring to the gradle-wrapper.jar?

Support sqlFile inside rollback

rollback() {
  sqlFile(path: "rollback.sql", relativeToChangelogFile: true)
}

fails because "rollback.sql" is not found.
It seems that this combination is not supported by the dsl.

Thanks!

Support Iterable where comma separated lists are expected

It's not very DSL friendly, to have to do this:

addUniqueConstraint(columnNames: 'A,B') // Ugh, hard-coded column names with commas to boot
addUniqueConstraint(columnNames: ['A', 'B'].join(',')) // Data driven is better, but must convert to String with commas

When it would be more natural to do this:

addUniqueConstraint(columnNames: ['A', 'B']) //  Data driven, no need to mess with commas! But, doesn't work, seems to pass the toString() result '[A, B]' to Liquibase, which interprets as '[A' and 'B]'.

Only using columnNames and addUniqueConstraint as examples, there are numerous such places in the Liquibase DSL.

SQLFileChange ChangeLogParameters is null but The xml configuration is not empty

When XML is configured, variables can be replaced correctly. However, when it is Groovy, SQLFileChange fetches changeLogParameters as empty. Debugger code finds that Groovy's Parser does not set changeLogParameters

version:
liquibase: 3.8.9
liquibase-groovy-dsl: 2.1.2

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
username=root
password=123456
changeLogFile=database/db-main-changelog.groovy
parameter.my21=my777777777
parameter.my22=my999999999
delete from s_test  where id in('818c4d04-c949-4096-a9cf-c412fe8c344b');

insert into s_test (id, login_name, login_password, user_name, user_number, phone_number, email, is_valid, remark, created_by, created_date, modified_by, modified_date)
values ('818c4d04-c949-4096-a9cf-c412fe8c344b', 'admin-test004', '${my21}', '${my22}', null, '123456789', '[email protected]', '1', 'test', 'anonymousUser', 1577691791394, 'anonymousUser', 1577691791394);
SQLFileChange
public String getSql() {
        String sql = super.getSql();
        if (sql == null) {
            InputStream sqlStream;
            try {
                sqlStream = openSqlStream();
                if (sqlStream == null) {
                    return null;
                }
                String content = StreamUtil.getStreamContents(sqlStream, encoding);
                if (getChangeSet() != null) {
                    // important:  groovy is null, xml is not null
                    ChangeLogParameters parameters = getChangeSet().getChangeLogParameters();
                    if (parameters != null) {
                        content = parameters.expandExpressions(content, getChangeSet().getChangeLog());
                    } 
                }
                return content;
            } catch (IOException e) {
                throw new UnexpectedLiquibaseException(e);
            }
        } else {
            return sql;
        }
    }

This method is called when the XML is parsed

DatabaseChangeLog
 protected ChangeSet createChangeSet(ParsedNode node, ResourceAccessor resourceAccessor) throws ParsedNodeException {
        ChangeSet changeSet = new ChangeSet(this);
        // important: This method is called to set variables when the XML is configured
        changeSet.setChangeLogParameters(this.getChangeLogParameters());
        changeSet.load(node, resourceAccessor);
        return changeSet;
  }

can I switch database type

hi,

is it pissible to use to same changelog files for different database?

my application support multiple databases. on XML days, we used to use dbms type and conversion required.. Based on that single chngelog been applied to all databases and liquibase did all necessary convertions..

is the same be done with dsl? if yes, how?

Compiling the DSL

Ok, so I'm new to this game :(

I have downloaded the ZIP and I don't see any classes, so I am guessing I have to build/compile this using gradle?

> gradle -v


Gradle 2.10

Build time: 2015-12-21 21:15:04 UTC
Build number: none
Revision: 276bdcded730f53aa8c11b479986aafa58e124a6

Groovy: 2.4.4
Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM: 1.6.0_45 (Sun Microsystems Inc. 20.45-b01)
OS: Windows 7 6.1 amd64

> gradle (?)

FAILURE: Build failed with an exception.

What went wrong:
A problem occurred configuring root project 'liquibase-groovy-dsl-master'.

If I put the URL in a browser, I get a 404

On the basis that it seems I have a certificate issue, I downloaded the jfrog JAR (https://jcenter.bintray.com/com/jfrog/bintray/gradle/gradle-bintray-plugin/0.6/) and altered the build.gradle:

dependencies {
  files('../libs/gradle-bintray-plugin-0.6.jar')

>gradle

FAILURE: Build failed with an exception.

  • Where:
    Build file 'D:\tidev\tools\liquibase-3.4.2\liquibase-groovy-dsl-master\build.gradle' line: 19

What went wrong:
A problem occurred evaluating root project 'liquibase-groovy-dsl-master'.

  • Plugin with id 'com.jfrog.bintray' not found.

Any clues?

I do not use Maven, so all I am after is (I guess) a build that creates a JAR or I need to JAR the classes built.

We will be using liquibase from the command line, rather than via gradle or gradlew.
This assumes we have the DSL in a jar such as liquibase-groovy.jar in the current directory.

liquibase --changeLogFile=a.groovy update

Any help gratefully received.

include xml changelogs is impossible

it's currently impossible to include xml changelog files due to in-code restrictions

databaseChangeLog() {
include(file: 'sequences.changelog.xml', relative: true)
include(file: 'tables.changelog.xml', relative: true)
......
}

liquibase.exception.SetupException: DatabaseChangeLog: 'relative' is not a supported attribute of the 'include' element

it's required to use includeAll method instead, but this method includes only groovy file, and I need xml in my project

Missing groovy support for some XML equivalents

I've been fiddling with some groovy code to see what is/isn't supported in comparison to XML change sets. Mostly it is OK, but for some commands, I get, for example,

''Unexpected error running Liquibase: ChangeSet 'test-mergeColumns': 'mergeColumns' is not a valid element of a ChangeSet''

My code (failures only) is

databaseChangeLog() {

def varTableName="testA"
def varAuthor="ra"

changeSet( author: varAuthor, id: "test-mergeColumns"){
        mergeColumns( tableName="testA", 
                 column1Name:"col3", joinString:":", column2Name:"col4",            finalColumnName:"MERGEDCOL", finalColumnType:"VARCHAR(20)")
}

changeSet( author: varAuthor, id: "test-addNotNullConstraint"){
        addNotNullConstraint( tableName:varTableName, columnName:"col2", columnDataType="CHAR")
}

changeSet( author: varAuthor, id: "test-renameColumn"){
        renameColumn(tableName: varTableName, oldColumnName: "col4", newColumnName:"FACTOR", columnDataType="INT")
}

changeSet( author: varAuthor, id: "test-addColumn"){
        addColumn(tableName: varTableName, type:"timestamp")
}

changeSet( author: varAuthor, id: "test-executeCommand", failOnError: false){
            executableCommand() {
                executable("something.groovy") {
                    arg "--x"
                    arg "--y:1" 
        }
}

changeSet( author: varAuthor, id: "test-loadData"){
        loadData(tableName: "testA", path:"test.csv")
}

changeSet( author: varAuthor, id: "test-loadUpdateData"){
        loadUpdateData(tableName: "testA", primaryKey: "col1", path:"test.csv")
}

}

Any comments gratefully received?

How can I load extensions

Hi

I see the examples has loadData, but liquibase complains 'loadData' is not a valid element of a ChangeSet

How can load extensions?

Support Groovy 4

Currently, this library builds with Groovy 2.4 and works fine with Groovy 3.x. However, with Groovy 4, it fails with a ChangeLogParseException with text Unrecognized root element.

For instance, given the following script:

databaseChangeLog {
    changeSet(id: '123', author: 'me') {
        createTable(tableName: 'my_table') {
            column(name: 'id', type: 'BIGINT', autoIncrement: true) {
                constraints(primaryKey: true, primaryKeyName: 'id_PK')
            }
        }
    }
}

Running with Groovy 4, it fails with: Caused by: liquibase.exception.ChangeLogParseException: Unrecognized root element changeSet. It works with Groovy 3.

Full stack trace (from a Spring Boot application)

Caused by: liquibase.exception.ChangeLogParseException: Unrecognized root element changeSet
	at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?]
	at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[?:?]
	at jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:?]
	at java.lang.reflect.Constructor.newInstance(Constructor.java:490) ~[?:?]
	at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:73) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.reflection.CachedConstructor.doConstructorInvoke(CachedConstructor.java:60) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrap.callConstructor(ConstructorSite.java:86) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:57) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:263) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:277) ~[groovy-4.0.5.jar:4.0.5]
	at liquibase.parser.ext.GroovyLiquibaseChangeLogParser$_getChangeLogMethodMissing_closure3.doCall(GroovyLiquibaseChangeLogParser.groovy:94) ~[liquibase-groovy-dsl-3.0.2.jar:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke(ClosureMetaMethod.java:88) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaClassImpl.invokeMissingMethod(MetaClassImpl.java:926) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:1428) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaClassImpl.doInvokeMethod(MetaClassImpl.java:1350) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1103) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1142) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1009) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:620) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:603) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeOnDelegationObjects(ClosureMetaClass.java:391) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:328) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1009) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:318) ~[groovy-4.0.5.jar:4.0.5]
	at Script1$_run_closure1.doCall(Script1.groovy:2) ~[?:?]
	at Script1$_run_closure1.doCall(Script1.groovy) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:279) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1009) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:39) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:130) ~[groovy-4.0.5.jar:4.0.5]
	at liquibase.parser.ext.GroovyLiquibaseChangeLogParser.processDatabaseChangeLogRootElement(GroovyLiquibaseChangeLogParser.groovy:134) ~[liquibase-groovy-dsl-3.0.2.jar:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:342) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:63) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:49) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:171) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:203) ~[groovy-4.0.5.jar:4.0.5]
	at liquibase.parser.ext.GroovyLiquibaseChangeLogParser$_getChangeLogMethodMissing_closure3.doCall(GroovyLiquibaseChangeLogParser.groovy:91) ~[liquibase-groovy-dsl-3.0.2.jar:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke(ClosureMetaMethod.java:88) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaClassImpl.invokeMissingMethod(MetaClassImpl.java:926) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:1428) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaClassImpl.doInvokeMethod(MetaClassImpl.java:1350) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1103) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1142) ~[groovy-4.0.5.jar:4.0.5]
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1009) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:318) ~[groovy-4.0.5.jar:4.0.5]
	at Script1.run(Script1.groovy:1) ~[?:?]
	at Script1$run.call(Unknown Source) ~[?:?]
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) ~[groovy-4.0.5.jar:4.0.5]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:130) ~[groovy-4.0.5.jar:4.0.5]
	at liquibase.parser.ext.GroovyLiquibaseChangeLogParser.parse(GroovyLiquibaseChangeLogParser.groovy:62) ~[liquibase-groovy-dsl-3.0.2.jar:?]
	at liquibase.Liquibase.getDatabaseChangeLog(Liquibase.java:380) ~[liquibase-core-4.15.0.jar:?]
	at liquibase.Liquibase.getDatabaseChangeLog(Liquibase.java:365) ~[liquibase-core-4.15.0.jar:?]
	at liquibase.Liquibase.lambda$update$1(Liquibase.java:222) ~[liquibase-core-4.15.0.jar:?]
	at liquibase.Scope.lambda$child$0(Scope.java:180) ~[liquibase-core-4.15.0.jar:?]
	at liquibase.Scope.child(Scope.java:189) ~[liquibase-core-4.15.0.jar:?]
	at liquibase.Scope.child(Scope.java:179) ~[liquibase-core-4.15.0.jar:?]
	at liquibase.Scope.child(Scope.java:158) ~[liquibase-core-4.15.0.jar:?]
	at liquibase.Liquibase.runInScope(Liquibase.java:2414) ~[liquibase-core-4.15.0.jar:?]
	at liquibase.Liquibase.update(Liquibase.java:209) ~[liquibase-core-4.15.0.jar:?]
	at liquibase.Liquibase.update(Liquibase.java:195) ~[liquibase-core-4.15.0.jar:?]
	at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:314) ~[liquibase-core-4.15.0.jar:?]
	at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:269) ~[liquibase-core-4.15.0.jar:?]
	at org.springframework.boot.autoconfigure.liquibase.DataSourceClosingSpringLiquibase.afterPropertiesSet(DataSourceClosingSpringLiquibase.java:46) ~[spring-boot-autoconfigure-2.7.4.jar:2.7.4]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) ~[spring-beans-5.3.23.jar:5.3.23]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.3.23.jar:5.3.23]
	... 18 more

From what I can tell, there is a small difference in the way Groovy 4 finds methods from the owner and delegates.

Before, it would look at the resolve strategy, and then attempt to find the method in either the owner or the delegate. If not found in the first, it would look in the second.

Now, it "delegates" the method call to the owner or delegate directly. For instance, if the resolve strategy is set to OWNER_FIRST, it will call the method on the owner. If not found, it will then invoke the methodMissing method on the metaClass. For Liquibase, it causes getChangeLogMethodMissing to be called on the owner, which then throws the ChangeLogParseException because the method is not on the owner - it is on the delegate. But because this exception isn't caught by Groovy (only MissingMethodException are caught), it just fails immediately without trying the delegate.

Don't know if that makes sense as I found it a bit hard to explain.

In our case, we can't run Liquibase in isolation as it is part of our application, which also depends on Groovy through Spock. We are trying to upgrade the whole stack to work with Groovy 4. However, I have a patch ready that fixes the problem for us.

Update Groovy dependencies

The current dependencies org.codehaus.groovy:groovy and groovy-dsl are not compatible with OpenJDK 14 and break Spring Boot application execution at startup with:

java.lang.NoClassDefFoundError: Could not initialize class org.codehaus.groovy.vmplugin.v7.Java7
at org.codehaus.groovy.vmplugin.VMPluginFactory.(VMPluginFactory.java:43)
at org.codehaus.groovy.reflection.GroovyClassValueFactory.
...

and

java.lang.NoClassDefFoundError: Could not initialize class org.codehaus.groovy.reflection.ReflectionCache
at org.codehaus.groovy.runtime.dgmimpl.NumberNumberMetaMethod.(NumberNumberMetaMethod.java:33) ~[groovy-2.5.8.jar:2.5.8]
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
...

Replacing the dependencies manually with groovy:3.0.3 and groovy-dsl:3.0.3
seems to work without issues.

Support placeholders in imports

I have tested a XML-File like this:

<databaseChangeLog
  xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
         http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
    
    <!-- defaults that may be overwritten with commandLine parameters -->
    <property name="targetSystem" value="MSY" />
    <property name="targetVersion" value="1.2.0" />
    
    <include file="changeLog/${targetSystem}/alter${targetSystem}-DB-${targetVersion}.xml" />

</databaseChangeLog>

transformed to groovy:

databaseChangeLog() {
    property(name:'targetSystem', value:'MSY')
    property(name:'targetVersion', value:'1.2.0')
   
    include(file: 'changeLog/${targetSystem}/alter${targetSystem}-DB-${targetVersion}.xml')
}

but then i get:

Unexpected error running Liquibase: changeLog/${targetSystem}/alter${targetSystem}-DB-${targetVersion}.xml does not exist

replacing single with double quotes does not work either as groovy complains that there is no property called targetSystem.
Did i use the property closures right, there's only documentation about the property(file:'') syntax.

changeSet logicalFilePath not recognized

There's a logicalFilePath attribute to changeSet elements (see the changeSetAttributes attribute group):

http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd

It appears to map to ChangeSet.filePath property. Neither of logicalFilePath or filePath appears recognized by the Groovy DSL:

    changeSet(id: '1', author: 'saly', logicalFilePath: 'c1') {
        // ...
    }
    changeSet(id: '2', author: 'holy', logicalFilePath: 'c2') {
        // ...
    }

I'm trying this in the context of CORE-3549 where I'm trying to convert any change log source to XML for use in runtime package without extra dependencies.

I'm also evaluating the conversion of Liquibase XML to Groovy DSL (for being more readable source) using XSLT. In all cases, I need to preserve/set the logicalFilePath to datachangeLogs and individual changeSets, the latter of which doesn't appear supported in the Groovy DSL, currently.

includeAll in changeLog throwing FileNotFoundException

Hello,

I'm having a tough time getting my includeAll working properly. When the includeAll method in the DatabaseChangeLogDelegate class attempts to locate files based on params.path, it's using an absolute path, not the classpath, so it throws exceptions like such:

java.io.FileNotFoundException: C:\java\persons\classpath:\db\versions

// This is using the absolute path
new File(params.path).eachFileMatch(~/.*.groovy/) { file ->
    if (resourceFilter == null || resourceFilter.include(file.path)) {
        files << file.path
    }
}

I have tried just about every combination of my primary changelog (below), but no matter what, I still get exceptions.

// classpath:/db/changeLog-master.groovy:

// doesn't work
databaseChangeLog {
    includeAll(path : "versions", relativeToChangelogFile: true)
}

// doesn't work
databaseChangeLog {
    includeAll(path : "classpath:/db/versions")
}

// this gets past the initial File matcher, but then fails when trying to locate the folder when the 
// parser starts actually searching the classpath
databaseChangeLog {
    includeAll(path : "src/main/resources/db/versions")
}

Attempting to fork the code and set the File matcher to use the classpath instead of absolute paths fails all of the tests, since the tests are testing the parserFactory, and not the File matcher.

Am I not configuring this properly, or is this an actual bug?

Thanks in advance for any assistance!

Cannot configure plugin with maven

I'm having a problem when executing the update goal. I get the following error:

[ERROR] Failed to execute goal org.liquibase:liquibase-maven-plugin:3.5.1:update (default) on project liquibase-sample-mvn: Error setting up or running Liquibase: Cannot find parser that supports src/main/resources/liquibase/masterChangelog.groovy -> [Help 1]

For some reason the GroovyLiquibaseChangeLogParser is not been registered in the ChangeLogParserFactory. When I inspect the parsers a cannot see the groovy one.

Here is my pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.liquibase-sample</groupId>
    <artifactId>liquibase-sample-mvn</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>Liquibase sample mvn</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>

        <!-- Database -->
        <postgres.version>9.1-901-1.jdbc4</postgres.version>
        <dbh2.version>1.4.192</dbh2.version>
        <liquibase.version>3.5.1</liquibase.version>
        <liquibase-groovy.version>1.2.1</liquibase-groovy.version>
    </properties>

    <dependencies>
        <!-- Database -->
        <dependency>
            <groupId>postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>${postgres.version}</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>${dbh2.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-groovy-dsl</artifactId>
            <version>${liquibase-groovy.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.liquibase</groupId>
                <artifactId>liquibase-maven-plugin</artifactId>
                <version>${liquibase.version}</version>
                <configuration>
                    <propertyFile>db.properties</propertyFile>
                </configuration>
                <executions>
                    <execution>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>update</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Any ideas?

Please provide example documentation to integrate in Spring Boot Liquibase

Trying to integrate like this:
build.gradle
dependencies {
implementation 'org.liquibase:liquibase-core'
implementation 'org.liquibase:liquibase-groovy-dsl:2.1.1'
runtimeOnly 'com.h2database:h2'
runtime 'org.liquibase:liquibase-core'
runtime 'org.liquibase:liquibase-groovy-dsl:2.1.1'
}

In Spring Boot application.properties
spring.liquibase.change-log=classpath:db/changelog/changeset0002.groovy

This groovy file has the changelog DSL.
But doing gradle bootRun throws following error:

Error creating bean with name 'liquibase' defined in class path resource [org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: Invocation of init method failed; nested exception is java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1

Support Serializing (generateChangeLog/Diff)

Trying to output a existing database or a diff to groovy does not work at the moment. I guess that feature has not been implemented yet?

$ ./liquibase --changeLogFile=output.groovy --logLevel=warning generateChangeLog
Unexpected error running Liquibase: java.lang.RuntimeException: No serializers associated with the filename or extension 'output.groovy'

SEVERE 27.01.17 10:28: liquibase: java.lang.RuntimeException: No serializers associated with the filename or extension 'output.groovy'
liquibase.exception.LiquibaseException: liquibase.command.CommandExecutionException: java.lang.RuntimeException: No serializers associated with the filename or extension 'output.groovy'
        at liquibase.integration.commandline.CommandLineUtils.doGenerateChangeLog(CommandLineUtils.java:265)
        at liquibase.integration.commandline.Main.doMigration(Main.java:1011)
        at liquibase.integration.commandline.Main.run(Main.java:188)
        at liquibase.integration.commandline.Main.main(Main.java:103)
Caused by: liquibase.command.CommandExecutionException: java.lang.RuntimeException: No serializers associated with the filename or extension 'output.groovy'
        at liquibase.command.AbstractCommand.execute(AbstractCommand.java:13)
        at liquibase.integration.commandline.CommandLineUtils.doGenerateChangeLog(CommandLineUtils.java:263)
        ... 3 more
Caused by: java.lang.RuntimeException: No serializers associated with the filename or extension 'output.groovy'
        at liquibase.serializer.ChangeLogSerializerFactory.getSerializer(ChangeLogSerializerFactory.java:55)
        at liquibase.diff.output.changelog.DiffToChangeLog.print(DiffToChangeLog.java:74)
        at liquibase.command.GenerateChangeLogCommand.run(GenerateChangeLogCommand.java:54)
        at liquibase.command.AbstractCommand.execute(AbstractCommand.java:8)
        ... 4 more

'createIndex' is not a valid element of a ChangeSet

When running update with a Groovy file generated by generateChangeLog, I get this error:

Execution failed for task ':update'.

liquibase.exception.LiquibaseException: Unexpected error running Liquibase: ChangeSet '1470069484023-159': 'createIndex' is not a valid element of a ChangeSet

NPE on customChange

I got an issue with customChange dsl

my changelog is pretty trivial

databaseChangeLog() {

changeSet(author: 'pupseg', id: 'test-1') {
customChange(class: 'my.VelocityTaskChange') {
param(name: 'param1', value: 'param1value')
}
}

public class VelocityTaskChange implements CustomTaskChange
do nothing right now

error on execution caused because customChange field is not initialized on liquibase validation stage and configureCustomChange() method called for null customChange object

liquibase.exception.UnexpectedLiquibaseException: liquibase.exception.CustomChangeException: java.lang.NullPointerException
at liquibase.change.custom.CustomChangeWrapper.validate(CustomChangeWrapper.java:144)
at liquibase.changelog.visitor.ValidatingVisitor.visit(ValidatingVisitor.java:117)
at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:73)
at liquibase.changelog.DatabaseChangeLog.validate(DatabaseChangeLog.java:199)
at liquibase.Liquibase.update(Liquibase.java:206)
at liquibase.Liquibase.update(Liquibase.java:190)
at liquibase.integration.commandline.Main.doMigration(Main.java:1096)
at liquibase.integration.commandline.Main.run(Main.java:180)
at liquibase.integration.commandline.Main.main(Main.java:99)
Caused by: liquibase.exception.CustomChangeException: java.lang.NullPointerException
at liquibase.change.custom.CustomChangeWrapper.configureCustomChange(CustomChangeWrapper.java:253)
at liquibase.change.custom.CustomChangeWrapper.validate(CustomChangeWrapper.java:142)
... 8 more
Caused by: java.lang.NullPointerException
at liquibase.util.ObjectUtil.getMethods(ObjectUtil.java:136)
at liquibase.util.ObjectUtil.getWriteMethod(ObjectUtil.java:125)
at liquibase.util.ObjectUtil.setProperty(ObjectUtil.java:50)
at liquibase.change.custom.CustomChangeWrapper.configureCustomChange(CustomChangeWrapper.java:248)
... 9 more
liquibase.exception.ValidationFailedException: Validation Failed:
1 changes have validation errors
liquibase.exception.UnexpectedLiquibaseException: liquibase.exception.CustomChangeException: java.lang.NullPointerException

    at liquibase.changelog.DatabaseChangeLog.validate(DatabaseChangeLog.java:206)
    at liquibase.Liquibase.update(Liquibase.java:206)
    at liquibase.Liquibase.update(Liquibase.java:190)
    at liquibase.integration.commandline.Main.doMigration(Main.java:1096)
    at liquibase.integration.commandline.Main.run(Main.java:180)
    at liquibase.integration.commandline.Main.main(Main.java:99)

Question: Integration with Spring?

Can't get this working with spring-shell.

In my applicationContext.xml i declare liquibase

<bean id="liquibase" class="liquibase.integration.spring.SpringLiquibase" depends-on="postgresService">
        <property name="dataSource" ref="psqlDataSource"/>
        <property name="changeLog" value="com.example.db.DbChangelog_master"/>
        <property name="defaultSchema" value="${postgres.schema}"/>
    </bean>

The jar is also included in my classpath, but everytime i get the exception

Caused by: liquibase.exception.UnknownChangelogFormatException: Cannot find parser that supports com.example.db.DbChangelog_master
    at liquibase.parser.ChangeLogParserFactory.getParser(ChangeLogParserFactory.java:70)
    at liquibase.Liquibase.getDatabaseChangeLog(Liquibase.java:226)
    at liquibase.Liquibase.update(Liquibase.java:202)
    at liquibase.Liquibase.update(Liquibase.java:192)
    at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:434)
    at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:391)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
    ... 13 more

Liquibase 4.23.x compatiblity

Hi,
When using liquibase 4.23.2 I have the following error:

Caused by: groovy.lang.MissingMethodException: No signature of method: liquibase.changelog.DatabaseChangeLog.include() is applicable for argument types: (String, Boolean, liquibase.integration.spring.SpringResourceAccessor...) values: [liquibase/patches/IRIS-27434-API-Possibility-to-configure-list-of-Roles-of-a-Project-per-Instance.groovy, ...]
Possible solutions: include(java.lang.String, boolean, boolean, liquibase.resource.ResourceAccessor, liquibase.ContextExpression, liquibase.LabelExpression, java.lang.Boolean, boolean), include(java.lang.String, boolean, boolean, liquibase.resource.ResourceAccessor, liquibase.ContextExpression, liquibase.Labels, java.lang.Boolean, boolean), include(java.lang.String, boolean, boolean, liquibase.resource.ResourceAccessor, liquibase.ContextExpression, liquibase.Labels, java.lang.Boolean, liquibase.changelog.DatabaseChangeLog$OnUnknownFileFormat), include(java.lang.String, boolean, boolean, liquibase.resource.ResourceAccessor, liquibase.ContextExpression, liquibase.Labels, java.lang.Boolean, liquibase.changelog.DatabaseChangeLog$OnUnknownFileFormat, liquibase.changelog.DatabaseChangeLog$ModifyChangeSets)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:72)
at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:48)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at org.liquibase.groovy.delegate.DatabaseChangeLogDelegate.include(DatabaseChangeLogDelegate.groovy:197)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:342)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1006)
at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
at liquibase.Script1$_run_closure1.doCall(Script1.groovy:4)
at liquibase.Script1$_run_closure1.doCall(Script1.groovy)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:279)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1006)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:39)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:130)
at liquibase.parser.ext.GroovyLiquibaseChangeLogParser.processDatabaseChangeLogRootElement(GroovyLiquibaseChangeLogParser.groovy:130)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:342)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:63)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:49)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:171)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:203)
at liquibase.parser.ext.GroovyLiquibaseChangeLogParser$_getChangeLogMethodMissing_closure3.doCall(GroovyLiquibaseChangeLogParser.groovy:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke(ClosureMetaMethod.java:88)
at groovy.lang.MetaClassImpl.invokeMissingMethod(MetaClassImpl.java:923)
at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:1412)
at groovy.lang.MetaClassImpl.doInvokeMethod(MetaClassImpl.java:1334)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1087)
at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1142)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1006)
at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
at liquibase.Script1.run(Script1.groovy:3)
at liquibase.Script1$run.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:130)
at liquibase.parser.ext.GroovyLiquibaseChangeLogParser.parse(GroovyLiquibaseChangeLogParser.groovy:59)

Could please check ??

Create and drop procedure improvements.

Since the 1.0.2 version of the plugin I detected that the createProcedure changeset had problems finding the files that contains the SQL script with the code of the procedure.

Also, the dropProcedure changeset is not available in the actual DSL.

See the pull requests for more details.

How to constraints in createTable

master.groovy

databaseChangeLog {
    changeSet(id: 1, author: 'baike') {
        createTable(tableName: 'test', remarks: 'test') {
            column(name: 'id', type: 'bigint', autoIncrement: true) {
                constraints {
                    nullable(false)
                    primaryKey(true)
                }
            }
            column(name: 'name', type: 'varchar(255)') {
                constraints(nullable: true)
            }
        }
        rollback {
            dropTable(tableName: 'test')
        }
    }

}

Execution script gradle validate

Unexpected error running Liquibase: Error: ChangeSet '1', createTable change: Setting constraint attributes in nested closures is no longer supported. Use an attribute map instead.
liquibase.exception.ChangeLogParseException: Error: ChangeSet '1', createTable change: Setting constraint attributes in nested closures is no longer supported. Use an attribute map instead.
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:83)
	at org.codehaus.groovy.reflection.CachedConstructor.doConstructorInvoke(CachedConstructor.java:77)
	at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrap.callConstructor(ConstructorSite.java:84)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:59)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:238)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:250)
	at org.liquibase.groovy.delegate.ConstraintDelegate.constraints(ConstraintDelegate.groovy:57)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:352)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:68)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:157)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:169)
	at Script1$_run_closure1$_closure2$_closure3$_closure5.doCall(Script1.groovy:5)
	at Script1$_run_closure1$_closure2$_closure3$_closure5.doCall(Script1.groovy)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:264)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:41)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
	at org.liquibase.groovy.delegate.ColumnDelegate.column(ColumnDelegate.groovy:74)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:352)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:68)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:157)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:177)
	at Script1$_run_closure1$_closure2$_closure3.doCall(Script1.groovy:4)
	at Script1$_run_closure1$_closure2$_closure3.doCall(Script1.groovy)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:264)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:41)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
	at org.liquibase.groovy.delegate.ChangeSetDelegate.makeColumnarChangeFromMap(ChangeSetDelegate.groovy:588)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:210)
	at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:59)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:157)
	at org.liquibase.groovy.delegate.ChangeSetDelegate.createTable(ChangeSetDelegate.groovy:264)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:352)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:68)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:157)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:177)
	at Script1$_run_closure1$_closure2.doCall(Script1.groovy:3)
	at Script1$_run_closure1$_closure2.doCall(Script1.groovy)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:264)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:41)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
	at org.liquibase.groovy.delegate.DatabaseChangeLogDelegate.changeSet(DatabaseChangeLogDelegate.groovy:149)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:352)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:68)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:157)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:177)
	at Script1$_run_closure1.doCall(Script1.groovy:2)
	at Script1$_run_closure1.doCall(Script1.groovy)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:264)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:41)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
	at liquibase.parser.ext.GroovyLiquibaseChangeLogParser.processDatabaseChangeLogRootElement(GroovyLiquibaseChangeLogParser.groovy:136)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:352)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:68)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:157)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:185)
	at liquibase.parser.ext.GroovyLiquibaseChangeLogParser$_getChangeLogMethodMissing_closure3.doCall(GroovyLiquibaseChangeLogParser.groovy:93)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke(ClosureMetaMethod.java:84)
	at groovy.lang.MetaClassImpl.invokeMissingMethod(MetaClassImpl.java:951)
	at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:1279)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1227)
	at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1125)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
	at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:68)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:157)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:169)
	at Script1.run(Script1.groovy:1)
	at Script1$run.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
	at liquibase.parser.ext.GroovyLiquibaseChangeLogParser.parse(GroovyLiquibaseChangeLogParser.groovy:64)
	at liquibase.Liquibase.getDatabaseChangeLog(Liquibase.java:217)
	at liquibase.Liquibase.validate(Liquibase.java:1552)
	at liquibase.integration.commandline.Main.doMigration(Main.java:1176)
	at liquibase.integration.commandline.Main.run(Main.java:191)
	at liquibase.integration.commandline.Main.main(Main.java:129)

Use triple-quoted strings in serializer

When running the generateChangeLog command on an oracle database, I run into a couple of issues:

  1. objects with multiple lines, e.g.
  changeSet(id: '1551192953968-7', author: 'edavidson (generated)') {
    createView(fullDefinition: true, viewName: 'FR_TEXT_COUNT') {
      "CREATE OR REPLACE FORCE VIEW FR_TEXT_COUNT (APPID, ITEMID, TYPE, PANEL, COUNT) AS select appid,itemid,type,panel,count(1) from fr_text_long
      group by appid,itemid,type,panel"
    }
  }
  1. objects with double quotes, e.g.
changeSet(id: '1551192755372-1043', author: 'edavidson (generated)') {
   createView(fullDefinition: true, viewName: 'HOLSCHED') {
     "CREATE OR REPLACE FORCE VIEW HOLSCHED (PERNO, DAYNO, HOLDATE, DESCR) AS SELECT "PERNO","DAYNO","HOLDATE","DESCR" FROM PAYROLL.HOLSCHED"
   }
 }

It seems to me that we could solve both these problems by using triple-quoted strings when writing text bodies in the serializer, e.g:

serializedChange = """\
${serializedChange} {
  '''${textBody}'''
}"""

triple-single quotes would be easier here, but could still fail because oracle escapes single-quotes by using two (''), so when a string begins or ends with an escaped single-quote:

select 'the last char in this string is a single quote: ''' from dual;

the changelog generation would fail. A more robust solution would be to properly escape the text based on the sql dialect, but that's probably more trouble than it's worth. Triple-quoted strings should catch most cases, and it's easy enough to fix the generated changelog manually in the few cases that are missed.

Let me know your thoughts.

initialization of Change property defaults not consistent with liquibase core

With xml you can not simply use the OutputChange, but that's no problem in groovy as we are not limited by the xml validation:

databaseChangeLog() {
    changeSet(id: '0', author:'unknown', runAlways: true, runOnChange: true){
        output(message: 'hello world', target: "STDOUT")
    }
}

however the liquibase.change.core.OutputChange does not require the target property to be set

    @DatabaseChangeProperty(description = "Target for message. Possible values: STDOUT, STDERR, FATAL, WARN, INFO, DEBUG. Default value: STDERR", exampleValue = "STDERR")
    public String getTarget() {
        if (target == null) {
            return "STDERR";
        }
        return target;
    }

if i extend the OutputChange class and override the getSerializedObjectNamespace method to use a different xml namespace, i can use it in xml and do not need to provide the target.
If i use the output change with groovy-dsl directly (and without target) i get the following error:

$ ./liquibase --logLevel=INFO --changeLogFile=changeLog/root.groovy update
INFO 07.02.17 09:23: liquibase: Successfully acquired change log lock
INFO 07.02.17 09:23: liquibase: Reading from S83CFLS.LIQUIBASE_LOG
SEVERE 07.02.17 09:23: liquibase: changeLog/root.groovy: changeLog/root.groovy::0::unknown: Change Set changeLog/root.groovy::0::unknown failed.  Error: Unknown target:
INFO 07.02.17 09:23: liquibase: changeLog/root.groovy::0::unknown: Successfully released change log lock
Unexpected error running Liquibase: Unknown target:

SEVERE 07.02.17 09:23: liquibase: changeLog/root.groovy::0::unknown: Unknown target:
liquibase.exception.MigrationFailedException: Migration failed for change set changeLog/root.groovy::0::unknown:
     Reason: liquibase.exception.UnexpectedLiquibaseException: Unknown target:
        at liquibase.changelog.ChangeSet.execute(ChangeSet.java:619)
        at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:51)
        at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:79)
        at liquibase.Liquibase.update(Liquibase.java:214)
        at liquibase.Liquibase.update(Liquibase.java:192)
        at liquibase.integration.commandline.Main.doMigration(Main.java:1130)
        at liquibase.integration.commandline.Main.run(Main.java:188)
        at liquibase.integration.commandline.Main.main(Main.java:103)
Caused by: liquibase.exception.UnexpectedLiquibaseException: Unknown target:
        at liquibase.change.core.OutputChange$1.generate(OutputChange.java:73)
        at liquibase.sqlgenerator.core.RuntimeGenerator.generateSql(RuntimeGenerator.java:19)
        at liquibase.sqlgenerator.core.RuntimeGenerator.generateSql(RuntimeGenerator.java:10)
        at liquibase.sqlgenerator.SqlGeneratorChain.generateSql(SqlGeneratorChain.java:30)
        at liquibase.sqlgenerator.SqlGeneratorFactory.generateSql(SqlGeneratorFactory.java:225)
        at liquibase.executor.AbstractExecutor.applyVisitors(AbstractExecutor.java:25)
        at liquibase.executor.jvm.JdbcExecutor.access$500(JdbcExecutor.java:36)
        at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:295)
        at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:55)
        at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:113)
        at liquibase.database.AbstractJdbcDatabase.execute(AbstractJdbcDatabase.java:1277)
        at liquibase.database.AbstractJdbcDatabase.executeStatements(AbstractJdbcDatabase.java:1259)
        at liquibase.changelog.ChangeSet.execute(ChangeSet.java:582)
        ... 7 more

So i debuged the code and found that target is a empty string (that s the way the class initializes the property) and not null or "STDERR".
When watching the setTarget in OutputChange, i can see that the ChangeFactory initializes properties with the exampleValue from the annotation when it calls createChangeParameterMetadata but it seems not to be called when used from the groovy-dsl plugin.

So this looks like a combination of a unclear default value in OutputChange and inconsistent behavior of the groovy-dsl plugin that may affect other Changes too.

'dropTable' is not a valid element of a ChangeSet

Hello!

I created very simple changeset:

databaseChangeLog {
    changeSet(id: '1', author: 'oleksii') {
        rollback {
            dropTable(schemaName = "public", tableName = "website_city")
        }
    }
}

I run rollback using gradle plugin:
gradle rollbackCount -PliquibaseCommandValue=1

But I am getting next exception:

Unexpected error running Liquibase: ChangeSet '1': 'dropTable' is not a valid element of a ChangeSet
liquibase.exception.ChangeLogParseException: ChangeSet '1': 'dropTable' is not a valid element of a ChangeSet
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)

Here are Gradle dependencies with versions that I am using in the project:

liquibaseRuntime 'org.liquibase:liquibase-gradle-plugin:2.0.1'
liquibaseRuntime 'org.liquibase:liquibase-core:3.6.1'
liquibaseRuntime 'org.liquibase:liquibase-groovy-dsl:2.0.1'
liquibaseRuntime 'org.codehaus.groovy:groovy:2.5.7'

Not sure whether I`m doing something wrong or it is a bug in the plugin itself. Can you help me with this?

question: how to refactor?

The problem I'm trying to solve is the following:

  • Every table in my database must have some technical fields: id, date and user (for update and delete)
  • I don't whant to copy-paste this column definitions from one createTable to another

How can I factor this peace of "code" for reuse? The only thing I came up with is to define a closure and then call it like this:

createTable(...) {
  techColumns.delegate = delegate
  techColumns('primary_key_constraint_name')
}

But this isn't very ellegant :(

Context for being able to use autocomplete of the dsl in different IDEs

I'm trying to use the DSL since it's opens up the posibilites more than using XML. For the XML we had the XSD which allows you to type faster (although still XML) the changelogs/changesets. In this DSL I'd like to do the same, but I couldn't set a context around the IDE so it knows what to suggest.

I'm reporting this not as a bug but as improvement.

Some unit tests always fail on windows

Some of the tests rely on absolute paths to changelog files. However, in order to verify that a path is absolute, they rely on assertions like

assertTrue includedChangeLogFile.startsWith("/")

which fails on windows, where the path will start with the drive name, e.g. 'C:/'.

Instead of working with strings, these tests should take advantage of java.io.File in order to work correctly across systems.

Tests which are affected by this:
org.liquibase.groovy.delegate.DatabaseChangeLogDelegateIncludeTests
org.liquibase.groovy.delegate.DatabaseChangeLogDelegateIncludeTests

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.