Use semver 2.0.0 as the human-readable version string format

This avoids the need to escape tilde in tag names.
This commit is contained in:
Richard Hansen 2024-12-23 21:22:05 -05:00
parent 9f2d6279d2
commit 54b6d0cb0d
3 changed files with 57 additions and 42 deletions

View file

@ -3,7 +3,7 @@
This document describes notable changes. For details, see the [source code
repository history](https://github.com/ddclient/ddclient/commits/main).
## v4.0.0~alpha (unreleased work-in-progress)
## v4.0.0-alpha (unreleased work-in-progress)
### Breaking changes

View file

@ -36,25 +36,40 @@ use Sys::Hostname;
# Note that version::normal and version::numify lose information because the underscore is
# effectively removed.
#
# To work around Perl's limitations, human-readable versions are translated to/from Perl versions
# as follows:
# To work around Perl's limitations, Perl versions are translated to/from human-readable Semantic
# Versioning 2.0.0 <https://semver.org/spec/v2.0.0.html> version strings as follows:
#
# Human-readable Perl version Notes
# -------------------------------------------------------------------------------------------
# 1.2.3~alpha v1.2.3.0_0 compares equal to Perl version v1.2.3 (unfortunately)
# 1.2.3~betaN v1.2.3.0_N 1 <= N < 900; compares equal to Perl v1.2.3.N
# 1.2.3~rcN v1.2.3.0_M 1 <= N < 99; M = N + 900; compares equal to Perl v1.2.3.M
# 1.2.3-alpha v1.2.3.0_0 compares equal to Perl version v1.2.3 (unfortunately)
# 1.2.3-beta.N v1.2.3.0_N 1 <= N < 900; compares equal to Perl v1.2.3.N
# 1.2.3-rc.N v1.2.3.0_M 1 <= N < 99; M = N + 900; compares equal to Perl v1.2.3.M
# 1.2.3 v1.2.3.999 for releases; no underscore in Perl version string
# 1.2.3rN v1.2.3.999.N 1 <= N < 1000; for re-releases, if necessary (rare)
# 1.2.3+r.N v1.2.3.999.N 1 <= N < 1000; for re-releases, if necessary (rare)
#
# A tilde is used to separate "alpha", "beta", and "rc" from the version numbers because it has
# special meaning for the version comparison algorithms in RPM and Debian:
# https://docs.fedoraproject.org/en-US/packaging-guidelines/Versioning/#_handling_non_sorting_versions_with_tilde_dot_and_caret
# https://manpages.debian.org/bookworm/dpkg-dev/deb-version.7.en.html
# A hyphen-minus ('-', a.k.a. dash) is used to separate "alpha", "beta", and "rc" from the version
# numbers because that is what <https://semver.org/spec/v2.0.0.html> requires. Tilde ('~') was
# considered instead of '-' because it has desirable semantics in the version comparison algorithms
# in Debian and RPM; see <https://manpages.debian.org/bookworm/dpkg-dev/deb-version.7.en.html> and
# <https://docs.fedoraproject.org/en-US/packaging-guidelines/Versioning/#_handling_non_sorting_versions_with_tilde_dot_and_caret>
# However, tilde is not permitted in Git tags, so the human-readable version string would have to
# be transformed for release tags, and then transformed back by downstream package maintainers to
# reconstruct the original version string. As long as downstream package maintainers have to
# transform the tag name anyway, the human-readable version string might as well have the same
# format as the tag name. Version strings conforming to <https://semver.org/spec/v2.0.0.html> have
# this property.
#
# No period separator is required between "beta", "rc", or "r" and its adjacent number(s); both RPM
# and Debian will compare the adjacent number numerically, not lexicographically ("~beta2" sorts
# before "~beta10" as expected).
# A period is required between "beta" or "rc" and its adjacent number(s) because
# <https://semver.org/spec/v2.0.0.html> says that parts containing non-number characters are
# compared lexicographically. For example, '-beta9' unfortunately sorts after '-beta10' but
# '-beta.9' sorts before '-beta.10', as desired. (Both the Debian and the RPM version comparison
# algorithms do not have this problem; they compare number parts numerically, not
# lexicographically, even if there is no period between the number and non-number characters.)
#
# A period is also required after the "r" for a re-release, but this is only for consistency with
# "beta" and "rc". <https://semver.org/spec/v2.0.0.html> says that build metadata (the stuff after
# the plus ('+') character) does not affect ordering at all so the lack of a period would not
# affect ordering.
#
# The Perl version is declared first then converted to a human-readable form. It would be nicer to
# declare a human-readable version string and convert that to a Perl version string, but various
@ -88,13 +103,13 @@ sub humanize_version {
return $v if !defined($r);
$v = $r;
if (!defined($pr)) {
$v .= "r$rr" if defined($rr);
$v .= "+r.$rr" if defined($rr);
} elsif ($pr eq '0') {
$v .= '~alpha';
$v .= '-alpha';
} elsif ($pr < 900) {
$v .= "~beta$pr";
$v .= "-beta.$pr";
} elsif ($pr < 999) {
$v .= '~rc' . ($pr - 900);
$v .= '-rc.' . ($pr - 900);
}
return $v;
}

View file

@ -8,33 +8,33 @@ ok(ddclient::parse_version($ddclient::VERSION),
"module's Perl version string is in opinionated form");
my $n = qr/0|[1-9]\d{0,2}/;
like($ddclient::version, qr/^$n\.$n\.$n(?:~alpha|~beta$n|~rc$n|r$n)?$/,
like($ddclient::version, qr/^$n\.$n\.$n(?:-alpha|-beta\.$n|-rc\.$n|\+r\.$n)?$/,
"human-readable version is in opinionated form");
my @tcs = (
['v1.0_0', '1~alpha'],
['v1.0.0_0', '1.0~alpha'],
['v1.2.3.0_0', '1.2.3~alpha'],
['v1.2.3.4.0_0', '1.2.3.4~alpha'],
['v1.0_1', '1~beta1'],
['v1.0.0_1', '1.0~beta1'],
['v1.2.3.0_1', '1.2.3~beta1'],
['v1.2.3.4.0_1', '1.2.3.4~beta1'],
['v1.2.3.0_899', '1.2.3~beta899'],
['v1.0_901', '1~rc1'],
['v1.0.0_901', '1.0~rc1'],
['v1.2.3.0_901', '1.2.3~rc1'],
['v1.2.3.4.0_901', '1.2.3.4~rc1'],
['v1.2.3.0_998', '1.2.3~rc98'],
['v1.0_0', '1-alpha'],
['v1.0.0_0', '1.0-alpha'],
['v1.2.3.0_0', '1.2.3-alpha'],
['v1.2.3.4.0_0', '1.2.3.4-alpha'],
['v1.0_1', '1-beta.1'],
['v1.0.0_1', '1.0-beta.1'],
['v1.2.3.0_1', '1.2.3-beta.1'],
['v1.2.3.4.0_1', '1.2.3.4-beta.1'],
['v1.2.3.0_899', '1.2.3-beta.899'],
['v1.0_901', '1-rc.1'],
['v1.0.0_901', '1.0-rc.1'],
['v1.2.3.0_901', '1.2.3-rc.1'],
['v1.2.3.4.0_901', '1.2.3.4-rc.1'],
['v1.2.3.0_998', '1.2.3-rc.98'],
['v1.999', '1'],
['v1.0.999', '1.0'],
['v1.2.3.999', '1.2.3'],
['v1.2.3.4.999', '1.2.3.4'],
['v1.999.1', '1r1'],
['v1.0.999.1', '1.0r1'],
['v1.2.3.999.1', '1.2.3r1'],
['v1.2.3.4.999.1', '1.2.3.4r1'],
['v1.2.3.999.999', '1.2.3r999'],
['v1.999.1', '1+r.1'],
['v1.0.999.1', '1.0+r.1'],
['v1.2.3.999.1', '1.2.3+r.1'],
['v1.2.3.4.999.1', '1.2.3.4+r.1'],
['v1.2.3.999.999', '1.2.3+r.999'],
[$ddclient::VERSION, $ddclient::version],
);
@ -49,10 +49,10 @@ subtest 'human-readable version can be translated back to Perl version' => sub {
for my $tc (@tcs) {
my ($want, $hv) = @$tc;
my $pv = "v$hv";
$pv =~ s/^(?!.*~)(.*?)(?:r(\d+))?$/"$1.999" . (defined($2) ? ".$2" : "")/e;
$pv =~ s/~alpha$/.0_0/;
$pv =~ s/~beta(\d+)$/.0_$1/;
$pv =~ s/~rc(\d+)$/'.0_' . (900 + $1)/e;
$pv =~ s/^(?!.*-)(.*?)(?:\+r\.(\d+))?$/"$1.999" . (defined($2) ? ".$2" : "")/e;
$pv =~ s/-alpha$/.0_0/;
$pv =~ s/-beta\.(\d+)$/.0_$1/;
$pv =~ s/-rc\.(\d+)$/'.0_' . (900 + $1)/e;
is($pv, $want, "$hv -> $want");
}
};