Can Liquibase or Flyway handle multi non-linear versioning scenario? - liquibase

Here is a tough one.
v1.1 has a table with index i.
v2.1 contains this table and index as well.
A bug was discovered and in v1.1.0.1 we changes the code and as a result, decided to drop the index.
We created a corresponding patch for v2.1, v2.1.0.6.
The customer applied patch v1.1.0.1 and a few weeks later upgraded to v2.1 (without patch 6)
As v2.1 code base performs better with the index we have a "broken" application.
I can't force my customers to apply the latest patch.
I can't force the developers to avoid such scenarios.
Can Liquibase or Flyway handle this scenario?

I guess these kind of problems are more organizational and not tool-specific. If you support multiple Version (A branch 1.0 and a newer one 2.0) and provide patches for both (which is totally legitimate approach - don't get me wrong here) you will probably have to provide upgrade notes for all these versions and maybe a matrix that shows from which version to which you can go (and what you can't do).
I just happened to upgrade an older version of Atlassian's Jira Bugtracker and had to find out that they do provide upgrade notes for all versions.
That would have meant to go from one version to the next to finally arrive at the latest version (I was on version 4.x and wanted to go to the latest 5.x) and obey all upgrade notes in between. (Btw, I skipped all this and set it up as a complete fresh installation to avoid this.)
Just to give you an impression, here is a page that shows all these upgrade notes:
https://confluence.atlassian.com/display/JIRA/Important+Version-Specific+Upgrade+Notes
So I guess you could provide a small script that recreates the index if somebody wants to go from version 1.1.0.1 to 2.1 and state in upgrade notes that it needs to be applied.
Since you asked if liquibase (or flyway) can support this, maybe it is helpful to mention that liquibase (I only know liquibase) has a something called preConditions. Which means you can run a changeset (resp. an sql) based on the fact that an (e.g.) index exists <indexExists>.
That could help to re-create the index if it is missing.
But since version 2.1 has already been released (before knowing that the index might be dropped in a future bugfix) there is no chance to add this feature to the upgrade procedure of version 2.1.

Liquibase will handle the drop index change across branches fine, but since you are going from a version that contains code (a drop index change) to one that does not expect that you are going to end up with your broken app state.
With liquibase, changes are completely independent of each other and independent of any versioning. You can think of the liquibase changelog as an ordered list of changes to make that each have a unique identifier. When you do an update, liquibase checks each change in turn to see if it has been ran and runs it if it has not.
Any "versioning" is purely within your codebase and branching scheme, liquibase does not care.
Imagine you start out with your 1.1.0 release that looks like:
change a
change b
change c
when you deploy 1.1.0, the customer database will know changes a,b, and c were ran.
You have v2.1 with new changesets to the end of your changelog file, so it looks like:
change a
change b
change c
change x
change y
change z
and all 2.1 customers database know that a,b,c,x,y,z are applied.
When you create 1.1.0.1 with changeset d that drops your index, you end up with this changelog in the 1.1.0.1 branch:
change a
change b
change c
change d
But when you upgrade your 1.1.0.1 customers to 2.1, liquibase just compares the defined changesets of (a,b,c,x,y,z) against the known changesets of (a,b,c,d) and runs x,y,z. It doesn't care that there is an already ran changeset of d, it does nothing about that.
The liquibase diff support can be used as a bit of a sanity check and would be able to report that there is a missing index compared to some "correct" database, but that is not something you would normally do in a production deployment scenario.

The answer may be a bit late, but I will share my experience. We also came across the same problem in our project. We dealt with it in the next way:
Since releases in our project were not made often, we marked each changeset in liquibase particular context. The value was the exact version migration (like v6.2.1-v6.2.2). We passed value to liquibase though jndi properties, so customer was able to specify them. So during upgrade customer was responsible for setting right value for migration scope for each upgrade. Liquibase context can accept list of values. So in the end, context looked like this:
context=v5.1-5.2,v5.3-5.3.1,v5.3.1-5.4,v6.2.1-v6.2.2

Related

Multi-Version Code Support in Git

I have been working on a big SQL based project that is taking an increasing amount of time and effort to maintain its versions. Lets keep it simple. I have three folders for each version of the code called Ver1, Ver2, and Ver3. All three version folders have the exact same filenames within it, but their content differs from version to version. If I make a change to a particular file in Ver3 that exists in Ver2 and Ver1, how can I use Git not to necessarily make the same changes in those other versions (not always practical due to partial rewrites for performance or logic changes), but to let me know that the other two versions of the file need to be updated in order to catchup to the Ver3? If Git isn't suited for this task, or if you have any experience with a similar issue, I would much appreciate any suggestions.

Separate sprints from versions

We'd like to split a version into several sprints, what is the best way to do this? Currently it seems to me that sprint == versions since every sprint is used as a affected version which for me doesn't feel right. What I'd like to do is the following:
I'd like to specify a version, say 1.0.0. This version is split in several sprints, A, B, C. No if a bug after the final release occurs, i like to specify as affected version 1.0.0 and not sprint A, B or C.
Is this somehow possible?
We use the YouTrack cloud hosting.
First of all, usually sprint == Fix version (the version in which this feature/task is meant to be implemented). Affected version is the one that contains the given bug (this version is implemented already). These two kinds of versions can use the same set of values (standard behaviour) or the different ones (can be changed in custom fields settings).
So, your Fix versions set of values should contain A, B and C, and the Affected versions one should contain 1.0.0. If you prefer using the same set of versions in both cases, you can leave sprint 1.0.0 (corresponding to Fix version 1.0.0).
Now, when you create a swimlane/task on an Agile Board in a selected sprint, the corresponding version is set as a Fix version (e.g. when you create a task in B sprint, the B Fix version is set to this task).
When you create a bug on an issue list, you can set Affected version as 1.0.0.
If you also want to set affected version for Bugs automatically, you can write simple workflow rule:
rule Set affected version
when issue.becomesReported() && issue.Type == {Bug} {
issue.Affected versions.add({1.0.0}});
}

Rules for incrementing patch number in semver

According to semver
"PATCH version when you make backwards-compatible bug fixes."
and
"A bug fix is defined as an internal change that fixes incorrect behavior."
With this in mind lets say I have a variable that can be called, like a color. And for some reason I need to change the color value.
v1.0.0
$color: #FFF;
v1.0.1
$color: #F0F0F0;
Now this is a variable that is defined in the API as something users can call. I haven't changed the actual variable that is called, only the value it returns. To do this I have to make a change to my code, on an API element, and I must merge this code into the production branch. But does something like this truly warrant incrementing the patch version number of your API?
The point of semantic versioning is to manage dependencies of software systems. Semantic versioning provides an organized specification to standardize this process in order to reliably track the state of these systems. As the specification states,
Once a versioned package has been released, the contents of that version MUST NOT be modified. Any modifications MUST be released as a new version.
If your changes affect the behaviour of your api (inputs or outputs) and require a release to be made then that release should be pegged to an appropriate version number. This will allow the users of the package to depend on your package with confidence. Each version will behave as expected; there should be no ambiguity.
As an example, let's say you make the change and release it but don't increment the patch number. You could potentially have two users who think they are using the same code but get different values when calling the $color api depending on when they acquired v1.0.0.
It's worth noting that there are different ways to approach getting this change to users depending on how you release your package. I can think of two possible cases:
If the package source is public, in early development of the package a quick change could be pushed to a development branch in which users could acquire changes at their own risk.
Alternatively, if the package is not open source, a pre-release could be made by appending an identifier to the version (see items 9 & 10 in the spec).
These are just a couple options. There may be others depending on your specific situation.
TL;DR Answer
Most importantly is that once v1.0.0 has been released, v1.0.0 should always behave the same way. Regardless of how trivial these changes may be they are still changes. This goes for all versions, X.Y.Z.

How to interpret merge information in TFS log output (or: how can I know which changesets is part of a build?)

First the question, then some background.
We're using Visual Studio 2008, C# 3.0 and .NET 3.5, and TFS 2008 as our VCS.
If I execute this command against our TFS database, to show information about a merge commit:
tf changeset 13469 /noprompt
I get output like this (redacted):
Changeset: 13469
User: Lasse
Date: 12. november 2010 14:06:06
Comment:
Some text here.
Items:
merge, edit $/path/to/target/filename.txt
... more merged files
... some blurb about reviewer texts, etc. nothing important/useful here
This was merged from a different path in the same database, but this information is not available here.
For instance, if I merged from $/path/to/main/ down to $/path/to/branch/, the path to the main project is not available in the merge changeset. (note, please don't say that I'm merging the wrong way, it doesn't matter in this case so I just made it simple.)
So, the question is this: Is there any way I can find out where that changeset was merged from? Which branch it came from? ... and which changeset it originated as in that branch (like 13468? 13462? 13453? ...)
Background
We haven't used much branching and merging so far, except for simple stuff like "tagging" a release.
From now on we're looking at using branching much more active, but this creates a challenge.
Let's say I open up our bug tracker, take the topmost bug, fixes it, and checks it in. This is done in one branch, let's say this is the master branch.
Now, at some point, a tester is going to verify that the hotfix we're going to release has this bug fixed, so he opens up our product and wants to verify before he starts that the bugfix has actually gone into this build.
When we didn't use branching, we simply took the changeset number of the commit that ultimately fixed a case and typed that into the case itself. Additionally, our product was built with a build-number (4th part of version number) identical to the changeset that was the latest changeset that became part of the build.
This way, the tester could simply look at the case, the version number and easily deduce if the build had that changeset or not. If the changeset number in the version number was equal to or higher than the one in the case, the changeset was part of that build.
With branches, that doesn't work. If I commit changeset X on the master branch, but forget to merge, the tester can't simply say "If I run version X or higher, I go that fix" any more.
Note that we're not using TFS work items, so there's no easy built-in way to link commits and cases.
The reason I asked about the TFS history output was that I assume that if I can see that changeset 13469 really came from another branch, and corresponds to changeset 13462 there, and the programmer has noted 13462 on the case, I can say "13462 is now part of the build, because it was merged to the right branch, became 13469, and the build output has version 13470."
In other words, I could build a tool that as part of the build looked at the history of the database and grabbed all the necessary information and stored it in a database, so that I could take cases on our ready-to-test list and compare against the version number of the executable the tester was running, and just list all cases that is both ready to test and part of that build.
So my question is really this: Does anyone have any hints to how we can solve this? Perhaps we're boneheaded and needs to be told the right way to do this, so if you got any good ideas, let me know.
I hear and feel your lament here, as we've run into the same limitation. With TFS 2008, there's no easy way to see that history. With TFS 2010, and the branch visualizer, it gets easier.
If this is something you really need, you could potentially write it yourself using the TFS API. You would have to walk your way back through the various changesets for the files. It would be relatively straightforward to code:
Get merge changeset
Get prior merge changeset
Determine merge source from the first changeset
Get history for the file between the dates of the two changesets.
I've done this manually before, but you could either do this in C# code, or, alternatively, write a PowerShell script to do this.

What version numbering scheme to use?

I'm looking for a version numbering scheme that expresses the extent of change, especially compatiblity.
Apache APR, for example, use the well known version numbering scheme
<major>.<minor>.<patch>
example: 4.5.11
Maven suggests a similar but more detailed schema:
<major>.<minor>.<patch>-<qualifier>-<build number>
example: 4.5.11-RC1-3732
Where is the Maven versioning scheme defined? Are there conventions for qualifier and build number? Probably it is a bad idea to use maven but not to follow the Maven version scheme ...
What other version numbering schemes do you know? What scheme would you prefer and why?
I would recommend the Semantic Versioning standard, which the Maven versioning system also appears to follow. Please check out,
http://semver.org/
In short it is <major>.<minor>.<patch><anything_else>, and you can add additional rules to the anything else part as seems fit to you. eg. -<qualifier>-<build_number>.
Here is the current Maven version comparison algorithm, and a discussion of it. As long as versions only grow, and all fields except the build number are updated manually, you're good. Qualifiers work like this: if one is a prefix of the other, longer is older. Otherwise they are compared alphabetically. Use them for pre-releases.
Seconding the use of semantic versioning for expressing compatibility; major is for non-backwards compatible changes, minor for backward-compatible features, patch for backward-compatible bugfixes. Document it so your library users can express dependencies on your library correctly. Your snapshots are automated and don't have to increment these, except the first snapshot after a release because of the way prefixes are compared.
Purely for completeness, i will mention the old Apple standard for version numbers. This looks like major version. minor version. bug version. stage. non-release revision. Stage is a code drawn from the set d (development), a (alpha), b (beta), or fc (final customer ship - more or less the same as release candidate, i think).
The stage and non-release revision are only used for versions short of proper releases.
So, the first version of something might be 1.0.0. You might have released a bugfix as 1.0.1, a new version (with more features) as 1.1, and a rewrite or major upgrade as 2.0. If you then wanted to work towards 2.0.1, you might start with 2.0.1d1, 2.0.1d2, on to 2.0.1d153 or whatever it took you, then send out 2.0.1a1 to QA, and after they approved 2.0.1a37, send 2.0.1b1 to some willing punters, then after 2.0.1b9 survived a week in the field, burn 2.0.1fc1 and start getting signoffs. When 2.0.1fc17 got enough, it would become 2.0.1, and there would be much rejoicing.
This format was standardised enough that there was a packed binary format for it, and helper routines in the libraries for doing comparisons.
After reading a lot of articles/QAs/FAQs/books I become to think
that [MAJOR].[MINOR].[REV] is most useful versioning schema to
describe compatibility between project version (versioning schema
for developer, does not for marketing).
MAJOR changes is backward incompatible and require changing
project name, path to files, GUIDs, etc.
MINOR changes is backward compatible. Mark introduction of new
features.
REV for security/bug fixes. Backward and forward compatible.
This versioning schema inspired by libtool versioning semantics and by articles:
http://www106.pair.com/rhp/parallel.html
NOTE: I also recommend provide build/date/custom/quality as additional info (build
number, build date, customer name, release quality):
Hello app v2.6.34 for National bank, 2011-05-03, beta, build 23545
But this info is not versioning info!
Note that a version number scheme (like x.y.0 vs. x.y) can be constrained by external factors.
Consider that announcement for Git 1.9 (Januaury 2014):
A release candidate Git v1.9-rc2 is now available for testing at the usual places.
I've heard rumours that various third-party tools do not like the two-digit version numbers (e.g. "Git 2.0") and started barfing left and right when the users install v1.9-rc1.
While it is tempting to laugh at them for their sloppy assumption, I am also practical and
do not mind calling the upcoming release v1.9.0 to help them.
If we go that route (and I am inclined to go that route at this moment), the versioning scheme will be:
The next release candidate will be v1.9.0-rc3, not v1.9-rc3;
The first maintenance release for v1.9.0 will be v1.9.1 (and Nth one be v1.9.N); and
The feature release after v1.9.0 will be either v1.10.0 or v2.0.0, depending on how big the feature jump we are looking at.