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
@@ -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.@@ -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)