From 65d8284fb89ce22cd42d0d6e2a37d6f40351cb83 Mon Sep 17 00:00:00 2001 From: kunkundi Date: Fri, 29 May 2026 00:52:07 +0800 Subject: [PATCH] [ci] standardize hotfix package version ordering across platforms --- .github/workflows/build.yml | 35 +++++++++---- .github/workflows/update-version-json.yml | 9 +++- scripts/linux/pkg_amd64.sh | 20 ++++++- scripts/linux/pkg_arm64.sh | 20 ++++++- scripts/macosx/pkg_arm64.sh | 20 ++++++- scripts/macosx/pkg_x64.sh | 20 ++++++- scripts/windows/pkg_x64.ps1 | 40 ++++++++++++++ src/version_checker/version_checker.cpp | 63 +++++++++-------------- tests/version_checker_test.cpp | 54 +++++++++++++++++++ xmake/targets.lua | 8 +++ 10 files changed, 234 insertions(+), 55 deletions(-) create mode 100644 scripts/windows/pkg_x64.ps1 create mode 100644 tests/version_checker_test.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d6f7510..450e402 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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 diff --git a/.github/workflows/update-version-json.yml b/.github/workflows/update-version-json.yml index 4700b0d..2b14ec2 100644 --- a/.github/workflows/update-version-json.yml +++ b/.github/workflows/update-version-json.yml @@ -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]}" diff --git a/scripts/linux/pkg_amd64.sh b/scripts/linux/pkg_amd64.sh index eb68104..be9fab2 100644 --- a/scripts/linux/pkg_amd64.sh +++ b/scripts/linux/pkg_amd64.sh @@ -4,13 +4,31 @@ set -e PKG_NAME="crossdesk" APP_NAME="CrossDesk" -APP_VERSION="$1" ARCHITECTURE="amd64" MAINTAINER="Junkun Di " 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}" diff --git a/scripts/linux/pkg_arm64.sh b/scripts/linux/pkg_arm64.sh index 7d304f9..ff97436 100644 --- a/scripts/linux/pkg_arm64.sh +++ b/scripts/linux/pkg_arm64.sh @@ -4,13 +4,31 @@ set -e PKG_NAME="crossdesk" APP_NAME="CrossDesk" -APP_VERSION="$1" ARCHITECTURE="arm64" MAINTAINER="Junkun Di " 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}" diff --git a/scripts/macosx/pkg_arm64.sh b/scripts/macosx/pkg_arm64.sh index ff37114..edf3eeb 100755 --- a/scripts/macosx/pkg_arm64.sh +++ b/scripts/macosx/pkg_arm64.sh @@ -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" diff --git a/scripts/macosx/pkg_x64.sh b/scripts/macosx/pkg_x64.sh index 37b7a97..0d4babc 100755 --- a/scripts/macosx/pkg_x64.sh +++ b/scripts/macosx/pkg_x64.sh @@ -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" diff --git a/scripts/windows/pkg_x64.ps1 b/scripts/windows/pkg_x64.ps1 new file mode 100644 index 0000000..83fc30f --- /dev/null +++ b/scripts/windows/pkg_x64.ps1 @@ -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 +} diff --git a/src/version_checker/version_checker.cpp b/src/version_checker/version_checker.cpp index 5cf3b62..196692c 100644 --- a/src/version_checker/version_checker.cpp +++ b/src/version_checker/version_checker.cpp @@ -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) { diff --git a/tests/version_checker_test.cpp b/tests/version_checker_test.cpp new file mode 100644 index 0000000..1ff14c0 --- /dev/null +++ b/tests/version_checker_test.cpp @@ -0,0 +1,54 @@ +#include "version_checker.h" + +#include +#include + +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; +} diff --git a/xmake/targets.lua b/xmake/targets.lua index f9bddc9..f7a86ab 100644 --- a/xmake/targets.lua +++ b/xmake/targets.lua @@ -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")