Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Liquibase extension #6334

Merged
merged 3 commits into from
Mar 6, 2020
Merged

Liquibase extension #6334

merged 3 commits into from
Mar 6, 2020

Conversation

andrejpetras
Copy link
Contributor

@andrejpetras andrejpetras commented Dec 23, 2019

Liquibase extension

  • Add the liquibase-core and snakeyml (it is used for liquibase json, yaml format) dependencies.
  • Because Liquibase object requires a JDBC connection I created a QLiquibase wrapper with datasource instance and common liquibase methods to open and close connection after each liquibase method.
  • Multiple datasources (Datasoruce annotation) are supported (like flyway)
  • Integration tests are for xml, json, yaml and sql format
  • Liquibase has own implementation of the class-path scanner to load the Services (Interface implementation). For this I generated txt files (list of implementation classes) at build time which are used in the native run time.

I am really not sure if the QLiquibase (wrapper class) is the right name.

Update:
I renamed the QLiquibase class in Liquibase
Add the org.osgi dependency

Copy link
Member

@gsmet gsmet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woot! Thanks for this work, very cool.

I added some suggestions and questions.

@gastaldi gastaldi added the triage/needs-rebase This PR needs to be rebased first because it has merge conflicts label Dec 30, 2019
@gastaldi
Copy link
Contributor

@andrejpetras looks like you need to rebase this branch, as it has some unrelated commits. Here are the steps in case you need some help:

  1. git checkout master
  2. git pull
  3. git checkout 5957-liquibase-extension
  4. git rebase master
  5. git push -f

@andrejpetras
Copy link
Contributor Author

@andrejpetras looks like you need to rebase this branch, as it has some unrelated commits. Here are the steps in case you need some help:

  1. git checkout master
  2. git pull
  3. git checkout 5957-liquibase-extension
  4. git rebase master
  5. git push -f

@gastaldi thanks for the hint. I will do that.

@gastaldi gastaldi removed the triage/needs-rebase This PR needs to be rebased first because it has merge conflicts label Jan 1, 2020
@andrejpetras andrejpetras requested a review from gsmet January 6, 2020 18:48
@gastaldi gastaldi added the triage/needs-rebase This PR needs to be rebased first because it has merge conflicts label Jan 7, 2020
@gastaldi
Copy link
Contributor

gastaldi commented Jan 7, 2020

Looks like it needs to be rebased again :)

Copy link
Member

@gsmet gsmet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a couple of small questions and remarks.

I'm a bit worried about the instantiation of a Liquibase instance for each operation. I think that's the one remaining issue but I'm not sure what we can do about it.

config.currentDateTimeFunction.ifPresent(database::setCurrentDateTimeFunction);
config.liquibaseCatalogName.ifPresent(database::setLiquibaseCatalogName);
config.liquibaseSchemaName.ifPresent(database::setLiquibaseSchemaName);
config.liquibaseTablespaceName.ifPresent(database::setLiquibaseTablespaceName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it a good idea to create a Liquibase instance for each operation?

I'm not familiar with Liquibase but it doesn't seem right to me. I'm not sure I see another solution though as I suppose we need to close it somehow but I thought I should raise the issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gsmet I am not sure but I found another option which could be the one

I am using the data-source driver to create a liquibase database and liquibase instance is created only once.

Then we have in each Liquibase bean method this logic:
Open JDBC connection
Execute liquibase.Liquibase method
Close JDBC connection

https://github.com/andrejpetras/quarkus/blob/de19e6e3de27ce9ede78069addce066dfb8c483e/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/Liquibase.java#L65

Like hibernate-orm or quartz extension I have guess method for the liquibase database:
https://github.com/andrejpetras/quarkus/blob/de19e6e3de27ce9ede78069addce066dfb8c483e/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/Liquibase.java#L105

I am not sure if it is possible to move this part in the LiquibaseProcessor but I found this:

dataSourceDriver.produce(new DataSourceDriverBuildItem(agroalBuildTimeConfig.defaultDataSource.driver.get()));

It looks like DataSourceDriverBuildItem currently supports only a default datasource

Commit:
andrejpetras@de19e6e

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gsmet could you please check the solution in this commit? andrejpetras@de19e6e
Looks like this is the last open point in this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the JDBC connection is created for each method execution

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not mark conversation as resolved if we are discussing it :). Sorry, I was away for a bit, will have a look at your commit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks cool

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I merge it into PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gsmet please have a look at the solution.

Copy link
Contributor Author

@andrejpetras andrejpetras Feb 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR update for liquibase 3.8.7 version

   @Inject
    LiquibaseFactory liquibaseFactory;

    try (Liquibase liquibase = liquibaseFactory.createLiquibase()) {
         liquibase.update(liquibaseFactory.createContexts(),liquibaseFactory.createLabels());
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The liquibase version 3.8.7 will be release in the next few weeks
Liquibase PR: liquibase/liquibase#987

@andrejpetras
Copy link
Contributor Author

@gsmet @gastaldi

How can I fix the problem with an Azure job?
Error: The job running on agent Azure Pipelines 12 ran longer than the maximum time of 30 minutes.

@gastaldi
Copy link
Contributor

gastaldi commented Jan 9, 2020

I usually.hit the "Re-run failed checks" button in the Checks tab. You probably need special permissions if that is not available for you. Anyway I triggered that for you in this PR

@andrejpetras
Copy link
Contributor Author

I usually.hit the "Re-run failed checks" button in the Checks tab. You probably need special permissions if that is not available for you. Anyway I triggered that for you in this PR

Oh, thank you.

@andrejpetras andrejpetras requested a review from gsmet January 9, 2020 09:02
@gastaldi gastaldi removed the triage/needs-rebase This PR needs to be rebased first because it has merge conflicts label Jan 9, 2020
@andrejpetras
Copy link
Contributor Author

@gastaldi @gsmet Can I also create the documentation page?

@gastaldi
Copy link
Contributor

@andrejpetras yes please, that would be great

@andrejpetras
Copy link
Contributor Author

@gastaldi should I create separate PR for it?

@gastaldi
Copy link
Contributor

No, I'd prefer if you added to this PR

@andrejpetras
Copy link
Contributor Author

andrejpetras commented Jan 17, 2020

@gsmet @gastaldi
I added the documentation page.
The Liquibase object is now created only once, and only the JDBC connection is created for each Liquibase method.

Could you please review this PR again.

@andrejpetras andrejpetras requested a review from gastaldi January 18, 2020 12:15
@andrejpetras
Copy link
Contributor Author

@gsmet @gastaldi do we need to fix any other task or issue in this PR?

* This fixture provides access to read the expected and the actual configuration of liquibase.
* It also provides a method combining all assertions to be reused for multiple tests.
*/
@Disabled
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this class needs a Disabled annotation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's copy & paste from the Flyway extension. My understanding is that we do not use this class as a test class, but only as a test help class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gastaldi should I remove it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is not necessary I believe it's better to remove it 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
--

<1> Inject the Liquibase object if you want to use it directly
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better move the deep technical explanation here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@boring-cyborg boring-cyborg bot added area/core area/dependencies Pull requests that update a dependency file labels Jan 30, 2020
Copy link
Member

@gsmet gsmet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrejpetras I pushed a rebase with an upgrade to 3.8.7.

I added a small question about the osgi dependency. Could you have a look?

<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>${osgi.version}</version>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this strictly needed or can we use an exclusion instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gsmet cool, thanks

I believe that I add this dependency for native build because of this class:
https://github.com/liquibase/liquibase/blob/9626494719cf3f6e698bcdd76ee97b9eee1ff717/liquibase-core/src/main/java/liquibase/servicelocator/ServiceLocator.java#L7

The OSGI is used in the static block of the class

    static {
        try {
            Class<?> scanner = Class.forName("Liquibase.ServiceLocator.ClrServiceLocator, Liquibase");
            instance = (ServiceLocator) scanner.newInstance();
        } catch (Exception e) {
            try {
                if (OSGiUtil.isLiquibaseLoadedAsOSGiBundle()) {
                    Bundle liquibaseBundle = FrameworkUtil.getBundle(ServiceLocator.class);
                    instance = new ServiceLocator(new OSGiPackageScanClassResolver(liquibaseBundle), 
                            new OSGiResourceAccessor(liquibaseBundle));
                } else {
                    instance = new ServiceLocator();
                }
            } catch (Throwable e1) {
                LogService.getLog(ServiceLocator.class).severe(LogType.LOG, "Cannot build ServiceLocator", e1);
            }
        }
    }

We are not using this in the quarkus at all.
I have no idea how it is possible to substitute the static block without replacing the whole class for the native build.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrejpetras we would need to move that code to a static method and substitute that method. Maybe you can prepare another PR for Liquibase?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wait silly me, we would still need the dependency anyway so let's leave it at that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gsmet I check the 4.0.x branch of the liquibase and the class does not have osgi packages anymore. We can check the liquibase extension again after liquibase release 4.0.0 version. (This will happen in few months or more ...) But this change should not affect the liquibase extension API for developer. We can change it later in background and clean up the dependencies and also fix the native resources with a regex. We can have new task for it and I can take it to synchronize the liquibase changes in the extension.

@gsmet
Copy link
Member

gsmet commented Feb 27, 2020

Yes, the idea is to merge it today but it's in conflict with my big datasource config PR so I would like to get this one in and then update the Liquibase PR.

Andrej Petras and others added 3 commits March 6, 2020 16:42
Also include the jaxb-deployment dependency to rely on this extension to
provide everything related to JAXB/JAXP.
@boring-cyborg boring-cyborg bot added the area/infra-automation anything related to CI, bots, etc. that are used to automated our infrastructure label Mar 6, 2020
@gsmet gsmet added this to the 1.4.0 milestone Mar 6, 2020
@gsmet
Copy link
Member

gsmet commented Mar 6, 2020

I just force-pushed an update with a migration to the new datasource config stuff and some fixes.

Let's see how it goes with CI.

@gsmet
Copy link
Member

gsmet commented Mar 6, 2020

@andrejpetras I'm going to merge that one and include it in CR2. The code is totally isolated so it's not a problem.

Thanks a lot for your work and your tenacity.

@gsmet gsmet merged commit 8cda477 into quarkusio:master Mar 6, 2020
machi1990 added a commit to machi1990/quarkus that referenced this pull request Mar 6, 2020
…urceSchemaReadyBuildItem a multiple build item

The liquibase extension was merged in quarkusio#6334 which means that we have multiple possibilities of making a DB schema ready.
This makes the build item that controls whether DB schemas are ready a mutliple build item so that it can be produced by several extensions.

Without this we have the following extensions when we try to cohabite Flyway and Liquibase
```
io.quarkus.builder.ChainBuildException: Multiple producers of item class
io.quarkus.agroal.deployment.JdbcDataSourceSchemaReadyBuildItem(io.quarkus.flyway.FlywayProcessor#configureRuntimeProperties)
```

Also avoid the usage of star imports in liquibase integration tests
machi1990 added a commit to machi1990/quarkus that referenced this pull request Mar 6, 2020
…urceSchemaReadyBuildItem a multiple build item

The liquibase extension was merged in quarkusio#6334 which means that we have multiple possibilities of making a DB schema ready.
This makes the build item that controls whether DB schemas are ready a mutliple build item so that it can be produced by several extensions.

Without this we have the following extensions when we try to cohabite Flyway and Liquibase
```
io.quarkus.builder.ChainBuildException: Multiple producers of item class
io.quarkus.agroal.deployment.JdbcDataSourceSchemaReadyBuildItem(io.quarkus.flyway.FlywayProcessor#configureRuntimeProperties)
```

Also avoid the usage of star imports in liquibase integration tests
@gsmet gsmet modified the milestones: 1.4.0, 1.3.0.Final, 1.3.0.CR2 Mar 8, 2020
gsmet pushed a commit to gsmet/quarkus that referenced this pull request Mar 8, 2020
…urceSchemaReadyBuildItem a multiple build item

The liquibase extension was merged in quarkusio#6334 which means that we have multiple possibilities of making a DB schema ready.
This makes the build item that controls whether DB schemas are ready a mutliple build item so that it can be produced by several extensions.

Without this we have the following extensions when we try to cohabite Flyway and Liquibase
```
io.quarkus.builder.ChainBuildException: Multiple producers of item class
io.quarkus.agroal.deployment.JdbcDataSourceSchemaReadyBuildItem(io.quarkus.flyway.FlywayProcessor#configureRuntimeProperties)
```

Also avoid the usage of star imports in liquibase integration tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/core area/dependencies Pull requests that update a dependency file area/documentation area/infra-automation anything related to CI, bots, etc. that are used to automated our infrastructure release/noteworthy-feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants