|
| 1 | +--- |
| 2 | +uid: understanding-ci-builds |
| 3 | +--- |
| 4 | +# Understanding Continuous Integration (CI) Builds |
| 5 | +The use of a version specific to CI builds is unique to the Constrained Semantic |
| 6 | +Version spec, in particular the CSemVer-CI support. These versions are NOT compatible |
| 7 | +with a CSemVer but are compatible with a SemVer. If that's not confusing enough the |
| 8 | +way in which they are constrained makes things a LOT more complicated. This task and |
| 9 | +the [Ubiquity.NET.Versioning](https://www.nuget.org/packages/Ubiquity.NET.Versioning) |
| 10 | +library BOTH got the behavior wrong initially! This article will hopefully make sense |
| 11 | +out of things... |
| 12 | + |
| 13 | +## Examples |
| 14 | +Hopefully examples will make things more clear: |
| 15 | + |
| 16 | +1) `v5.0.4--ci.123456.ZZZ` |
| 17 | + * This is a CI build based on a release `v5.0.3` |
| 18 | + * That is, it is ordered AFTER a release of `v5.0.3` |
| 19 | + * It is also a SemVer 'pre-release' and therefore ordered BEFORE |
| 20 | + `v5.0.4`. |
| 21 | + * Thus this CI build is ordered BETWEEN the previously released `v5.0.3` and |
| 22 | + the as of yet unreleased `v5.0.4`. |
| 23 | + * Using this task the `ZZZ` indicates this is a developer local build. No |
| 24 | + guarantees of uniqueness are provided for such versions across machines. |
| 25 | + * It is possible for two developers to achieve the same build version for two |
| 26 | + completely distinct builds. |
| 27 | + * Though in practical terms this is a very unlikely statistical |
| 28 | + probability. |
| 29 | +2) 'v5.0.4-beta.0.1.ci.123456.ZZZ` |
| 30 | + * This is a CI Build based on a previously released "pre-release" version |
| 31 | + `v5.0.3-alpha.0.1` |
| 32 | + * As with the previous example this is ordered AFTER the release it is based on |
| 33 | + and BEFORE the Patch+1 version (`v5.0.4-beta.0.1`). |
| 34 | + |
| 35 | +## lifetime scope of a CI Build |
| 36 | +The lifetime of a CI build is generally very short and once a version is released |
| 37 | +all CIs that led up to that release are essentially moot. |
| 38 | + |
| 39 | +## CI versions are POST-RELEASE based |
| 40 | +CI versioning falls into one of two categories: |
| 41 | +1) Never had a release to base anything on |
| 42 | + 1) Intermediate builds while developing the very first release of a product. |
| 43 | +2) A build that occurs ***AFTER*** something was released, but ***BEFORE*** the |
| 44 | + next formal release. Such builds usually include: |
| 45 | + 1) Local Developer Builds |
| 46 | + 2) Pull Request builds (Automated "buddy" builds) |
| 47 | + 3) "CI" builds |
| 48 | + 1) Formal builds of the code base either from any PR or on a schedule (usually |
| 49 | + nightly builds) |
| 50 | + |
| 51 | +For CSemVer-CI, which are based on SemVer, the pre-release syntax is all that is |
| 52 | +available to indicate the status of a CI build. Additionally, a CSemVer[-CI] supports |
| 53 | +representation as an "ordered" version number OR as a File Version Quad. The file |
| 54 | +version quad keeps things 'interesting'... |
| 55 | + |
| 56 | +### String forms of versions |
| 57 | +As a string a CI build is represented with pre-release component of 'ci' or '-ci'. The |
| 58 | +latter is used if the base version already includes pre-release data (The 'double dash' |
| 59 | +trick) |
| 60 | + |
| 61 | +`5.0.5--ci.BuildIndex.BuildName' |
| 62 | + |
| 63 | +#### As a SemVer |
| 64 | + |
| 65 | +| Value | Description |
| 66 | +|-------|------------| |
| 67 | +| 5 | Major portion of the version | |
| 68 | +| 0 | Minor portion of the version | |
| 69 | +| 5 | Patch portion of the version | |
| 70 | +| 'ci.BuildIndex.BuildName' | pre-release data indicating a CI build where the version is patch+1 | |
| 71 | + |
| 72 | +Since this is a pre-release it is ordered BEFORE an actual release of (5.0.5) and |
| 73 | +AFTER any release of (5.0.4). |
| 74 | + |
| 75 | +#### As a CSemVer-CI |
| 76 | +As a CSemVer-CI that is interpreted a bit differently than you might expect, in |
| 77 | +particular the 'Major.Minor.Patch' are what is known as the "Patch+1" form. That is |
| 78 | +the `base build` version for this CSemVer-CI version is v5.0.4! That is what is used |
| 79 | +as the defining value of a build as it isn't known what the actual release version |
| 80 | +will be (it hasn't released yet!). |
| 81 | + |
| 82 | +SemVer has rules regarding compatibilities with respect to changes in elements of a |
| 83 | +version. Thus, any versioning strategy that follows those rules does NOT have a fixed |
| 84 | +(next version). So CSemVer-CI uses a POST release strategy where the |
| 85 | +`<major>.<minor>.<patch>` is actually `<major>.<minor>.<patch+1>` to guarantee it is |
| 86 | +ordered AFTER the release it is based on but BEFORE the next possible release. The |
| 87 | +actual release value may use an even greater value, but CSemVer-CI doesn't care. |
| 88 | + |
| 89 | +The CSemVer-CI spec is silent on the point of what happens if the base build |
| 90 | +version patch is already `9999` (The max allowed value). Does it roll over to |
| 91 | +0 and +1 to minor? While that does maintain ordering it pushes the boundaries |
| 92 | +of the meaning of the version numbers. Though it is a rather common scenario for |
| 93 | +a build to require a major version update when only some small portion of things |
| 94 | +is actually incompatible and the rest is largely backwards compatible. It just doesn't |
| 95 | +guarantee it anymore. |
| 96 | + |
| 97 | +This task assumes it is proper to roll over into the next form. (In fact it relies |
| 98 | +on the ordered integral form of the version and increments that, until it reaches the |
| 99 | +maximum) |
| 100 | + |
| 101 | +### Ordered Version |
| 102 | +Ordered versions are a concept unique to Constrained Semantic versions. The constraints |
| 103 | +applied to a SemVer allow creation of an integral value for all versions, except CI |
| 104 | +builds. Ignoring CI builds for the moment, the ordered number is computed from the |
| 105 | +values of the various parts of a version as they are constrained by the CSemVer spec. |
| 106 | +The math involved is not important for this discussion. Just that each Constrained |
| 107 | +Version is representable as a distinct integral value (63 bits actually). A CSemVer-CI |
| 108 | +build has two elements the base build and the additional 'BuildIndex' and 'BuildName' |
| 109 | +components. This means the string, File version and ordered version numbers are |
| 110 | +confusingly different for a CI build. The ordered version number does NOT account for |
| 111 | +CI in any way. It is ONLY able to convert to/from a CSemVer. Thus, a CSemVer-CI has |
| 112 | +an ambiguous conversion. Should it convert the Patch+1 form in a string or the |
| 113 | +base build number?. |
| 114 | + |
| 115 | +### File Version Quad and UINT64 |
| 116 | +A file Version quad is a data structure that is blittable as an unsigned 64 bit value. |
| 117 | +Each such value is broken down into four fields (thus the 'quad' in the common naming) |
| 118 | +that are 16 bits each (unsigned). These versions are common in Windows platforms as |
| 119 | +that is the form used in resource file versioning. (Though this form is used in other |
| 120 | +cases on other platforms as well.) Such a value is really the ordered version number |
| 121 | +shifted left by one bit and the LSB used to indicate a CI build with odd numbered |
| 122 | +values to represent a CI build. Thus, a File Version of a CI build is derived from |
| 123 | +the base version of the CSemVer-CI. The ordering of such values is the same as an |
| 124 | +integral conversion. (or, most likely, a simple re-interpret style cast to an unsigned |
| 125 | +64 bit value). The LSB reserved to indicate a CI ensures that a CI file Version is |
| 126 | +ordered AFTER a non-CI File version for the same base build. This is the most |
| 127 | +confusing and subtle aspect of the versioning and where this task an related library |
| 128 | +went wrong in early releases. |
| 129 | + |
| 130 | +>[!IMPORTANT] |
| 131 | +> To be crystal clear, the FILEVERSION for a CI build comes from the ***base build*** |
| 132 | +> version as it includes a bit that, when set, indicates a CI build, but also a |
| 133 | +> greater integral value. Thus, ordering for a CI build as a POST release version is |
| 134 | +> built into this representation already. |
| 135 | +> |
| 136 | +> The ***string*** form of a version uses the `Patch+1` version to maintain proper |
| 137 | +> ordering following the rules defined by SemVer. That is the FileVersion and string |
| 138 | +> forms will use different versions at first glance. The string form requires some |
| 139 | +> interpretation to fully understand the meaning, while still retaining the desired |
| 140 | +> ordering based on SemVer defined rules. |
| 141 | +
|
| 142 | +File Version QUAD (Bit 63 is the MSB and bit 0 is the LSB)<sup>[1](#footnote_1)</sup> |
| 143 | + |
| 144 | +|Field | Name | Description | |
| 145 | +|------|------|-------------| |
| 146 | +|Bits 48-63 | Major | Major portion of a build | |
| 147 | +|Bits 32-47 | Minor | Minor portion of a build | |
| 148 | +|Bits 16-31| Build | Build number for a build | |
| 149 | +|Bits 1-15 | Revision | Revision of the build | |
| 150 | +|Bit 0 | CI Build | normally incorporated into the "revision" (1 == CI Build, 0 == release build)| |
| 151 | + |
| 152 | +Bits 1-63 are the same as the ordered version of the base build for a CI build and |
| 153 | +the same as the ordered version of a release build. |
| 154 | + |
| 155 | +------ |
| 156 | +<sup><a id="footnote_1">1</a></sup> Endianess of the platform does not matter as the bits are numbered as MSB->LSB |
| 157 | +and the actual byte layout is dependent on the target platform even though the bits |
| 158 | +are not. It is NOT safe to transfer a FileVersion (or Ordered version) as in integral |
| 159 | +value without considering the endianess of the source, target and transport mechanism, |
| 160 | +all of which are out of scope for this library and the CSemVer spec in general. |
| 161 | + |
| 162 | + |
0 commit comments