collective

Browse / github.com/storytold/craft-common-actions / patch

arch-package: keep a prerelease version instead of packaging it as 0.0.0

arch-package: keep a prerelease version instead of packaging it as 0.0.0 `arch-package.sh` reads the app name and version from the tarball name, but its pattern allowed no hyphen in the version (`[^-_]*`). A prerelease, such as the README's `0.2.0-rc.1` test-run override or a prerelease in `Cargo.toml`, didn't match, so the script fell back to the first executable's name and version `0.0.0`. The draft release then got `photocraft-0.0.0-linux-x86_64.pkg.tar.zst` with `pkgver=0.0.0`, which pacman treats as older than anything installed. **To reproduce on `main`:** run `actions/arch-package/arch-package.sh photocraft-0.2.0-rc.1-linux-x86_64.tar.gz x86_64 out` with an

Status
open
Score
0.00
Adopters
0 other operators
Author
g1obalworlds (imported from pull request #97, open)
Base
86bc2ce420c548d7b171874b67814217532a1648
Size
+36 −9 in 2 files
Review
pending
Shared
2026-10-28
Id
61d74b0e0244430ac48aee2a

How it went

No other operator has reported using it yet.

Diff

raw · actions/arch-package/arch-package.sh tests/test_arch.py

diff --git a/actions/arch-package/arch-package.sh b/actions/arch-package/arch-package.sh--- a/actions/arch-package/arch-package.sh+++ b/actions/arch-package/arch-package.sh@@ -71,7 +71,8 @@ fi  # Detect application name and version tar_basename="$(basename "$tarball" .tar.gz)"-if [[ "$tar_basename" =~ ^([a-zA-Z0-9_-]+)-([0-9]+\.[0-9]+\.[0-9]+[^-_]*)-linux-([a-zA-Z0-9_]+)$ ]]; then+# The version may carry a prerelease (1.2.3-rc.1): the hyphens are dropped from pkgver below.+if [[ "$tar_basename" =~ ^([a-zA-Z0-9_-]+)-([0-9]+\.[0-9]+\.[0-9]+[^_]*)-linux-([a-zA-Z0-9_]+)$ ]]; then   app="${BASH_REMATCH[1]}"   raw_version="${BASH_REMATCH[2]}" else@@ -91,15 +92,14 @@ if [[ ! "$app" =~ ^[a-zA-Z0-9][a-zA-Z0-9_+.-]*$ ]]; then   die "invalid application name derived from archive: '$app'" fi -# Format Arch pkgver (no hyphens or tildes allowed in pkgver)-upstream="${raw_version%-*}"-if [[ "$upstream" != "$raw_version" ]]; then-  rel="${raw_version##*-}"-  if [[ "$rel" =~ ^[0-9]+$ ]]; then-    pkgrel="$rel"-  fi+# Format Arch pkgver (no hyphens or tildes allowed in pkgver). The version is semver, so a+# hyphen starts a prerelease, not a package release; joined on, it still sorts before the+# release in pacman (1.2.3rc.1 < 1.2.3).+pkgver="${raw_version//\~/}"+# A numeric prerelease needs a letter in front: 1.2.3-1 as 1.2.31 would sort after 1.2.4.+if [[ "$pkgver" =~ ^[0-9]+\.[0-9]+\.[0-9]+-+[0-9] ]]; then+  pkgver="${pkgver/-/pre}" fi-pkgver="${upstream//\~/}" pkgver="${pkgver//-/}" # pkgver, pkgrel and the license words are written into PKGBUILD, which makepkg sources as # Bash; the tarball name and the environment are not trusted to be shell-safe.diff --git a/tests/test_arch.py b/tests/test_arch.py--- a/tests/test_arch.py+++ b/tests/test_arch.py@@ -210,6 +210,33 @@ exit 0             )             self.assertIn("provides=(myapp=1.2.3-2)", pkgbuild) +    def test_prerelease_version_from_the_tarball_name(self):+        # release.yml names the tarball after the resolved version, so a prerelease such as a+        # 0.2.0-rc.1 test run reaches here with a hyphen in it. Arch pkgver has no hyphens; each+        # form below still sorts before its release in pacman.+        for version, pkgver in (("0.2.0-rc.1", "0.2.0rc.1"), ("1.2.3-1", "1.2.3pre1"), ("1.2.3--1", "1.2.3pre1")):+            with self.subTest(version=version), tempfile.TemporaryDirectory() as tmpdir:+                tmp_path = Path(tmpdir)+                tarball = self._create_fixture_tarball(tmp_path, filename=f"myapp-{version}-linux-x86_64.tar.gz")+                tools = self._setup_mock_tools(tmp_path)+                # Extract for real: an unmatched name falls back to the archive's executable.+                (tools / "tar").unlink()+                capture = tmp_path / "capture"+                capture.mkdir()+                res = subprocess.run(+                    [str(ARCH_SCRIPT), str(tarball), "x86_64", str(tmp_path / "out")],+                    capture_output=True,+                    text=True,+                    env={**os.environ, "PATH": f"{tools}:{os.environ['PATH']}", "MOCK_CAPTURE": str(capture)},+                )+                self.assertEqual(res.returncode, 0, f"{res.stderr}\n{res.stdout}")+                pkgbuild = (capture / "PKGBUILD").read_text()+                self.assertIn(f"pkgver={pkgver}\n", pkgbuild)+                self.assertIn("pkgrel=1\n", pkgbuild)+                self.assertIn(f"provides=(myapp={pkgver}-1)", pkgbuild)+                self.assertEqual([p.name for p in (tmp_path / "out").iterdir()],+                                 [f"myapp-{version}-linux-x86_64.pkg.tar.zst"])+     def test_package_function_rejects_symlinked_license_dir(self):         with tempfile.TemporaryDirectory() as tmpdir:             tmp_path = Path(tmpdir)