Package version improvements - #102
Open
Christopher Obbard (obbardc) wants to merge 8 commits into
Open
Conversation
Christopher Obbard (obbardc)
had a problem deploying
to
Staging
September 4, 2026 15:58 — with
GitHub Actions
Error
Christopher Obbard (obbardc)
had a problem deploying
to
Staging
September 4, 2026 15:59 — with
GitHub Actions
Error
Christopher Obbard (obbardc)
had a problem deploying
to
Staging
September 4, 2026 16:00 — with
GitHub Actions
Error
Christopher Obbard (obbardc)
had a problem deploying
to
Staging
September 4, 2026 16:00 — with
GitHub Actions
Error
Christopher Obbard (obbardc)
force-pushed
the
wip/obbardc/version-improvements
branch
from
September 4, 2026 16:32
b4ec130 to
9e9b9d9
Compare
systemd-boot sorts boot entries on the BLS 'version' key, which kernel-install writes verbatim from uname -r. Under systemd's version comparison: 7.2.0-rc7-qcom-next-20260821 > 7.2.0-qcom-next-20260826 so every release candidate outranked the final release that followed it, and an rc daily stayed the default boot entry after the release was installed. The deciding comparison is a plain strcmp of "rc" against "qcom", where 'r' > 'q'; there is no notion of a pre-release involved. debian/rules already rewrites -rcN to ~rcN, but only for the Debian version, because a package name may not contain '~' and the binary packages are named linux-image-<KVER>. So dpkg ordered these correctly all along and only the boot menu was wrong. Joining the suffix with '+' fixes it: systemd compares the separator before the chunk behind it, and '-' < '+'. This is not a local invention -- it is why Debian's own kernels sort correctly (linux-image-7.1.10+deb14-amd64). Upstream bindeb-pkg has the identical ~rc/-rc split and gets away with it for a different reason: it puts a numeric commit count in that slot, and systemd ranks digits above letters. qcom-next was the only scheme putting a lowercase word there. The Debian version is unchanged, byte for byte: DATE_PART reads the date off the end of LOCALVERSION, which still matches. Only uname -r and the binary package names change. Note this renames every binary package. Already-installed kernels under the old names are not upgraded or removed by it -- they keep their existing sort position until purged, so the fix applies to newly installed kernels only. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
The stub was a bare '0qli', which left a packaging-only rebuild -- same kernel snapshot, changed debian/ -- with no field to bump. Neither of the other two components can absorb it: suite_suffix_mapping is a per-suite constant shared by every row, and the delivery suffix is the Daily/Release marker. Bumping either to force a rebuild through would corrupt what they mean. Make the trailing digit part of the stub, so a rebuild is 0qli1 -> 0qli2 and lands uniformly across every suite: 0qli1~bpo13+1~ < 0qli1~bpo13+1 < 0qli2~bpo13+1 derive-debian-revision.sh now rejects a stub that does not end in a digit, alongside the existing "must not end in ~" check. Both guard the same thing: a stub that quietly loses a field it is supposed to carry. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
debian/rules recovered the snapshot date by matching the tail of
LOCALVERSION, a string it did not build and cannot safely parse. The variant
name in the middle is caller-supplied and unbounded, and a branch-tip suffix
ends in a 12-hex SHA that can be eight digits:
$ echo '+qcom-next-g123456789012' | grep -oE '[0-9]{8}$'
56789012
Such a build was versioned 7.2.0~rc7+56789012-0qli1, naming a snapshot date
that never existed and sorting it against real ones. Roughly one branch-tip
SHA in ten ends that way, so this is a live bug, not a theoretical one.
Anchoring the match would have fixed those refs while leaving the guess in
place. Carry the field instead. derive-localversion.sh already knows the
snapshot -- it matched the tag to build LOCALVERSION in the first place -- so
it now emits both:
LOCALVERSION=+qcom-next-20260722
SNAPSHOT=20260722
KEY=VALUE because the workflow appends them straight to GITHUB_ENV.
prepare-source.sh gains --snapshot and forwards it, and its tag auto-detect
derives both fields in one match. debian/rules takes SNAPSHOT as an input and
validates its shape rather than discovering it.
The composed component is spelled +git<snapshot>, which is Debian's own idiom
for a VCS snapshot, rather than appended bare as +<snapshot> where it reads as
part of the upstream version:
7.2.0~rc3+git20260722-0qcom1
Ordering is unaffected -- 'git' is a constant prefix on both sides of every
comparison, and the date behind it still decides.
Neither caller reconstructs the field when it is absent. An explicit
--localversion replaces the derived suffix precisely because the ref no
longer describes the build, so parsing it back would reinstate the guess this
commit removes. Both paths warn that the Debian version will carry no dated
component, which is visible and correctable, unlike a date invented from a
SHA.
Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
A second tag cut on the same day (qcom-next-7.2-20260826.1) collapsed onto the same version as the first, because every derivation matched only a bare YYYYMMDD. derive-localversion.sh dropped the ordinal; prepare-source.sh matched trailing digits with -([0-9]+)$, which a ".1" suffix cannot satisfy at all, so the tag fell through to the +<whole-tag> fallback. Match the date width explicitly with an optional ordinal after it, so the component stays whole: qcom-next-7.2-20260826 -> +qcom-next-20260826 / 20260826 qcom-next-7.2-20260826.1 -> +qcom-next-20260826.1 / 20260826.1 The first tag of a day deliberately keeps the plain form rather than normalising to ".0". Both comparators read an absent ordinal as lower than a present one, so the respin already sorts above it and every other build is spared a ".0" it never needed. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
The snapshot date identifies the tag, not the commit the tag pointed at when the build was cut. A moved tag then produces two different kernels under one version, indistinguishable in the archive and on a running system. Append the commit to both strings: uname -r 7.2.0-rc7+qcom-next-20260826.1-gabcdef123456 Debian version 7.2.0~rc7+git20260826.1~gabcdef123456-0qli1~bpo13+1 The separators differ, and the difference is load-bearing rather than sloppy. systemd weighs the separator before the chunk behind it, so '-g<sha>' leaves an absent respin ordinal sorting below a present one. dpkg instead alternates digit and non-digit runs and reads an exhausted run as lower than a letter, so the same '.' or '-' join would decide before reaching the ordinal: 7.2.0+git20260826.g3f2f3ca1a81e > 7.2.0+git20260826.1.gabcdef123456 putting a respin below the build it respins. '~' sorts below everything including the empty string, so the ordinal is always compared first and the SHA only ever breaks a tie between builds sharing a snapshot. The alternative -- spelling ".0" on every non-respin build -- buys the same ordering at the cost of a redundant ordinal in every version forever. What '~' costs is one reading: the version sorts below the same snapshot without a SHA, as though it preceded it. Nothing occupies that slot, because every snapshot build carries a SHA, so the claim is never tested against a real version. The SHA cannot order anything -- two SHAs have no relation -- so a moved tag still needs its respin ordinal or the packaging revision bumped before users can upgrade onto it. What this buys is that the two builds are never confused for each other. --sha becomes required for every build rather than just branch tips, and is validated as hex, since it is now part of every kernel release rather than a fallback identity for refs that had nothing else. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
A branch-tip build had no snapshot, so debian/rules emitted a version with no
+git<date> at all -- 7.2.0~rc7-0qli1~bpo13+1 -- which sorts below every dated
build rather than among them. Take the date from the HEAD commit instead, so
these builds land in the same sequence:
7.2.0~rc7+git20260821~g07f50dc44edd-… tag build
7.2.0~rc7+git20260904~g07f50dc44edd-… branch tip, dated by commit
The date is the committer date of HEAD, not the build date:
- rebuilding a commit reproduces its version instead of inventing a higher
one on each run
- the date describes the source rather than when CI happened to run
- it lands in the same space as upstream's tag dates, which track the
commit each tag is cut from
Committer date rather than author date, because an author date can be months
old on a backported patch. Normalised to UTC, since --date=short would
otherwise render in each committer's timezone and make one commit yield
different dates.
--date only supplies what a branch tip's ref cannot: --sha is still required
for every build, and a dated tag carries its own date and ignores --date. A
branch-tip release therefore has the same shape as a tag build rather than a
second shape of its own.
prepare-source.sh gets the same treatment, so the fix is not confined to the
paths CI happens to drive. Its auto-detect covers two refs that carry no date
-- a tag that is not dated, and no tag at all -- and both left SNAPSHOT empty,
which reproduced exactly the undated version above for anyone running the
script directly. Both now date the build by HEAD, matching how
derive-localversion.sh treats any ref without a date of its own.
An explicit --localversion still supplies no snapshot and still warns. That
path is an override: the ref was replaced precisely because it no longer
describes the build, so dating it from HEAD would assert something the caller
has just denied.
The trade-off is that a commit date need not advance: rewinding the branch to
an older commit produces a lower version that apt will not offer as an
upgrade. Documented in derive-localversion.sh rather than left to be found.
Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
@gitclone@ and @Branch@ were substituted with empty strings, so every changelog carried a bare "* Source:" naming nothing. Thread the clone URL, ref and full SHA through prepare-source.sh so the entry says where the build came from: * Source: https://github.com/qualcomm-linux/kernel qcom-next * Commit: 07f50dc44edd… The version strings already name the commit, so this is not the only record of it. What they do not carry is the repository and the ref, which are nowhere else at all, and a 12-character abbreviation is not the commit itself. The comments claiming the changelog is the sole pin on the exact source are corrected to say what it actually pins. prepare-source.sh gains one --git-sha, taking the full SHA. The 12-character form used in the version strings is derived from it a few lines later rather than accepted as a second option, so the two widths are provably the same commit and there is one place to change if that width ever moves. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
Records why the kernel release and the Debian version are two strings rather than one, and why each spells the same four fields differently: the '+' join that keeps a release candidate below its final release under systemd, and the '~' before the SHA that keeps a respin above the build it respins under dpkg. Both separators look arbitrary and both are load-bearing, so the reasoning is written down where someone tempted to normalise them will find it. Also covers what the version deliberately does not carry -- the repository and ref live in the changelog -- and the one case where a branch-tip version can go backwards, when the branch is rewound to an older commit. README.md keeps the format table and the note that the separators are load-bearing, and points here for the reasoning rather than carrying a second account of it that would drift. Scoped to qcom-next; the derivation is not variant-agnostic. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
Christopher Obbard (obbardc)
marked this pull request as ready for review
September 9, 2026 15:00
Christopher Obbard (obbardc)
force-pushed
the
wip/obbardc/version-improvements
branch
from
September 9, 2026 15:01
9e9b9d9 to
5d0d21d
Compare
Christopher Obbard (obbardc)
temporarily deployed
to
Staging
September 9, 2026 15:09 — with
GitHub Actions
Inactive
Christopher Obbard (obbardc)
temporarily deployed
to
Staging
September 9, 2026 15:09 — with
GitHub Actions
Inactive
Christopher Obbard (obbardc)
temporarily deployed
to
Staging
September 9, 2026 15:09 — with
GitHub Actions
Inactive
Christopher Obbard (obbardc)
temporarily deployed
to
Staging
September 9, 2026 15:10 — with
GitHub Actions
Inactive
Bjordis Collaku (bjordiscollaku)
approved these changes
Sep 9, 2026
Bjordis Collaku (bjordiscollaku)
left a comment
Contributor
There was a problem hiding this comment.
Ran the ordering claims through a dpkg comparator, including the one that matters most for a version rework: the upgrade path from what is already published. 7.2.0+20260826-0qli~bpo13+1 sorts below 7.2.0+git20260826~gd49c...-0qli1~bpo13+1, so nothing in qli gets stranded. rc below final, respin above first tag of the day, Daily below Release and the packaging rebuild all check out too.
~ where the version field allows it and + where a package name cannot carry it is the right split. docs/version.md is a good record of why, particularly the ~g<sha> reasoning.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This branch reworks how the package's version is derived.
This is required because systemd-boot sorted versions with rc7 higher than non-rc in the systemd-boot menu.
The Kernel release (
uname -r) and Debian package versions now both carry:<version>.1)Also:
derive-localversion.shrather than parsed from LOCALVERSION, which was fragile (a branch-tip SHA can itself end in 8 digits and get misread as a date)See
docs/version.mdfor the full rationale.