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

Flyway integration issue - #5344 #5349

Merged
merged 16 commits into from Mar 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/release-notes/README.md
Expand Up @@ -3,10 +3,10 @@
doc/sphinx-guides/source/developers/making-releases.rst documents the official process for making release notes but as indicated there, we are experimenting with a process with the following goals:

- As a developer, I want to express in my pull request when an addition to the release notes will be necessary.
- As a developer, I want to be aware of changes that should be made to my dev environment after a pull request has been merged. I already know to look in `scripts/database/upgrades` if I pull the latest code from the "develop" branch for updates as described in doc/sphinx-guides/source/developers/sql-upgrade-scripts.rst but I want a place to look for non-SQL updates that are required. These could be Solr schema changes or curl commands to reload metadata blocks, for example.
- As a developer, I want to be aware of changes that should be made to my dev environment after a pull request has been merged. These could be Solr schema changes or curl commands to reload metadata blocks, for example.

# release-notes directory process

- Create a Markdown file named after your branch (assuming your branch starts with an issue number as requested in doc/sphinx-guides/source/developers/version-control.rst) such as "5053-apis-custom-homepage.md".
- In the file you created, give instructions for non-SQL upgrade steps that must be taken to run the branch in your pull request. Examples include Solr schema updates or reloading metadata blocks.
- In the file you created, give instructions for non-SQL upgrade steps that must be taken to run the branch in your pull request. Examples include Solr schema updates or reloading metadata blocks. (SQL updates are handled separately as indicated in doc/sphinx-guides/source/developers/sql-upgrade-scripts.rst.)
- At release time, gather all the files into final release notes and make a `git rm` commit to delete them to prevent clutter.
3 changes: 1 addition & 2 deletions doc/sphinx-guides/source/developers/making-releases.rst
Expand Up @@ -62,7 +62,7 @@ Create a draft release at https://github.com/IQSS/dataverse/releases/new
- The "tag version" and "title" should be the number of the milestone with a "v" in front (i.e. v4.6.2).
- For the description, follow previous examples at https://github.com/IQSS/dataverse/releases

Please note that the current process involves copying and pasting a running Google doc into release notes but we are conducting an experiment whereby developers can express the need for an addition to release notes by creating a file in ``/doc/release-notes`` containing the name of the issue they're working on. Perhaps the name of the branch could be used for the filename with ".md" appended (release notes are written in Markdown) such as ``5053-apis-custom-homepage.md``. To avoid accumulating many stale files over time, when a release is cut these files should probably be removed with ``git rm``. This experiment may help inform a future experiment having to do with improvements to our process for writing SQL upgrade scripts. See the :doc:`sql-upgrade-scripts` section for more on this topic.
Please note that the current process involves copying and pasting a running Google doc into release notes but we are conducting an experiment whereby developers can express the need for an addition to release notes by creating a file in ``/doc/release-notes`` containing the name of the issue they're working on. Perhaps the name of the branch could be used for the filename with ".md" appended (release notes are written in Markdown) such as ``5053-apis-custom-homepage.md``. To avoid accumulating many stale files over time, when a release is cut these files should probably be removed with ``git rm``.

Make Artifacts Available for Download
-------------------------------------
Expand All @@ -71,7 +71,6 @@ Upload the following artifacts to the draft release you created:

- war file (``mvn package`` from Jenkins)
- installer (``cd scripts/installer && make``)
- database migration script (see also the :doc:`sql-upgrade-scripts` section)
- other files as needed, such as an updated Solr schema

Publish Release
Expand Down
29 changes: 17 additions & 12 deletions doc/sphinx-guides/source/developers/sql-upgrade-scripts.rst
Expand Up @@ -2,40 +2,45 @@
SQL Upgrade Scripts
===================

The database schema for Dataverse is constantly evolving. As other developers make changes to the database schema you will need to keep up with these changes to have your development environment in working order. Additionally, as you make changes to the database schema, you must write SQL upgrade scripts when needed and communicate with your fellow developers about applying those scripts.
The database schema for Dataverse is constantly evolving and we have adopted a tool called Flyway to help keep your development environment up to date and in working order. As you make changes to the database schema (changes to ``@Entity`` classes), you must write SQL upgrade scripts when needed and follow Flyway file naming conventions.

Copy link
Contributor

@landreev landreev Dec 3, 2018

Choose a reason for hiding this comment

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

This may be nitpicking, but I don't fully get why it is necessary to change "upgrade scripts" and "scripts" to "SQLs". I don't see how it makes the text any better; and it's not even a proper use of the word.
?
(I can understand if you feel it is important to have the word "SQL" in there; rather than to just say "script" or "upgrade script". Still, it should probably be "SQL script" and/or "SQL upgrade script", etc. then.)

.. contents:: |toctitle|
:local:

Location of SQL Upgrade Scripts
-------------------------------

``scripts/database/upgrades`` is the directory where we keep or SQL upgrade scripts.
``src/main/resources/db/migration`` is the directory where we keep SQL upgrade scripts for Flyway to find.

How to Determine if You Need to Create or Update a SQL Upgrade Script
---------------------------------------------------------------------
In the past (before adopting Flyway) we used to keep SQL upgrade scripts in ``scripts/database/upgrades``. These scripts can still be used as reference but no new scripts should be added there.

How to Determine if You Need to Create a SQL Upgrade Script
-----------------------------------------------------------

If you are creating a new database table (which maps to an ``@Entity`` in JPA), you do not need to create or update a SQL upgrade script. The reason for this is that we use ``create-tables`` in ``src/main/resources/META-INF/persistence.xml`` so that new tables are automatically created by Glassfish when you deploy your war file.

If you are doing anything other than creating a new database table such as adding a column to an existing table, you must create or update a SQL upgrade script.

How to Create or Update a SQL Upgrade Script
--------------------------------------------
How to Create a SQL Upgrade Script
----------------------------------

We assume you have already read the :doc:`version-control` section and have been keeping your feature branch up to date with the "develop" branch.

First, check https://github.com/IQSS/dataverse/tree/develop/scripts/database/upgrades to see if a SQL upgrade script for the next release already exists. For example, if the current release is 4.9.4 and the next release will be 4.10, the script will be named ``upgrade_v4.9.4_to_v4.10.sql``. If the script exists, just add your changes to the bottom of it.
Create a new file called something like ``V4.11__5513-database-variablemetadata.sql`` in the ``src/main/resources/db/migration`` directory. Use the previously released version (4.11 in the example above) rather than what we guess will be the next released version (which is often uncertain). For the "description" you should the name of your branch, which should include the GitHub issue you are working on, as in the example above. To read more about Flyway file naming conventions, see https://flywaydb.org/documentation/migrations#naming

If no SQL upgrade script exists, look at https://github.com/IQSS/dataverse/milestones to figure out the name of the next milestone and create a script using the naming convention above.
The SQL migration script you wrote will be part of the war file and executed when the war file is deployed. To see a history of Flyway database migrations that have been applied, look at the ``flyway_schema_history`` table.

As with any task related to Dataverse development, if you need any help writing SQL upgrade scripts, please reach out using any of the channels mentioned under "Getting Help" in the :doc:`intro` section.

Please note that we are aware of the problem of merge conflicts in the SQL update script as well as how the next version number can change at any time. Please see the :doc:`making-releases` section for how we are running an experiment having to do with release notes that might help inform an improvement of our process for developing SQL upgrade scripts.
Troubleshooting
---------------

Renaming SQL Upgrade Scripts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Communicating the Need to Run SQL Updates
-----------------------------------------
Please note that if you need to rename your script (because a new version of Dataverse was released, for example), you will see the error "FlywayException: Validate failed: Detected applied migration not resolved locally" when you attempt to deploy and deployment will fail.

If you have made a pull request that contains SQL updates and that pull request is merged into the "develop" branch, you are responsible for communicating to other developers that when then pull the latest code from "develop" they must run your SQL updates. Post a message to the "dataverse-dev" mailing list at https://groups.google.com/forum/#!forum/dataverse-dev
To resolve this problem, delete the old migration from the ``flyway_schema_history`` table and attempt to redeploy.

----

Expand Down
2 changes: 1 addition & 1 deletion doc/sphinx-guides/source/installation/upgrading.rst
Expand Up @@ -7,7 +7,7 @@ Upgrading

When upgrading within Dataverse 4.x, you will need to follow the upgrade instructions for each intermediate version.

Upgrades always involve deploying the latest war file but may also include running SQL scripts and updating the schema used by Solr.
Upgrades always involve deploying the latest war file but may also include updating the schema used by Solr or other manual steps. Running database migration scripts was once required but this has been automated (see the ``flyway_schema_history`` database table to see migrations that have been run).

Please consult the release notes associated with each release at https://github.com/IQSS/dataverse/releases for more information.

Expand Down
7 changes: 7 additions & 0 deletions pom.xml
Expand Up @@ -37,6 +37,7 @@
<junit.vintage.version>5.3.1</junit.vintage.version>
<junit.platform.version>1.3.1</junit.platform.version>
<mockito.version>2.22.0</mockito.version>
<flyway.version>5.2.4</flyway.version>
<!--
Jacoco 0.8.2 seems to break Netbeans code coverage integration so we'll use 0.8.1 instead.
See https://github.com/jacoco/jacoco/issues/772 for discussion of how the XML changed.
Expand Down Expand Up @@ -251,6 +252,11 @@
<artifactId>jbcrypt</artifactId>
<version>0.3m</version>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>${flyway.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
Expand Down Expand Up @@ -626,6 +632,7 @@
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.sql</include>
<include>**/*.xml</include>
</includes>
</resource>
Expand Down
@@ -0,0 +1,39 @@
package edu.harvard.iq.dataverse.flyway;

import org.flywaydb.core.Flyway;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.sql.DataSource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Properties;

@Startup
@Singleton
Copy link
Contributor

Choose a reason for hiding this comment

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

While reading into Flyway in a Java EE context, I stumbled over the annotation
@TransactionManagement(value = TransactionManagementType.BEAN).

The explanation sounds reasonable - should this be added here?

@TransactionManagement(value = TransactionManagementType.BEAN)
class StartupFlywayMigrator {

@Resource(lookup = "jdbc/VDCNetDS")
private DataSource dataSource;

@PostConstruct
void migrateDatabase() {

Copy link
Contributor

Choose a reason for hiding this comment

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

IMHO a check on dataSource == null should be done here or a try/catch for NPEs, so the user gets a reasonable error message. That should finally result in an EJBException getting thrown, so deployment fails.

if (dataSource == null){
throw new NullPointerException("Failed to migrate, cannot connect to database");
}

Flyway flyway = Flyway.configure()
.dataSource(dataSource)
.baselineOnMigrate(true)
.load();

flyway.migrate();
}
}
Empty file.