[ci] standardize hotfix package version ordering across platforms

This commit is contained in:
kunkundi
2026-05-29 00:52:07 +08:00
parent eea107db66
commit 65d8284fb8
10 changed files with 234 additions and 55 deletions
+25 -10
View File
@@ -53,7 +53,11 @@ jobs:
PATCH_NUMBER=0
fi
if [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then
if [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]+)-([0-9]{8})$ ]]; then
VERSION_BASE="${BASH_REMATCH[1]}"
PATCH_NUMBER="${BASH_REMATCH[3]}"
BUILD_DATE_OVERRIDE="${BASH_REMATCH[4]}"
elif [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then
VERSION_BASE="${BASH_REMATCH[1]}"
BUILD_DATE_OVERRIDE="${BASH_REMATCH[3]}"
PATCH_NUMBER="${BASH_REMATCH[4]}"
@@ -82,7 +86,7 @@ jobs:
fi
if [[ "${PATCH_NUMBER}" != "0" ]]; then
LEGAL_VERSION="v${VERSION_BASE}-${BUILD_DATE}-${PATCH_NUMBER}"
LEGAL_VERSION="v${VERSION_BASE}-${PATCH_NUMBER}-${BUILD_DATE}"
else
LEGAL_VERSION="v${VERSION_BASE}-${BUILD_DATE}"
fi
@@ -146,7 +150,11 @@ jobs:
PATCH_NUMBER=0
fi
if [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then
if [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]+)-([0-9]{8})$ ]]; then
VERSION_BASE="${BASH_REMATCH[1]}"
PATCH_NUMBER="${BASH_REMATCH[3]}"
BUILD_DATE="${BASH_REMATCH[4]}"
elif [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then
VERSION_BASE="${BASH_REMATCH[1]}"
BUILD_DATE="${BASH_REMATCH[3]}"
PATCH_NUMBER="${BASH_REMATCH[4]}"
@@ -159,7 +167,7 @@ jobs:
fi
if [[ "${PATCH_NUMBER}" != "0" ]]; then
VERSION_NUM="v${VERSION_BASE}-${BUILD_DATE}-${PATCH_NUMBER}"
VERSION_NUM="v${VERSION_BASE}-${PATCH_NUMBER}-${BUILD_DATE}"
else
VERSION_NUM="v${VERSION_BASE}-${BUILD_DATE}"
fi
@@ -228,7 +236,11 @@ jobs:
$PATCH_NUMBER = "0"
}
if ($version -match '^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$') {
if ($version -match '^([0-9]+(\.[0-9]+){1,3})-([0-9]+)-([0-9]{8})$') {
$version = $Matches[1]
$PATCH_NUMBER = $Matches[3]
$BUILD_DATE = $Matches[4]
} elseif ($version -match '^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$') {
$version = $Matches[1]
$BUILD_DATE = $Matches[3]
$PATCH_NUMBER = $Matches[4]
@@ -241,7 +253,7 @@ jobs:
}
if ($PATCH_NUMBER -ne "0") {
$VERSION_NUM = "v$version-$BUILD_DATE-$PATCH_NUMBER"
$VERSION_NUM = "v$version-$PATCH_NUMBER-$BUILD_DATE"
} else {
$VERSION_NUM = "v$version-$BUILD_DATE"
}
@@ -321,8 +333,7 @@ jobs:
- name: Package
shell: pwsh
run: |
cd "${{ github.workspace }}\scripts\windows"
makensis /DVERSION=$env:VERSION_NUM nsis_script.nsi
& "${{ github.workspace }}\scripts\windows\pkg_x64.ps1" $env:VERSION_NUM
- name: Build Portable CrossDesk
run: |
@@ -403,7 +414,11 @@ jobs:
PATCH_NUMBER=0
fi
if [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then
if [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]+)-([0-9]{8})$ ]]; then
VERSION_BASE="${BASH_REMATCH[1]}"
PATCH_NUMBER="${BASH_REMATCH[3]}"
BUILD_DATE="${BASH_REMATCH[4]}"
elif [[ "${VERSION_BASE}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then
VERSION_BASE="${BASH_REMATCH[1]}"
BUILD_DATE="${BASH_REMATCH[3]}"
PATCH_NUMBER="${BASH_REMATCH[4]}"
@@ -417,7 +432,7 @@ jobs:
BUILD_DATE_ISO="${BUILD_DATE:0:4}-${BUILD_DATE:4:2}-${BUILD_DATE:6:2}"
if [[ "${PATCH_NUMBER}" != "0" ]]; then
VERSION_NUM="${VERSION_BASE}-${BUILD_DATE}-${PATCH_NUMBER}"
VERSION_NUM="${VERSION_BASE}-${PATCH_NUMBER}-${BUILD_DATE}"
else
VERSION_NUM="${VERSION_BASE}-${BUILD_DATE}"
fi
+7 -2
View File
@@ -28,8 +28,13 @@ jobs:
VERSION_BASE="${TAG_VERSION}"
PATCH_NUMBER=0
# Extract date and patch from tags such as v1.2.3-20251113-1.
if [[ "${TAG_VERSION}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then
# Extract date and patch from tags such as v1.2.3-1-20251113.
if [[ "${TAG_VERSION}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]+)-([0-9]{8})$ ]]; then
VERSION_BASE="${BASH_REMATCH[1]}"
PATCH_NUMBER="${BASH_REMATCH[3]}"
DATE_STR="${BASH_REMATCH[4]}"
BUILD_DATE_ISO="${DATE_STR:0:4}-${DATE_STR:4:2}-${DATE_STR:6:2}"
elif [[ "${TAG_VERSION}" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then
VERSION_BASE="${BASH_REMATCH[1]}"
DATE_STR="${BASH_REMATCH[3]}"
PATCH_NUMBER="${BASH_REMATCH[4]}"
+19 -1
View File
@@ -4,13 +4,31 @@ set -e
PKG_NAME="crossdesk"
APP_NAME="CrossDesk"
APP_VERSION="$1"
ARCHITECTURE="amd64"
MAINTAINER="Junkun Di <junkun.di@hotmail.com>"
DESCRIPTION="A simple cross-platform remote desktop client."
ALSA_RUNTIME_DEP="libasound2 | libasound2t64"
PORTAL_RUNTIME_RECOMMENDS="xdg-desktop-portal, xdg-desktop-portal-gtk | xdg-desktop-portal-kde | xdg-desktop-portal-wlr"
normalize_app_version() {
local input="$1"
local prefix=""
local body="$input"
if [[ "$body" == v* ]]; then
prefix="v"
body="${body#v}"
fi
if [[ "$body" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then
echo "${prefix}${BASH_REMATCH[1]}-${BASH_REMATCH[4]}-${BASH_REMATCH[3]}"
else
echo "$input"
fi
}
APP_VERSION="$(normalize_app_version "$1")"
# Remove 'v' prefix from version for Debian package (Debian version must start with digit)
DEB_VERSION="${APP_VERSION#v}"
+19 -1
View File
@@ -4,13 +4,31 @@ set -e
PKG_NAME="crossdesk"
APP_NAME="CrossDesk"
APP_VERSION="$1"
ARCHITECTURE="arm64"
MAINTAINER="Junkun Di <junkun.di@hotmail.com>"
DESCRIPTION="A simple cross-platform remote desktop client."
ALSA_RUNTIME_DEP="libasound2 | libasound2t64"
PORTAL_RUNTIME_RECOMMENDS="xdg-desktop-portal, xdg-desktop-portal-gtk | xdg-desktop-portal-kde | xdg-desktop-portal-wlr"
normalize_app_version() {
local input="$1"
local prefix=""
local body="$input"
if [[ "$body" == v* ]]; then
prefix="v"
body="${body#v}"
fi
if [[ "$body" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then
echo "${prefix}${BASH_REMATCH[1]}-${BASH_REMATCH[4]}-${BASH_REMATCH[3]}"
else
echo "$input"
fi
}
APP_VERSION="$(normalize_app_version "$1")"
# Remove 'v' prefix from version for Debian package (Debian version must start with digit)
DEB_VERSION="${APP_VERSION#v}"
+19 -1
View File
@@ -4,13 +4,31 @@ set -e
APP_NAME="crossdesk"
APP_NAME_UPPER="CrossDesk"
EXECUTABLE_PATH="./build/macosx/arm64/release/crossdesk"
APP_VERSION="$1"
PLATFORM="macos"
ARCH="arm64"
IDENTIFIER="cn.crossdesk.app"
ICON_PATH="icons/macos/crossdesk.icns"
MACOS_MIN_VERSION="10.12"
normalize_app_version() {
local input="$1"
local prefix=""
local body="$input"
if [[ "$body" == v* ]]; then
prefix="v"
body="${body#v}"
fi
if [[ "$body" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then
echo "${prefix}${BASH_REMATCH[1]}-${BASH_REMATCH[4]}-${BASH_REMATCH[3]}"
else
echo "$input"
fi
}
APP_VERSION="$(normalize_app_version "$1")"
APP_BUNDLE="${APP_NAME_UPPER}.app"
CONTENTS_DIR="${APP_BUNDLE}/Contents"
MACOS_DIR="${CONTENTS_DIR}/MacOS"
+19 -1
View File
@@ -4,13 +4,31 @@ set -e
APP_NAME="crossdesk"
APP_NAME_UPPER="CrossDesk"
EXECUTABLE_PATH="build/macosx/x86_64/release/crossdesk"
APP_VERSION="$1"
PLATFORM="macos"
ARCH="x64"
IDENTIFIER="cn.crossdesk.app"
ICON_PATH="icons/macos/crossdesk.icns"
MACOS_MIN_VERSION="10.12"
normalize_app_version() {
local input="$1"
local prefix=""
local body="$input"
if [[ "$body" == v* ]]; then
prefix="v"
body="${body#v}"
fi
if [[ "$body" =~ ^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$ ]]; then
echo "${prefix}${BASH_REMATCH[1]}-${BASH_REMATCH[4]}-${BASH_REMATCH[3]}"
else
echo "$input"
fi
}
APP_VERSION="$(normalize_app_version "$1")"
APP_BUNDLE="${APP_NAME_UPPER}.app"
CONTENTS_DIR="${APP_BUNDLE}/Contents"
MACOS_DIR="${CONTENTS_DIR}/MacOS"
+40
View File
@@ -0,0 +1,40 @@
param(
[Parameter(Mandatory = $true)]
[string]$Version
)
$ErrorActionPreference = "Stop"
function Normalize-AppVersion {
param(
[Parameter(Mandatory = $true)]
[string]$InputVersion
)
$prefix = ""
$body = $InputVersion
if ($body.StartsWith("v")) {
$prefix = "v"
$body = $body.Substring(1)
}
if ($body -match '^([0-9]+(\.[0-9]+){1,3})-([0-9]{8})-([0-9]+)$') {
return "${prefix}$($Matches[1])-$($Matches[4])-$($Matches[3])"
}
return $InputVersion
}
$normalizedVersion = Normalize-AppVersion -InputVersion $Version
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
Push-Location $scriptDir
try {
& makensis "/DVERSION=$normalizedVersion" "nsis_script.nsi"
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
} finally {
Pop-Location
}
+24 -39
View File
@@ -137,27 +137,6 @@ bool ExtractDateFromText(const std::string& value,
return false;
}
bool ExtractPatchAfterDate(const std::string& value,
size_t start,
int* patch) {
size_t pos = start;
while (pos < value.size() && !IsAlphaNumeric(value[pos])) {
pos++;
}
const size_t token_start = pos;
while (pos < value.size() && IsAlphaNumeric(value[pos])) {
pos++;
}
if (token_start == pos) {
return false;
}
return TryParseInlinePatch(value.substr(token_start, pos - token_start),
patch);
}
ParsedVersion ParseVersion(const std::string& version) {
const size_t numeric_start = FindNumericStart(version);
const size_t numeric_end = FindNumericEnd(version, numeric_start);
@@ -167,10 +146,29 @@ ParsedVersion ParseVersion(const std::string& version) {
numeric_end - numeric_start));
const std::string suffix = version.substr(numeric_end);
size_t date_end = 0;
if (ExtractDateFromText(suffix, &parsed.date, &date_end)) {
size_t pos = 0;
while (pos < suffix.size()) {
while (pos < suffix.size() && !IsAlphaNumeric(suffix[pos])) {
pos++;
}
const size_t token_start = pos;
while (pos < suffix.size() && IsAlphaNumeric(suffix[pos])) {
pos++;
}
if (token_start == pos) {
continue;
}
const std::string token = suffix.substr(token_start, pos - token_start);
if (parsed.date.empty() && IsCompactDateAt(token, 0)) {
parsed.date = CompactDateToIso(token);
continue;
}
int patch = 0;
if (ExtractPatchAfterDate(suffix, date_end, &patch)) {
if (!parsed.has_patch && TryParseInlinePatch(token, &patch)) {
parsed.has_patch = true;
parsed.patch = patch;
}
@@ -280,6 +278,8 @@ bool IsNewerVersionWithMetadata(const std::string& current,
const std::string& latest,
const std::string& latest_date,
int latest_patch) {
(void)latest_date;
const ParsedVersion current_version = ParseVersion(current);
const ParsedVersion latest_version = ParseVersion(latest);
@@ -292,21 +292,6 @@ bool IsNewerVersionWithMetadata(const std::string& current,
return false;
}
const std::string resolved_latest_date =
!latest_date.empty() ? latest_date : latest_version.date;
if (!resolved_latest_date.empty() && !current_version.date.empty()) {
if (resolved_latest_date > current_version.date) {
return true;
}
if (resolved_latest_date < current_version.date) {
return false;
}
} else if (!resolved_latest_date.empty() && current_version.date.empty()) {
return true;
} else if (resolved_latest_date.empty() && !current_version.date.empty()) {
return false;
}
const bool metadata_has_patch = latest_patch >= 0;
const bool latest_has_patch = metadata_has_patch || latest_version.has_patch;
if (latest_has_patch || current_version.has_patch) {
+54
View File
@@ -0,0 +1,54 @@
#include "version_checker.h"
#include <iostream>
#include <string>
namespace {
bool ExpectEqual(const std::string& name, bool actual, bool expected) {
if (actual == expected) {
return true;
}
std::cerr << name << " mismatch\n"
<< " expected: " << expected << "\n"
<< " actual: " << actual << "\n";
return false;
}
} // namespace
int main() {
bool ok = true;
ok &= ExpectEqual("new patch-before-date is newer",
crossdesk::IsNewerVersionWithMetadata(
"v1.3.5-20260529", "v1.3.5-1-20260529", "", -1),
true);
ok &= ExpectEqual("larger patch wins regardless of date",
crossdesk::IsNewerVersionWithMetadata(
"v1.3.5-2-20260530", "v1.3.5-3-20260529", "", -1),
true);
ok &= ExpectEqual("smaller patch loses regardless of date",
crossdesk::IsNewerVersionWithMetadata(
"v1.3.5-3-20260529", "v1.3.5-2-20260530", "", -1),
false);
ok &= ExpectEqual("old date-before-patch remains supported",
crossdesk::IsNewerVersionWithMetadata(
"v1.3.5-20260529-1", "v1.3.5-20260529-2", "", -1),
true);
ok &= ExpectEqual("metadata patch overrides date",
crossdesk::IsNewerVersionWithMetadata(
"v1.3.5-9-20260530", "v1.3.5", "2026-05-31", 10),
true);
ok &= ExpectEqual("date alone does not update same version",
crossdesk::IsNewerVersionWithMetadata(
"v1.3.5-20260529", "v1.3.5-20260530", "", -1),
false);
ok &= ExpectEqual("numeric version still wins",
crossdesk::IsNewerVersionWithMetadata(
"v1.3.5-9-20260529", "v1.3.6-1-20260529", "", -1),
true);
return ok ? 0 : 1;
}
+8
View File
@@ -70,6 +70,14 @@ function setup_targets()
set_default(false)
add_files("tests/display_popup_hover_state_test.cpp")
target("version_checker_test")
set_kind("binary")
set_default(false)
add_packages("cpp-httplib")
add_includedirs("src/version_checker")
add_files("tests/version_checker_test.cpp",
"src/version_checker/version_checker.cpp")
target("screen_capturer")
set_kind("object")
add_deps("rd_log", "common")