liquibase / liquibase-gradle-plugin

A Gradle plugin for Liquibase
Other
197 stars 57 forks source link

Unknown option: 'excludeObjects' #78

Closed lpsimonelli closed 1 year ago

lpsimonelli commented 3 years ago

Hey, I'm configuring the plugin like so:

liquibase {
    activities {
        main {
            changeLogFile 'src/main/resources/db/changelog/changelogs/2020-09-14_16-40-00_ids.yaml'
            url 'jdbc:postgresql://localhost:5431/test'
            username 'user'
            password 'pass'
            excludeObjects 'table:test_.*'

        }
    }
}

This yields the following error (tried using liquibase 4.0.0 & 3.8.9):

Unexpected error running Liquibase: Unknown option: 'excludeObjects'
liquibase.exception.CommandLineParsingException: Unknown option: 'excludeObjects'
        at liquibase.integration.commandline.Main.parseOptionArgument(Main.java:818)
        at liquibase.integration.commandline.Main.parseOptions(Main.java:764)
        at liquibase.integration.commandline.Main.run(Main.java:177)
        at liquibase.integration.commandline.Main.main(Main.java:129) 

I haven't been able to find much about excludeObjects. From what i see, it appears the plugin is correctly parsing it and sending it to liquibase, which seems to be rejecting it. Any clues?

dewirosalin commented 3 years ago

In my case it return this following error: Unexpected command parameter: '--excludeObjects=table:*._test

So I try to put it on liquibase.properties file and I got this following error: ERROR [liquibase.integration.commandline.Main]: Unexpected error running Liquibase: liquibase.structure.core."table liquibase.exception.UnexpectedLiquibaseException: java.lang.ClassNotFoundException: liquibase.structure.core."table at liquibase.diff.output.StandardObjectChangeFilter.parseFilter(StandardObjectChangeFilter.java:57) at liquibase.diff.output.StandardObjectChangeFilter.<init>(StandardObjectChangeFilter.java:34) at liquibase.integration.commandline.Main.doMigration(Main.java:1375) at liquibase.integration.commandline.Main.run(Main.java:302) at liquibase.integration.commandline.Main.main(Main.java:159) Caused by: java.lang.ClassNotFoundException: liquibase.structure.core."table at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) at java.base/java.lang.Class.forName0(Native Method) at java.base/java.lang.Class.forName(Class.java:315) at liquibase.diff.output.StandardObjectChangeFilter.parseFilter(StandardObjectChangeFilter.java:53) ... 4 common frames omitted

Then I try to not use wildcard on liquibase.properties and it works with some problem. It did not exclude the first and last table that I set. For example, I want to exclude several table when I generate changelog file excludeObjects: "table_1, table_2, table_3, table_4" and I run generateChangeLog command, it only exclude table_2 and table_3. table_1 and table_4 still generate in the changelog. I'm using liquibase gradle plugin version 2.0.4 and liquibase 3.9.0

stevesaliman commented 3 years ago

The fact that the plugin appears to be sending the excludeObjects to Liquibase correctly suggests that the problem is in Liquibase itself.

I tried testing this myself, but I wasn't able to reproduce the problem with Liquibase 4.3.1. Do you still have the problem in the latest version of Liquibase?

t0rum commented 3 years ago

I have simular issue

And looks like I have an idea about what's wrong. liquibase generateChangelog --excludeObjects=SPACE produces Unexpected command parameter error. liquibase --excludeObjects=SPACE generateChangelog, however, does not.

From coment here it looks like excludeObjects are inserted after command because of compatibility. And in documentation here this attribute is after command... in diff, and before command in generateChangeLog. Also, in note it's explicitly stated, that The includeObjects attribute must be passed before generateChangeLog.

Liquibase: 3.9.0, 4.1.1, 4.3.1 Plugin: 2.0.4

stevesaliman commented 3 years ago

It looks like Liquibase is inconsistent in the way it treats excludeObjects and includeObjects. They appear to be BOTH liquibase options and command parameters. It turns out there are actually a few options like that, like referenceUrl which can be specified both before and after the diff command.

This means that if you run gradlew diff it runs fine, which is why I wasn't seeing the issue when I tested it. If you run any other Liquibase command, it fails. But at least now I see the problem :-)

The larger plugin issue is that different parameters are valid for different commands, and the plugin should probably only send Liquibase the parameters that are valid for the command being run, but I don't want to maintain a mapping of commands to valid parameters, because they can change from version to version.

A better solution is probably to require command parameters to be entered on the command line like we have to do with the values needed for the tag command, and not from the action blocks like it does now. This would make a clean distinction between Liquibase options which would always come from the action blocks, and Liquibase command parameters, which would always come fro the command line. For example, we could do something like gradlew diff -PliquibaseCommandParam=excludeObjects=SPACE to have Liquibase send excludeObjects, but only if specified on the command line, and you'd only specify that property if you wanted to run the diff or generateChangelog commands. The problem with that approach is what to do when there are multiple arguments to pass. For example what if you wanted to run liquibase rollbackOneChangeSet --changeSetId=bob --force? Gradle only lets you define a property once, the plugin has no idea how many properties you'd want to define, and simply using a comma to separate the key/value pairs is dangerous because a comma might be a valid part of the value we want to send to Liquibase.

This will require some more thought...

stevesaliman commented 1 year ago

Version 2.2.0 completely changed the way we send arguments to liquibase, particularly when using Liquibase 4.4+, where I now have to maintain the mapping of commands to valid arguments, this should no longer be an issue.