Automate semver in ConcourseCI - semantic-versioning

I have a ConcourseCI pipeline that automatically increments my version number using this resource type: https://github.com/concourse/semver-resource
My resource declaration looks like this:
- name: version
type: semver
source:
driver: git
initial_version: 0.0.1
uri: {{version-repo-uri}}
branch: {{version-repo-branch}}
file: {{version-file}}
private_key: {{git-key}}
And my job looks like this:
- name: increment-version
plan:
- get: {{git-repo-name}}
trigger: true
- get: version
params: {bump: patch}
- put: version
params: {file: version/version}
So as you can see, right now I'm always bumping PATCH version. However, I'd like an easy and preferably automated way for the pipeline to increment MAJOR, MINOR, PATCH, or RC version depending on the circumstances.
Is there a git hook or something similar that will know when to bump what? Any implementation best practices when automating semver into a pipeline? Any other Concourse resource-type I should be using instead? Or is this something we should definitely leave for a human to decide? And in that case, how to easily integrate that "manual" step into a CD pipeline?
The closest thing I can think of is having a version file in my project (committed to github) with the intended version, which will set MAJOR, MINOR, PATCH numbers. The pipeline picks ups that file, uses it as a base somehow, and only increments RC numbers, but this feels incredibly error prone.
To be clear, I'm not asking how to version releases in theory, and the meanings of what major, minor, or patch are. I'm asking in practice how to implement those recommendations listed on https://semver.org/.

My solution to this problem is to tag the commits, and a script which reads the Git commit message and steps the version based on the content:
If a version tag exist on the current commit: always step PATCH.
Else:
List all commits until the previous tag.
If any message contains "step: major" then step MAJOR
Else if all messages contain "step: patch" or "step: micro" then step PATCH
Else step MINOR
This means that if the committer does not state anything in the message, then the change is assumed to be a functional change.
Tag and push the commit before the built artifact is distributed. Otherwise the next build could produce an already existing version.
Just modify the logic as needed for your use cases.

Related

GitLab's only:changes and the first commiit in a branch

I have a multi-module build with one "leading" module and one additional one. I have set things up so that the additional module is only built when either it or the build files have changed:
build:sbt:module-main:
extends: .build-sbt
build:sbt:module-a:
extends: .build-sbt
only:
changes:
- module-a/**/*
- project/**/*
- "*.yml"
- "*.sbt
The behaviour I observe is that in a pipeline resulting from pushing a new branch, both modules are always built, regardless of the actual changes. Then when new commits are pushed to the branch, the pipelines triggered off of those will behave according to my rule, i.e. module-a will only be built when there was a change that affects it.
I would expect the same behaviour from the start.
I assume that "change" means "what git thinks has changed between this branch and the branch it was based off of". Is that not what change means in this context?
While searching for another answer I discovered by accident that Gitlab is working as designed in this case.

Is there a way to run lints/code style checks on a MR diffs and post results inline?

Is there some integration available in GitLab for various linters/formatting tools?
Of course, you can always manually program a pipeline step that'd get the tested diffs, run the tool on them and fail if it encounters any issues, but that's suboptimal from usability perspective (especially for huge diffs/logs).
I.e. some review tools support posting the lint/codestyle check results inline (see https://github.com/traveloka/hubormaster as an example of what I'd ideally want to achieve).
Is anything like this possible in the current GitLab? Is there a tracking issue for this?
I believe you can use Danger for something like this. You'd need a job which does the linting / formatting, and then have a Dangerfile (with some Ruby, if you use that option), which formats the message to include the line number.
You can check the reference for their GitLab integration and options available.
Short example:
.gitlab-ci.yml:
danger:
stage: lint
image: <docker image with Danger>
script:
- danger --version
- danger --dangerfile=Dangerfile --verbose
tags:
- docker
Dangerfile:
warn("Please add something", file: "README.md", line: 1)

How to disable use branch name with GitVersion

Is there a way to disable GitVersion using the branch name?
We had an inadvertent build number increment as the result of using a branch named: 3.16-changelist
The current build version was 3.16.0
After merging that branch it was: 3.16.1
That was unexpected. Wondering if that behavior can be disabled.
Thanks.

How do I build gitlab-ci pages only on the latest semver tag? Ignoring backport tags/etc

I want to run the gitlab-ci pages job only if the project is getting a new tag pushed. I already know that you can do this with:
only:
- tags
but the issue is that, if we ever push a tag for an older version (a backported bugfix or something) then this would overwrite the pages build. We tag using SEMVER if that helps
For example, what I'm trying to avoid is having a bug fix for an earlier version replacing the gitlab pages.
Let's say on the master branch we release version 1.5.0, this will build the pages for that version, and those will be the current documentation pages.
Now let's say we had to do a bugfix for version 1.3.0 to 1.3.1, if we make that bug fix and then push it, since pages builds on tags, it would build the docs for 1.3.1 and those would replace the docs for 1.5.0, which I want to avoid somehow.
GitLab CI allows to use regex patterns with only.
In your case, if you want your pipeline to be run only if a new tag is pushed, you should think of a naming convention for tags and find a regex that will only match these new tags. This should give you some ideas:
job:
only:
- /^(\d+\.)?(\d+\.)?(\*|\d+)$/
except:
- branches
- triggers
You need the except statement to specify that the job should only run when a tag is pushed. If you just added - tags to an only statement with a regex, it would run whenever a tag is pushed + when a branch or trigger matches the regex.
One possible solution would be to incorporate an beginning stage job that compares the latest tag and only sends success if the most recent pushed tag is the latest
stages:
- compare tags
- build
- test
- deploy
job:
stage: compare tags
only:
- <semver tag regex goes here>
except:
- branches
script: 'script-that-will-compare-all-semver-tags-to-CI_COMMIT_TAG-and-fail-if-not-latest'
job:
stage: build
...
job:
stage: test
...
...
the whole job should stop if the semver comparison fails

How to determine why GitVersion chose a specific base version?

I am using GitVersion (version 3.5.3 if it matters), and getting some unexpected results; specifically the produced version has an unexpected commit count portion. Looking at the log I can see the commit count is calculated correctly, but the base version used by GitVersion is wrong (or at least not what I thought it would be).
However the log file for GitVersion is less than helpful, it just lists a series of tags, then a long list of merge bases, and at the end it just says which base version it decided to use.
Can GitVersion let me know somehow why it chose that specific base version?
I am not sure, you already checked or not; but it is explained how they calculate base version and also new versions in their documentation
UPDATE: Added main information from documentation.
Architecture
GitVersion has three distict steps for calculating versions in v3.0.
If the current commit is tagged, the tag is used and build metadata (Excluding commit count) is added. The other two steps will not execute
A set of strategies are evaluated to decide on the base version and
some metadata about that version. These strategies include
HighestReachableTag, NextVersionInConfig, MergedBranchWithVersion,
VersionInBranchName etc
The highest base version is selected, using that base version the new
version is calculated.
Visually it looks something like this:
Base Version Strategies
HighestTagBaseVersionStrategy - Finds the highest reachable tag from
the current branch
VersionInBranchBaseVersionStrategy - Extracts version information
from the branch name. eg release/3.0.0 will find 3.0.0
ConfigNextVersionBaseVersionStrategy - Returns the version from the
GitVersion.yaml file
MergeMessageBaseVersionStrategy - Finds version numbers from merge
messages. eg.
Merge 'release/3.0.0' into 'master' will return 3.0.0
FallbackBaseVersionStrategy - Always returns 0.1.0 for new
repositories
Each strategy needs to return an instance of BaseVersion which has the following properties
Source - Description of the source. eg `Merge message 'Merge
'release/3.0.0' into 'master''
ShouldIncrement - Some strategies should have the version
incremented, others do not. eg ConfigNextVersionBaseVersionStrategy
returns false, HighestTagBaseVersionStrategy returns true
SemanticVersion - SemVer of the base version strategy
BaseVersionSource - Sha of the source. Commits will be counted from
this Sha. Can be null (eg ConfigNextVersionBaseVersionStrategy
returns null)
BranchNameOverride - When useBranchName or {BranchName} is used in
the tag configuration, this allows the branch name to be changed by a
base version. VersionInBranchBaseVersionStrategy uses this to strip
out anything before the first - or /. So foo ends up being evaluated
as foo. If in doubt, just use null

Resources