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 This document describes notable changes. For details, see the [source code
repository history](https://github.com/ddclient/ddclient/commits/main). 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 ### Breaking changes

View file

@ -36,25 +36,40 @@ use Sys::Hostname;
# Note that version::normal and version::numify lose information because the underscore is # Note that version::normal and version::numify lose information because the underscore is
# effectively removed. # effectively removed.
# #
# To work around Perl's limitations, human-readable versions are translated to/from Perl versions # To work around Perl's limitations, Perl versions are translated to/from human-readable Semantic
# as follows: # Versioning 2.0.0 <https://semver.org/spec/v2.0.0.html> version strings as follows:
# #
# Human-readable Perl version Notes # 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-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-beta.N 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-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.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 # A hyphen-minus ('-', a.k.a. dash) is used to separate "alpha", "beta", and "rc" from the version
# special meaning for the version comparison algorithms in RPM and Debian: # numbers because that is what <https://semver.org/spec/v2.0.0.html> requires. Tilde ('~') was
# https://docs.fedoraproject.org/en-US/packaging-guidelines/Versioning/#_handling_non_sorting_versions_with_tilde_dot_and_caret # considered instead of '-' because it has desirable semantics in the version comparison algorithms
# https://manpages.debian.org/bookworm/dpkg-dev/deb-version.7.en.html # 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 # A period is required between "beta" or "rc" and its adjacent number(s) because
# and Debian will compare the adjacent number numerically, not lexicographically ("~beta2" sorts # <https://semver.org/spec/v2.0.0.html> says that parts containing non-number characters are
# before "~beta10" as expected). # 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 # 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 # 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); return $v if !defined($r);
$v = $r; $v = $r;
if (!defined($pr)) { if (!defined($pr)) {
$v .= "r$rr" if defined($rr); $v .= "+r.$rr" if defined($rr);
} elsif ($pr eq '0') { } elsif ($pr eq '0') {
$v .= '~alpha'; $v .= '-alpha';
} elsif ($pr < 900) { } elsif ($pr < 900) {
$v .= "~beta$pr"; $v .= "-beta.$pr";
} elsif ($pr < 999) { } elsif ($pr < 999) {
$v .= '~rc' . ($pr - 900); $v .= '-rc.' . ($pr - 900);
} }
return $v; return $v;
} }

View file

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