Preferred:
X.Y.Z_${CI-buildNo}.${gitcommit}
Ensure our POM accepts versions set externally.
for Now Maven: X.Y.Z , Tag X.Y.Z__${CI-buildNo}.${gitcommit} , Docker label ${CI-buildNo}.${gitcommit}
Thanks to Axel Fontaine & Jez Humble
- Keep as much knowledge as possible inside the POM
- Every build is a potential release, so I want to use a maven release version (i.e. not a snapshot version) for each build
- The CI machine (the one and only machine you should ever build releases on)
- Ideal traceability:
- Git commit
- Build Number from CI server
A multi-module build should have all modules use the version of the parent POM, which itself is unique for every build
We need a sane default for local development to avoid having to pass a dummy version for every single local build.
<properties>
<!-- Sane default when no revision property is passed in from the commandline -->
<revision>0-SNAPSHOT</revision>
</properties>
For services and deliverables consumed by other teams and external parties you can also easily combine this technique with semantic versioning by prefixing the version tag in your POM with the correct semantic version.
You can then automatically produce releases internally and manually updated this semantic version before each external delivery.
<version>X.Y.Z+${revision}</version>
<properties>
<!-- Sane default when no revision property is passed in from the commandline -->
<revision>0-SNAPSHOT</revision>
</properties>
<plugin>
<artifactId>maven-scm-plugin</artifactId>
<version>1.9.4</version>
<configuration>
<tag>${project.artifactId}-${project.version}</tag>
</configuration>
</plugin>
- Use Git
- Use a CI Server for build Releases & Deployment
- Maven 3.2.1+ ( Continuous Delivery friendly versions. )
- Ideally Docker so you get Versioned containers
- Wagon S3: Create an S3 Repo and only one Role/User with that access
- A Release Repository ( I use Wagon S3, could be Artifactory, Nexus etc;)
- Plugins
- maven-scm-plugin
- git-commit-id-plugin
In Maven 3.2 - it was not allowed to give a Parent pom as a version range, this was thankfully fixed in Maven 3.5.
We would like this as it's much easier to improve the POM's in the hierarchy and automatically roll them in to the next build and reduces changing this through the hierarchy.
MNG-2199 Support version ranges in parent elements
<artifactId>npiper-rest-reference</artifactId>
<version>0.0.3</version>
<packaging>jar</packaging>
<name>npiper-rest-reference</name>
<parent>
<groupId>neilpiper.me</groupId>
<artifactId>rest.microservice.base</artifactId>
<version>>0.1.0_22.2013488</version>
</parent>
This works.. Semantic version of the POM artifact and a parent version range.
<artifactId>npiper-rest-reference</artifactId>
<version>0.0.3</version>
<packaging>jar</packaging>
<name>npiper-rest-reference</name>
<parent>
<groupId>neilpiper.me</groupId>
<artifactId>rest.microservice.base</artifactId>
<!-- We can now do version ranges -->
<version>(,1.0]</version>
</parent>
But, .. when using this maven is now strict on only using a semantic version. Which is where we are now, not quite exactly what we are after but a workable compromise.
<artifactId>npiper-rest-reference</artifactId>
<version>0.0.3+${revision}</version>
<packaging>jar</packaging>
<name>npiper-rest-reference</name>
<parent>
<groupId>neilpiper.me</groupId>
<artifactId>rest.microservice.base</artifactId>
<version>(,1.0]</version>
</parent>
BUILD FAILURE:
'version' contains an expression but should be a constant. @ line 8, column 11
[FATAL] Version must be a constant
So now.. we have good parent inheritance
On a build
SemVer: 1.0.0 Build; 37 Short git commit: 7806fad
Maven Jar: 1.0.0
Git Tag: 1.0.0_37.7806fad
Docker label: 37.7806fad
github.pages - 'Description' gives the metadata of what the master build is currently at.
# If you need to update the semantic version
# The build server must provide the Revision attribute
mvn deploy scm:tag -Drevision=$BUILD_NUMBER_$GIT_SHORT_COMMIT
Travis-CI is an awesome free server, lots of features - however it won't allow you to import SSH keys in the free version.
This means an element of Jiggery pokery to do the setup:
Need to encrypt and set as environment variables:
- AWS Access (For our S3 bucket)
- Git User
- Git Auth token
I also found the scm:tag
maven command not respecting a server.xml values so as a workaround put in -D settings for environment variables.
The deploy command line then looks like this.
mvn clean install deploy scm:tag -Drevision=$(git rev-parse --short HEAD) -Dusername=${GIT_USER_NAME} -Dpassword=${
GITPW}
- RELEASE
We reduce the need for the SNAPSHOT... because every succesful deploy that has been screened through our pipeline is a prod candidate.
Thoughts.. STAGE vs. MASTER?
MAJOR version when you make incompatible API changes, MINOR version when you add functionality in a backwards-compatible manner, and PATCH version when you make backwards-compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
Software using Semantic Versioning MUST declare a public API
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.
Major version zero (0.y.z) is for initial development. Anything may change at any time. The public API should not be considered stable.
A pre-release version MAY be denoted by appending a hyphen and a series of dot separated identifiers immediately following the patch version.
Build metadata MAY be denoted by appending a plus sign and a series of dot separated identifiers immediately following the patch or pre-release version
----o-------- MASTER ------o------------o
\ / /
\-o-o-o-o-o--DEVELOPMENT---o-o--o
\ /
o---FEATURE-------o
- master (Prod)
- develop (Trunk)
- Feature (Short lived)
Short lived Feature branches for expirements.
CI hooked up to develop
and merge activities to master, hotfixes off master only if required.
Major versions could create separate branches, however it is almost worth starting a new Repo as your earlier versions should become maintenance only.
Merge the development
commit id into master
- it should be very straightforward.
git merge <commit-id>
git push
Copy the candidate from STAGING into 'RELEASES' repo.
https://docs.gitlab.com/ee/workflow/workflow.html
Errrm... No
Useful, maybe in a very large project and multiple teams.. but perhaps not for microservices
Append the git commit to a SNAPSHOT build Should only do SNAPSHOT's on Green Unit test builds
X.Y.Z+${short gitcommitid}.{CI buildNo}
Git commit hash as build meta-data for the built artifact.
ARG GIT_COMMIT=unspecified
LABEL git_commit=$GIT_COMMIT
https://blog.scottlowe.org/2017/11/08/how-tag-docker-images-git-commit-information/
docker build -t flask-local-build --build-arg GIT_COMMIT=$(git log -1 --format=%h) .
https://opencredo.com/versioning-a-microservice-system-with-git/
https://github.com/sidohaakma/semver-maven-plugin
https://blog.philipphauer.de/version-numbers-continuous-delivery-maven-docker/
https://github.com/fabric8io/docker-maven-plugin
https://trunkbaseddevelopment.com/
https://github.com/ktoso/maven-git-commit-id-plugin
https://axelfontaine.com/blog/dead-burried.html
https://axelfontaine.com/blog/maven-releases-steroids.html
https://axelfontaine.com/blog/final-nail.html
http://www.openpersuasion.org/continuous-delivery-of-microservices/
https://asardana.com/2017/11/04/microservices-database-management-using-liquibase/
(Jenkins and Branching - pipeline) https://stackoverflow.com/questions/39161285/maven-release-plugin-use-in-jenkins-pipeline
https://medium.com/production-ready/implementing-semantic-monitoring-534f16e18247