Self-host tarballs on asger.weirsoe.dk instead of GitHub Releases
Serve from /srv/tarballz on CT148 via a 'location /tarballz/' alias, NOT from under /var/www/asger: the asger-web deploy swaps that whole directory atomically, so tarballs kept inside it would be deleted on the next site deploy. CT148's rootfs was 3G with 2.7G free - one tarball would have filled it - so it is grown to 15G; speedy's thin pool has room even though vgs reports the VG nearly full. Publishing uploads to a .part name and renames on arrival so a download can never see a truncated file, verifies sha256 on the host, then fetches the public URL and checks it against the sha256 baked into the PKGBUILD. Both checks run before the AUR push, so the package cannot go out pointing at a missing file. Old tarballs are pruned to the newest three. GH_TOKEN is kept but demoted to an optional GITHUB_PAT for R module downloads; it no longer has anything to do with publishing.
This commit is contained in:
@@ -40,8 +40,8 @@ def main() -> int:
|
||||
ap.add_argument("--build-info", required=True)
|
||||
ap.add_argument("--template", required=True)
|
||||
ap.add_argument("--out", required=True)
|
||||
ap.add_argument("--gh-owner", required=True)
|
||||
ap.add_argument("--gh-repo", default="jasp-desktop-bin")
|
||||
ap.add_argument("--base-url", required=True,
|
||||
help="public directory the tarball is served from")
|
||||
ap.add_argument("--maintainer", required=True)
|
||||
ap.add_argument("--pkgname", default="jasp-desktop-bin")
|
||||
args = ap.parse_args()
|
||||
@@ -58,10 +58,7 @@ def main() -> int:
|
||||
print(f"new version {jasp_version}: pkgrel 1")
|
||||
|
||||
tag = f"v{jasp_version}-{pkgrel}"
|
||||
download_url = (
|
||||
f"https://github.com/{args.gh_owner}/{args.gh_repo}"
|
||||
f"/releases/download/{tag}/{info['tarball']}"
|
||||
)
|
||||
download_url = f"{args.base_url.rstrip('/')}/{info['tarball']}"
|
||||
|
||||
qt_minor = info["qt6_minor"]
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Create (or reuse) a GitHub release and upload the JASP tarball to it.
|
||||
# Uses the REST API directly so the workflow does not depend on `gh` being
|
||||
# present in the runner image.
|
||||
#
|
||||
# GH_TOKEN PAT with `contents: write` on the target repo (required)
|
||||
# GH_OWNER GitHub account owning the release repo (required)
|
||||
# GH_REPO release repo name (default jasp-desktop-bin)
|
||||
# TAG release tag, e.g. v0.98.1-1 (required)
|
||||
# ASSET path to the tarball to upload (required)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
: "${GH_TOKEN:?GH_TOKEN is required}"
|
||||
: "${GH_OWNER:?GH_OWNER is required}"
|
||||
: "${TAG:?TAG is required}"
|
||||
: "${ASSET:?ASSET is required}"
|
||||
GH_REPO="${GH_REPO:-jasp-desktop-bin}"
|
||||
|
||||
API="https://api.github.com/repos/${GH_OWNER}/${GH_REPO}"
|
||||
UPLOADS="https://uploads.github.com/repos/${GH_OWNER}/${GH_REPO}"
|
||||
AUTH=(-H "Authorization: Bearer ${GH_TOKEN}" -H "Accept: application/vnd.github+json")
|
||||
|
||||
asset_name="$(basename "$ASSET")"
|
||||
|
||||
echo ":: looking for existing release $TAG"
|
||||
release_id="$(curl -sSf "${AUTH[@]}" "${API}/releases/tags/${TAG}" 2>/dev/null \
|
||||
| python3 -c 'import json,sys; print(json.load(sys.stdin).get("id",""))' 2>/dev/null || true)"
|
||||
|
||||
if [[ -z "$release_id" ]]; then
|
||||
echo ":: creating release $TAG"
|
||||
release_id="$(curl -sSf -X POST "${AUTH[@]}" "${API}/releases" \
|
||||
-d "$(python3 -c '
|
||||
import json, os
|
||||
print(json.dumps({
|
||||
"tag_name": os.environ["TAG"],
|
||||
"name": "JASP " + os.environ["TAG"],
|
||||
"body": os.environ.get("RELEASE_NOTES", ""),
|
||||
"draft": False,
|
||||
"prerelease": False,
|
||||
}))')" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"
|
||||
else
|
||||
echo ":: reusing release $release_id"
|
||||
# Replace a same-named asset so re-runs are idempotent.
|
||||
old="$(curl -sSf "${AUTH[@]}" "${API}/releases/${release_id}/assets" \
|
||||
| python3 -c "
|
||||
import json, sys
|
||||
name = '${asset_name}'
|
||||
print(next((a['id'] for a in json.load(sys.stdin) if a['name'] == name), ''))
|
||||
")"
|
||||
if [[ -n "$old" ]]; then
|
||||
echo ":: deleting previous asset $old"
|
||||
curl -sSf -X DELETE "${AUTH[@]}" "${API}/releases/assets/${old}"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ":: uploading $asset_name ($(du -h "$ASSET" | cut -f1))"
|
||||
curl -sSf -X POST "${AUTH[@]}" \
|
||||
-H "Content-Type: application/zstd" \
|
||||
--data-binary "@${ASSET}" \
|
||||
"${UPLOADS}/releases/${release_id}/assets?name=${asset_name}" >/dev/null
|
||||
|
||||
echo ":: uploaded to https://github.com/${GH_OWNER}/${GH_REPO}/releases/tag/${TAG}"
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
# Publish the built tarball to asger.weirsoe.dk, which is what the AUR PKGBUILD
|
||||
# downloads from.
|
||||
#
|
||||
# TARBALL_SSH_KEY private key authorised on the web host (required)
|
||||
# TARBALL_HOST web host, e.g. 192.168.10.148 (required)
|
||||
# TARBALL_PATH directory on that host (required)
|
||||
# KEEP_RELEASES how many tarballs to retain (default 3)
|
||||
# $1 path to the tarball to upload
|
||||
#
|
||||
# The files live in /srv/tarballz, deliberately NOT under /var/www/asger: the
|
||||
# asger-web deploy replaces that directory atomically (build into .new, swap,
|
||||
# delete .old), so anything stored inside it disappears on the next site deploy.
|
||||
# nginx exposes /srv/tarballz via a `location /tarballz/` alias.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
TARBALL="${1:?path to tarball is required}"
|
||||
: "${TARBALL_SSH_KEY:?TARBALL_SSH_KEY is required}"
|
||||
: "${TARBALL_HOST:?TARBALL_HOST is required}"
|
||||
: "${TARBALL_PATH:?TARBALL_PATH is required}"
|
||||
KEEP_RELEASES="${KEEP_RELEASES:-3}"
|
||||
|
||||
name="$(basename "$TARBALL")"
|
||||
|
||||
mkdir -p ~/.ssh
|
||||
printf '%s\n' "$TARBALL_SSH_KEY" > ~/.ssh/tarball_key
|
||||
chmod 600 ~/.ssh/tarball_key
|
||||
ssh-keyscan -t ed25519 "$TARBALL_HOST" >> ~/.ssh/known_hosts 2>/dev/null || true
|
||||
SSH=(ssh -i "$HOME/.ssh/tarball_key" -o StrictHostKeyChecking=accept-new)
|
||||
|
||||
echo ":: uploading ${name} ($(du -h "$TARBALL" | cut -f1)) to ${TARBALL_HOST}:${TARBALL_PATH}"
|
||||
|
||||
# Upload to a temporary name and rename on arrival, so a download that starts
|
||||
# mid-transfer can never see a truncated file at the final URL.
|
||||
"${SSH[@]}" "root@${TARBALL_HOST}" "mkdir -p '${TARBALL_PATH}'"
|
||||
"${SSH[@]}" "root@${TARBALL_HOST}" "cat > '${TARBALL_PATH}/.${name}.part'" < "$TARBALL"
|
||||
"${SSH[@]}" "root@${TARBALL_HOST}" "mv '${TARBALL_PATH}/.${name}.part' '${TARBALL_PATH}/${name}' && chmod 644 '${TARBALL_PATH}/${name}'"
|
||||
|
||||
echo ":: verifying the uploaded copy matches"
|
||||
local_sum="$(sha256sum "$TARBALL" | awk '{print $1}')"
|
||||
remote_sum="$("${SSH[@]}" "root@${TARBALL_HOST}" "sha256sum '${TARBALL_PATH}/${name}'" | awk '{print $1}')"
|
||||
if [[ "$local_sum" != "$remote_sum" ]]; then
|
||||
echo "error: checksum mismatch after upload" >&2
|
||||
echo " local $local_sum" >&2
|
||||
echo " remote $remote_sum" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo ":: sha256 matches ($local_sum)"
|
||||
|
||||
# Old releases are kept so that a user mid-install of the previous version is
|
||||
# not left with a dead URL, but not forever - each one is well over a gigabyte.
|
||||
echo ":: pruning to the newest ${KEEP_RELEASES} tarballs"
|
||||
"${SSH[@]}" "root@${TARBALL_HOST}" "
|
||||
cd '${TARBALL_PATH}' || exit 0
|
||||
ls -1t jasp-desktop-*.tar.zst 2>/dev/null | tail -n +\$((${KEEP_RELEASES} + 1)) | while read -r old; do
|
||||
echo \" removing \$old\"
|
||||
rm -f -- \"\$old\"
|
||||
done
|
||||
echo ' remaining:'
|
||||
ls -1sh jasp-desktop-*.tar.zst 2>/dev/null | sed 's/^/ /'
|
||||
"
|
||||
|
||||
echo ":: published"
|
||||
Reference in New Issue
Block a user