Skip to content

Commit 12ee336

Browse files
committed
fix(arch)+ci: clone the latest release tag, guard it in CI
install.sh's Arch path now clones the resolved release tag ($RELEASE_TAG) instead of a hard-coded branch, matching what deb/rpm/tarball already do (all four targets follow the same published release). A published tag always has a downloadable archive and its PKGBUILD pins _tag to that version, so makepkg's source=() can never 404 — and Arch tracks the latest release automatically, nothing hard-coded. Add tests/test-install-arch-source.sh + a CI job reproducing the installer's Arch chain (resolve the cloned ref -> read its PKGBUILD _tag -> assert archive/v$_tag.tar.gz is HTTP 200). It fails on the broken state (clone master -> 1.4.0-beta -> 404) and passes on the fixed state, so a future master bump to an unreleased version, a stale hard-coded branch, or a tag/_tag mismatch is caught in CI before users hit it (#17). (cherry picked from commit 35c7687)
1 parent 4ec75f9 commit 12ee336

3 files changed

Lines changed: 98 additions & 9 deletions

File tree

.github/workflows/rust.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ jobs:
7070
- name: Audit packaging deps manifest vs builders
7171
run: python3 packaging/audit-deps.py
7272

73+
test-install-arch-source:
74+
runs-on: ubuntu-latest
75+
steps:
76+
- uses: actions/checkout@v5
77+
- name: Verify the Arch installer resolves to an existing source tarball
78+
# Guards against issue #17: the Arch install path must clone a ref
79+
# whose PKGBUILD _tag points at a tarball that actually exists (HTTP
80+
# 200). Catches a master bump to an unreleased version, a stale
81+
# hard-coded branch, or any tag/_tag mismatch — before users hit it.
82+
run: bash tests/test-install-arch-source.sh
83+
7384
test-x86:
7485
runs-on: ubuntu-latest
7586
steps:
@@ -93,7 +104,7 @@ jobs:
93104
run: cargo test --verbose
94105

95106
release:
96-
needs: [lint, test-postprocess, test-apply-continuation, test-transcribe-routing, packaging-audit, test-x86, test-arm64]
107+
needs: [lint, test-postprocess, test-apply-continuation, test-transcribe-routing, packaging-audit, test-install-arch-source, test-x86, test-arm64]
97108
# Disabled: dictee ships locally-built CUDA assets that CI cannot produce,
98109
# so a tag push must NOT auto-publish an empty release (it would also flip
99110
# the GitHub "Latest" pointer and break install.sh's asset lookup for

install.sh

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -568,14 +568,21 @@ mode_online() {
568568
fi
569569
fi
570570

571-
info "Cloning the dictee repository (release/1.3)..."
572-
# Clone the matching release branch for Arch (not master): makepkg
573-
# then builds THIS release's PKGBUILD, whose source= fetches the
574-
# release's version tag archive (v1.3.5). PKGBUILD packaging fixes
575-
# still ship without a binary version bump — the tag archive is the
576-
# frozen binary source. The 1.4 line ships its own install.sh that
577-
# clones master.
578-
git clone --depth 1 --branch release/1.3 "https://github.com/${REPO}.git" dictee-src
571+
info "Cloning dictee at the latest release tag (${RELEASE_TAG})..."
572+
# Clone the resolved release TAG ($RELEASE_TAG), NOT master. This
573+
# mirrors what the deb/rpm/tarball paths already do — they pull assets
574+
# from the release tag — so all four targets follow the same published
575+
# release. The Arch path builds from source, so it clones the tag to
576+
# read its PKGBUILD; makepkg then builds it via source=()
577+
# (archive/v$_tag.tar.gz). Cloning the tag guarantees that archive
578+
# exists: a published tag always has a downloadable archive, and the
579+
# tag's PKGBUILD pins _tag to that same version. master must NOT be
580+
# cloned — it can sit ahead on an unreleased dev version (e.g.
581+
# 1.4.0-beta) whose tag does not exist yet, making makepkg fetch a 404
582+
# archive and abort (issue #17). Tracking $RELEASE_TAG also means Arch
583+
# follows the latest published release automatically, nothing
584+
# hard-coded. $RELEASE_TAG is set above (latest stable, or --version).
585+
git clone --depth 1 --branch "$RELEASE_TAG" "https://github.com/${REPO}.git" dictee-src
579586
cd dictee-src
580587

581588
info "Building via makepkg (this will compile from source)..."

tests/test-install-arch-source.sh

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/bin/env bash
2+
# test-install-arch-source.sh — guard against issue #17.
3+
#
4+
# The online installer's Arch path clones a git ref so makepkg can read its
5+
# PKGBUILD; makepkg then re-fetches the tagged tarball declared in the
6+
# PKGBUILD's source=() (archive/v$_tag.tar.gz) and builds THAT. If the
7+
# cloned ref's PKGBUILD points _tag at a version that was never tagged
8+
# (e.g. an in-dev 1.4.0-beta on master), the download 404s and makepkg
9+
# aborts for every Arch/CachyOS user.
10+
#
11+
# This test reproduces the exact chain the installer takes and asserts the
12+
# resulting source tarball actually exists (HTTP 200). It fails on the
13+
# broken state (clone master -> _tag=1.4.0-beta -> 404) and passes on the
14+
# fixed state (clone the latest release tag / release branch -> 200).
15+
#
16+
# Usage: test-install-arch-source.sh [path-to-install.sh]
17+
# defaults to the install.sh at the repo root next to this test.
18+
19+
set -uo pipefail
20+
21+
REPO="rcspam/dictee"
22+
INSTALL_SH="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/install.sh}"
23+
24+
fail() { echo "FAIL: $*" >&2; exit 1; }
25+
26+
[[ -r "$INSTALL_SH" ]] || fail "install.sh not readable: $INSTALL_SH"
27+
28+
# 1. Find the Arch clone line (ignore the unrelated AUR dotool clone).
29+
clone_line="$(grep -E 'git clone .*dictee-src' "$INSTALL_SH" | grep -vE 'aur\.archlinux' | head -1)"
30+
[[ -n "$clone_line" ]] || fail "no 'git clone ... dictee-src' line found in $INSTALL_SH"
31+
32+
# 2. Extract the --branch argument. It may be a literal ref (a branch like
33+
# release/1.3 or a tag like v1.3.5) or the $RELEASE_TAG variable. A bare
34+
# clone with no --branch checks out the repo's default branch (master).
35+
ref=""
36+
if [[ "$clone_line" =~ --branch[[:space:]]+([^[:space:]]+) ]]; then
37+
ref="${BASH_REMATCH[1]}"
38+
ref="${ref%\"}"; ref="${ref#\"}" # strip surrounding double quotes
39+
fi
40+
41+
case "$ref" in
42+
"")
43+
ref="master" ;; # bare clone -> default branch
44+
*'$RELEASE_TAG'*|*'${RELEASE_TAG}'*)
45+
# Installer clones the resolved latest-release tag. Resolve it the
46+
# same way install.sh does, so we exercise the real chain.
47+
ref="$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" \
48+
| grep -Po '"tag_name"\s*:\s*"\K[^"]+' | head -1)"
49+
[[ -n "$ref" ]] || fail "cannot resolve \$RELEASE_TAG from /releases/latest" ;;
50+
*'$'*)
51+
fail "unsupported variable in install.sh --branch argument: $ref" ;;
52+
esac
53+
echo "Installer resolves Arch source to ref: $ref"
54+
55+
# 3. Read that ref's PKGBUILD and extract _tag (the version makepkg fetches).
56+
pkgbuild="$(curl -fsSL "https://raw.githubusercontent.com/${REPO}/${ref}/PKGBUILD")" \
57+
|| fail "cannot fetch PKGBUILD from ref '$ref'"
58+
tag="$(printf '%s\n' "$pkgbuild" | grep -E '^_tag=' | head -1 | cut -d= -f2)"
59+
[[ -n "$tag" ]] || fail "no _tag= in PKGBUILD of ref '$ref'"
60+
echo "PKGBUILD _tag: $tag"
61+
62+
# 4. The chain only works if archive/v$_tag.tar.gz exists (what makepkg's
63+
# source=() downloads). Assert HTTP 200.
64+
url="https://github.com/${REPO}/archive/v${tag}.tar.gz"
65+
code="$(curl -fsS -o /dev/null -w '%{http_code}' -L "$url")"
66+
echo "Source archive $url -> HTTP $code"
67+
68+
[[ "$code" == "200" ]] \
69+
|| fail "Arch installer would fetch a non-existent tarball (HTTP $code) for v$tag — see issue #17"
70+
71+
echo "PASS: installer's Arch source chain resolves to an existing tarball (v$tag)"

0 commit comments

Comments
 (0)