Module versioning¶
This section focuses on best practices around module versioning. For information about how module versions are handled in CEKit take a look at descriptor documentation for modules.
Suggested versioning scheme¶
You are free to define your versioning scheme, but we strongly suggest to follow Python versioning scheme.
MAJOR.MINOR.MICRO
Although it was developed for Python - it’s easy to reuse it anywhere, including modules versioning.
Note
Its design is very similar to semantic versioning scheme. You can read about differences between these two here.
Versioning summary¶
Use
MAJOR.MINOR.MICRO
versioning scheme.Try to avoid release suffixes, but if you really need to add one of them, use PEP 440 style:
Pre-releases like Alpha, Beta, Release Candidate
Note
There is no dot before the modifier.
MAJOR.MINORaN # Alpha release: 1.0a1 MAJOR.MINORbN # Beta release: 1.0b1 MAJOR.MINORrcN # Release Candidate: 1.0rc1 MAJOR.MINOR # Final release: 1.0
-
Note
Please note the dot before the
post
modifier.MAJOR.MINOR.postN # Post-release: 1.0.post1
-
Note
Please note the dot before the
dev
modifier.MAJOR.MINORaN.devM # Developmental release of an alpha release: 1.0a1.dev1 MAJOR.MINORbN.devM # Developmental release of a beta release: 1.0b1.dev1 MAJOR.MINORrcN.devM # Developmental release of a release candidate: 1.0rc1.dev1 MAJOR.MINOR.postN.devM # Developmental release of a post-release: 1.0.post1.dev1
Custom versioning scheme¶
Although it is possible to to use a custom versioning scheme for modules, we suggest to not use it. Custom versioning scheme can lead to issues that will be hard to debug, especially when your image uses multiple module repositories and many modules.
You should be fine when you will be strictly defining modules and versions in the image descriptor, but it’s very problematic to do so. It’s even close to impossible when you do not control the modules you are consuming.
As an example, an issue can arrive when you mix versioning schemes in modules. Version that follows the suggested versioning scheme will always take precedence before a custom versioning scheme.
See also
See information about parsing module versions.
Git references vs. module versions¶
It is very common use case to place modules inside a Git repository. This is a very efficient way to share modules with others.
Git repositories are always using version of some sort, in Git we talk about ref’s. This can be a branch or a tag name. References can point to a stable release (tags) or to a work in progress (branches).
Defining module version is required in CEKit.
This means that the module definition must have the version
key.
If you reference modules stored in a Git repository we can talk about two layers of versioning:
Git references
Module versions itself
We will use a simple example to explain how we can reference modules. Here is the module descriptor.
name: "org.company.project.feature"
version: "1.0"
execute:
- script: "install.sh"
Below you can see the image descriptor snippet with only relevant content for this example.
modules:
repositories:
- name: "org.company.project"
git:
url: "https://github.com/company/project-modules"
ref: "release-3.1.0"
install:
- name: "org.company.project.feature"
Note
As you can see above, the module repository does have a different reference than 1.0
.
This is not a mistake - module repositories can contain multiple modules with different
versions. Module repositories group modules together under a single version.
Referencing stable versions of modules¶
Referencing stable versions of modules is very easy. The most important thing to remember is that in order to pin a version of module, we need to be able to pin to a specific version of the module registry itself too.
Referencing tags is a great way to ensure that we use the same code always. This means that the git repository references need to be managed carefully and proper tag management need to be preserved (no force push on tags).
Once we have tags – we can reference them in the module registry ref
just like
in the example above.
We don’t need to specify versions in the install section of modules as long as we have a single version of particular module available in repositories. If this is not the case and in your workflow you maintain multiple versions of same module – specifying version to install may be required.
Note
An example could be a module that installs OpenJDK 8 and OpenJDK 11 – name of the module is the same, these live in the same module repository, but versions differ.
If multiple versions of a particular module are available and the version will not be specified in the module installation section newest version will be installed.
Referencing development versions of modules¶
Module being currently in development should have set the version in module descriptor being the next (target) version. This will make sure the version is already set in the module and no code changes are required to actually release a module.
Assuming that the current released version of the module is 1.0
, we can develop the 2.0
version of this module, so we just define it in the module descriptor:
name: "org.company.project.feature"
version: "2.0"
execute:
- script: "install.sh"
If we develop module locally and reference the module repository using path
attribute,
no Git repository references are used at all. Modules are copied from the repository to the
target directory and used there at build time.
We can use overrides feature to point to our development work. Using overrides makes it easy to not touch the image descriptor at development time.
modules:
repositories:
# Override our module repository location to point to a local directory
- name: "org.company.project"
path: "project-modules"
Please note that we did not specify which version of the org.company.project.feature
module
should be installed. This is perfectly fine! Since we are overriding the module repository,
the only module version of the org.company.project.feature
available will be our
locally developed – 2.0
, so there is no need to define it, but of course we can do it.
If we want to share with someone our development work, we should push the module repository
to a Git repository using specific branch. This branch could be a feature branch,
or a regular development branch (for example main
), it depends on your workflow.
In our example, let’s use a feature branch: feature-dev
. Once code is pushed to this
branch, we can update our overrides.yaml
file to use it:
modules:
repositories:
- name: "org.company.project"
git:
url: "https://github.com/company/project-modules"
ref: "feature-dev"
Changelog¶
Just as any other library, a module should carry a changelog. Every release should have published list of changes made in the code. This will make it much easier to consume particular module.