Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/70200.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed master nightly build version to reflect the next unreleased codename (Potassium/3009) instead of the previous released major (Argon/3008). Master nightlies now emit `3009.0nb<N>+<N>.g<sha>` (rendered as `3009.0~nb<N>+...` in RPM/DEB names) so they sort above every 3008.x release and below any future 3009 pre-release.
65 changes: 56 additions & 9 deletions salt/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,19 +639,23 @@ def __discover_version(saltstack_version):
# Let's not import `salt.utils` for the above check
kwargs["close_fds"] = True

# Constrain describe to the next-unreleased codename's major
# (Potassium / 3009 on master). No ``v3009.*`` tag exists yet so
# describe falls through to just the raw SHA, which the SHA-only
# branch below lifts to a ``3009.0nb<N>+<N>.g<sha>`` version so
# master nightlies sort above every 3008.x release and below any
# future 3009 pre-release. Maintenance branches (e.g. 3008.x) keep
# their own hardcoded ``v<major>.*`` constraint from their branch's
# version.py (rebased on branch-cut), which is why this value is
# tied to the *next* codename here.
process = subprocess.Popen(
[
"git",
"describe",
"--tags",
"--long",
# Constrain to the branch's own major (3008.x) so tags
# from other majors reachable in the git graph do not hijack
# the detected version. Merged forward from 3007.x's
# v3007.* constraint (see git log for f3ffc8f9c9ea) and
# rebased to this branch's major.
"--match",
"v3008.*",
"v3009.*",
"--always",
"--candidates=150",
],
Expand All @@ -667,7 +671,46 @@ def __discover_version(saltstack_version):
return saltstack_version

if SaltStackVersion.git_sha_regex.match(out):
# We only define the parsed SHA and set NOC as ??? (unknown)
# Describe fell through to just the raw SHA — no ``v3009.*``
# tag was reachable. This is the normal state on ``master``
# while the next codename is still unreleased. Lift the
# baseline to the next unreleased codename and count commits
# since the previous major's first tag, so the emitted version
# sorts above every released version of the previous major and
# below any pre-release/final of the next.
next_rel = SaltVersionsInfo.next_release()
cur_rel = SaltVersionsInfo.current_release()
if next_rel and cur_rel and next_rel.info[0] != cur_rel.info[0]:
anchor = f"v{cur_rel.info[0]}.0"
try:
rev_list = subprocess.check_output(
["git", "rev-list", "--count", f"{anchor}..HEAD"],
cwd=cwd,
stderr=subprocess.DEVNULL,
)
count = int(rev_list.decode().strip())
except (subprocess.CalledProcessError, ValueError):
count = -1
sha = out.strip()
if not sha.startswith("g"):
sha = f"g{sha}"
# ``nb`` = nightly build. Uses the existing pre_type slot on
# SaltStackVersion; the ``__str__`` formatter renders it as
# ``<major>.<minor>nb<count>+<count>.<sha>``. The RPM/DEB
# changelog helpers rewrite ``nb`` to ``~nb`` so distro
# version comparison places nightly builds below the
# unadorned final release (see tools/changelog.py).
return SaltStackVersion(
next_rel.info[0],
0,
0,
pre_type="nb",
pre_num=count if count >= 0 else 0,
noc=count,
sha=sha,
)
# No unreleased codename available (or same as current) — fall
# back to the historical behaviour of just recording the SHA.
saltstack_version.sha = out.strip()
saltstack_version.noc = -1
return saltstack_version
Expand Down Expand Up @@ -730,8 +773,12 @@ def __get_version(saltstack_version):

# Get additional version information if available
__saltstack_version__ = __get_version(__saltstack_version__)
if __saltstack_version__.name:
# Set SaltVersionsInfo._current_release to avoid lookups when finding previous and next releases
if __saltstack_version__.name and not __saltstack_version__.pre_type:
# Populate SaltVersionsInfo._current_release only for released / stable
# versions. A pre-release (e.g. ``3009.0nb1292`` on master) reflects the
# tree's *next* codename, not the last released one — treating it as
# ``current`` would corrupt SaltVersionsInfo.current_release() for
# downstream callers that rely on it meaning "last released codename".
SaltVersionsInfo._current_release = getattr(
SaltVersionsInfo, __saltstack_version__.name.upper()
)
Expand Down
43 changes: 41 additions & 2 deletions tools/changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import logging
import os
import pathlib
import re
import sys
import textwrap

Expand Down Expand Up @@ -39,6 +40,35 @@
)


# PEP 440 pre-release markers (a, b, rc) plus Salt's ``nb`` (nightly
# build). We anchor on ``<digit>`` on both sides so ``rc1`` matches but
# random letters embedded in numbers don't. rpm/deb version comparison
# treats extra alphanumeric segments as *greater* than nothing
# (``3009.0nb1292`` > ``3009.0``), while any segment starting with ``~``
# is *less than nothing* (``3009.0~nb1292`` < ``3009.0``) — which is what
# we want for pre-releases.
_DISTRO_PRERELEASE_RE = re.compile(r"(?<=\d)(a|b|rc|nb)(?=\d)")


def _to_distro_version(pep440_version: str) -> str:
"""
Rewrite PEP 440 pre-release markers in ``pep440_version`` to the ``~``
form used by rpmvercmp / dpkg-vercmp so pre-releases sort below the
final release.

Only the public-version segment (before ``+``) is rewritten — the
local-version identifier can contain hex SHAs whose letters would
false-match (e.g. ``621251a737`` looks like ``1a7`` = digit-a-digit).

Examples:
``3009.0rc1`` -> ``3009.0~rc1``
``3009.0nb1292+1292.g…`` -> ``3009.0~nb1292+1292.g…``
``3008.2`` -> ``3008.2`` (unchanged)
"""
public, sep, local = pep440_version.partition("+")
return _DISTRO_PRERELEASE_RE.sub(r"~\1", public) + sep + local


def _get_changelog_contents(ctx: Context, version: Version):
"""
Return the full changelog generated by towncrier.
Expand Down Expand Up @@ -108,7 +138,12 @@ def update_rpm(ctx: Context, salt_version: Version, draft: bool = False):
rpm_release = str(salt_version.post)
str_salt_version = f"{rpm_version}-{rpm_release}"
else:
rpm_version = str(salt_version).replace("rc", "~rc")
# Rewrite PEP 440 pre-release markers to the ``~`` distro form so
# rpmvercmp sorts pre-releases *below* the unadorned final version.
# rpmvercmp treats extra alphanumeric segments as *greater* (so
# ``3009.0nb1292`` > ``3009.0``), while any segment starting with
# ``~`` sorts *less than nothing* (``3009.0~nb1292`` < ``3009.0``).
rpm_version = _to_distro_version(str(salt_version))
rpm_release = "0"
str_salt_version = rpm_version

Expand Down Expand Up @@ -172,7 +207,11 @@ def update_deb(ctx: Context, salt_version: Version, draft: bool = False):
debian_changelog_path = "pkg/debian/changelog"
tmp_debian_changelog_path = f"{debian_changelog_path}.1"
with open(tmp_debian_changelog_path, "w", encoding="utf-8") as wfp:
wfp.write(f"salt ({salt_version}) stable; urgency=medium\n\n")
# See _to_distro_version() for rationale — dpkg-vercmp has the same
# "extra segment sorts higher" quirk as rpmvercmp, so pre-release
# markers need to be rewritten to the ``~`` form here too.
deb_version = _to_distro_version(str(salt_version))
wfp.write(f"salt ({deb_version}) stable; urgency=medium\n\n")
wfp.write(formated)
wfp.write(
f"\n -- Salt Project Packaging <saltproject-packaging@vmware.com> {date}\n\n"
Expand Down
Loading