Compare commits
2
Commits
v0.4.20-win
...
v0.4.21
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
670450ccfd | ||
|
|
9fadfbc37a |
@@ -319,21 +319,23 @@ jobs:
|
||||
TRIPLE_C_BUILD_SUFFIX: ${{ needs.compute-version.outputs.suffix }}
|
||||
run: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
npx tauri build
|
||||
# AppImage only: the .deb and .rpm were dropped in favour of the one
|
||||
# artifact that runs everywhere, and building them is pure cost.
|
||||
# Left as "all" in tauri.conf.json so macOS and Windows are unaffected.
|
||||
npx tauri build --bundles appimage
|
||||
|
||||
# linuxdeploy bundles a libwayland-client.so.0 that shadows the host's
|
||||
# and breaks Mesa's EGL on systems newer than the build runner, so the
|
||||
# window comes up blank. It has to come from the host; see the script
|
||||
# header for the evidence and the trade.
|
||||
- name: Unbundle the host-coupled Wayland client
|
||||
run: bash scripts/unbundle-wayland-client.sh app/src-tauri/target/release/bundle/appimage
|
||||
- name: Finalize the AppImage
|
||||
run: bash scripts/finalize-appimage.sh app/src-tauri/target/release/bundle/appimage
|
||||
|
||||
- name: Collect artifacts
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
cp app/src-tauri/target/release/bundle/appimage/*.AppImage artifacts/ 2>/dev/null || true
|
||||
cp app/src-tauri/target/release/bundle/deb/*.deb artifacts/ 2>/dev/null || true
|
||||
cp app/src-tauri/target/release/bundle/rpm/*.rpm artifacts/ 2>/dev/null || true
|
||||
cp app/src-tauri/target/release/bundle/appimage/*.zsync artifacts/ 2>/dev/null || true
|
||||
ls -la artifacts/
|
||||
|
||||
# Assets, not workflow artifacts — see the note at the top of this file.
|
||||
|
||||
@@ -185,21 +185,23 @@ jobs:
|
||||
working-directory: ./app
|
||||
run: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
npx tauri build
|
||||
# AppImage only: the .deb and .rpm were dropped in favour of the one
|
||||
# artifact that runs everywhere, and building them is pure cost.
|
||||
# Left as "all" in tauri.conf.json so macOS and Windows are unaffected.
|
||||
npx tauri build --bundles appimage
|
||||
|
||||
# linuxdeploy bundles a libwayland-client.so.0 that shadows the host's
|
||||
# and breaks Mesa's EGL on systems newer than the build runner, so the
|
||||
# window comes up blank. It has to come from the host; see the script
|
||||
# header for the evidence and the trade.
|
||||
- name: Unbundle the host-coupled Wayland client
|
||||
run: bash scripts/unbundle-wayland-client.sh app/src-tauri/target/release/bundle/appimage
|
||||
- name: Finalize the AppImage
|
||||
run: bash scripts/finalize-appimage.sh app/src-tauri/target/release/bundle/appimage
|
||||
|
||||
- name: Collect artifacts
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
cp app/src-tauri/target/release/bundle/appimage/*.AppImage artifacts/ 2>/dev/null || true
|
||||
cp app/src-tauri/target/release/bundle/deb/*.deb artifacts/ 2>/dev/null || true
|
||||
cp app/src-tauri/target/release/bundle/rpm/*.rpm artifacts/ 2>/dev/null || true
|
||||
cp app/src-tauri/target/release/bundle/appimage/*.zsync artifacts/ 2>/dev/null || true
|
||||
ls -la artifacts/
|
||||
|
||||
- name: Upload to Gitea release
|
||||
@@ -277,6 +279,15 @@ jobs:
|
||||
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets?name=${filename}"
|
||||
done
|
||||
|
||||
# The fixed tag every installed AppImage checks for updates. Separate
|
||||
# from the versioned release above because the updater's URL must never
|
||||
# move, and `releases/latest` does.
|
||||
- name: Publish the Linux update channel
|
||||
if: gitea.event_name == 'push'
|
||||
env:
|
||||
GH_PAT: ${{ secrets.GH_PAT }}
|
||||
run: bash scripts/publish-update-channel.sh artifacts
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
needs: [compute-version]
|
||||
|
||||
@@ -679,8 +679,26 @@ deliberately out of scope — this is not a project backup.
|
||||
|
||||
## Packaging
|
||||
|
||||
Linux ships as `.deb`, `.rpm` and AppImage, all three built by `build-app.yml` (releases) and
|
||||
`build-app-preview.yml` (the PR check). **There is deliberately no Arch package.** A
|
||||
Linux ships as **AppImage only**, built by `build-app.yml` (releases) and
|
||||
`build-app-preview.yml` (the PR check). The `.deb` and `.rpm` were dropped: two more artifacts to
|
||||
build and publish for an audience the AppImage already serves, and neither could self-update. The
|
||||
Linux job passes `--bundles appimage`; `tauri.conf.json` still says `"targets": "all"` so macOS and
|
||||
Windows are untouched.
|
||||
|
||||
`scripts/finalize-appimage.sh` post-processes every AppImage, and both things it does are
|
||||
load-bearing. **It demotes the bundled `libwayland-client.so.0`** off the loader path, keeping it as
|
||||
a fallback for a host that has none: `libEGL_mesa.so.0` has a hard `DT_NEEDED` on that library, so a
|
||||
bundled copy older than the host's Mesa stops the EGL driver loading at all and the window comes up
|
||||
blank — measured on wayland 1.26 / Mesa 26.2.1 against a 22.04-built image. Do not "fix" this by
|
||||
bundling a newer wayland: the floor is set by the user's Mesa, which moves independently of our
|
||||
releases, so this is a host-coupled library like libGL and libdrm. **It also embeds AppStream
|
||||
metadata and update information**, without which an AppImage manager can adopt the app but never
|
||||
update it. The update URL points at a fixed `linux-latest` tag on the GitHub mirror
|
||||
(`scripts/publish-update-channel.sh`), never `releases/latest` — that follows whichever release is
|
||||
newest, and the backfill creates a GitHub release per Gitea tag including the `-win` and `-mac` ones
|
||||
that carry no AppImage. The script's post-repack assertions are the only test any of this has.
|
||||
|
||||
**There is deliberately no Arch package.** A
|
||||
`triple-c-bin` `PKGBUILD` and a `publish-arch-package.yml` existed and were removed; they live on
|
||||
`hold/arch-packaging`. Do not re-add them without the piece that was always missing: the package
|
||||
was never on the AUR, so it was a manual `pacman -U` of a downloaded file — the same gesture as
|
||||
|
||||
+5
-3
@@ -41,14 +41,16 @@ Download the build for your platform from [GitHub Releases](https://github.com/s
|
||||
|----------|------|---------|
|
||||
| **Windows** | `Triple-C_<version>_x64-setup.exe` or `.msi` | Run the installer. |
|
||||
| **macOS** | `Triple-C_<version>_universal.dmg` | Open the `.dmg` and drag Triple-C to Applications. |
|
||||
| **Debian / Ubuntu** | `Triple-C_<version>_amd64.deb` | `sudo apt install ./Triple-C_<version>_amd64.deb` |
|
||||
| **Fedora / RHEL** | `Triple-C-<version>-1.x86_64.rpm` | `sudo dnf install ./Triple-C-<version>-1.x86_64.rpm` |
|
||||
| **Arch / CachyOS / other Linux** | `Triple-C_<version>_amd64.AppImage` | `chmod +x` it, then run it directly. See the AppImage notes below. |
|
||||
| **Linux (all distributions)** | `Triple-C_<version>_amd64.AppImage` | `chmod +x` it, then run it directly. See the AppImage notes below. |
|
||||
|
||||
> **macOS note:** The app is not signed or notarized. On first launch, macOS Gatekeeper may block it — right-click the app and select "Open" to bypass, or remove the quarantine attribute: `xattr -cr /Applications/Triple-C.app`.
|
||||
|
||||
> **AppImage note:** Two things are worth knowing. Running an AppImage needs FUSE 2, which Arch and CachyOS do not install by default — `sudo pacman -S fuse2` once, or run it with `--appimage-extract-and-run` to sidestep FUSE entirely. And an AppImage is just an executable file: nothing registers it with the desktop, so it will not appear in your app launcher on its own. Run [`scripts/install-appimage.sh`](scripts/install-appimage.sh) to add a launcher entry and icons — see [Adding an AppImage to the app launcher](#adding-an-appimage-to-the-app-launcher).
|
||||
|
||||
> **Linux is AppImage only.** The `.deb` and `.rpm` were dropped. They were a second and third artifact to build, test and publish for an audience already served by the one file that runs on every distribution — and unlike the AppImage they could not be kept up to date automatically. Older releases still carry them if you need one.
|
||||
|
||||
> **Updates.** The AppImage carries update information, so an AppImage manager (Gear Lever, AppImageLauncher and similar) can adopt it and update it in place — pulling only the changed blocks rather than re-downloading 85 MB. It reads a fixed `linux-latest` tag on GitHub, so the URL never moves between versions.
|
||||
|
||||
> **No Arch package.** There was a `triple-c-bin` `.pkg.tar.zst` attached to some releases, built by a maintainer-triggered workflow. It was never on the AUR, so installing it meant downloading a file and running `pacman -U` — no better than the AppImage — and being manual-only it reached 1 release in 28, which made the promise of it worse than not making it. The `PKGBUILD` and its workflow are preserved on the `hold/arch-packaging` branch if an AUR package is ever worth doing properly.
|
||||
|
||||
### Adding an AppImage to the app launcher
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
AppStream metadata for the AppImage.
|
||||
|
||||
Without this an AppImage manager (Gear Lever, AppImageLauncher and the like)
|
||||
can adopt the file but has nothing to show for it: no summary, no category,
|
||||
no release history. appimagetool warns about its absence on every build.
|
||||
|
||||
The id matches `identifier` in tauri.conf.json and the .desktop basename, so
|
||||
the desktop entry, the AppStream component and the AppImage all name the
|
||||
same application. `@VERSION@` is substituted at build time.
|
||||
-->
|
||||
<component type="desktop-application">
|
||||
<id>com.triple-c.desktop</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>MIT</project_license>
|
||||
|
||||
<name>Triple-C</name>
|
||||
<summary>Run Claude Code sessions in isolated Docker containers</summary>
|
||||
|
||||
<description>
|
||||
<p>
|
||||
Triple-C sandboxes Claude Code inside per-project Docker containers, so an
|
||||
agent can install packages, edit files and run commands without touching
|
||||
the host. Each project gets its own container, its own credentials and its
|
||||
own terminal sessions.
|
||||
</p>
|
||||
<p>Features:</p>
|
||||
<ul>
|
||||
<li>Per-project containers with persistent home and config volumes</li>
|
||||
<li>Multiple terminal sessions per project, in one reorderable tab strip</li>
|
||||
<li>Notes that can be sent straight into a running agent's prompt</li>
|
||||
<li>Anthropic, AWS Bedrock, Ollama, llama.cpp and OpenAI-compatible backends</li>
|
||||
<li>Remote access over a browser terminal, and speech-to-text input</li>
|
||||
</ul>
|
||||
</description>
|
||||
|
||||
<launchable type="desktop-id">Triple-C.desktop</launchable>
|
||||
<categories>
|
||||
<category>Development</category>
|
||||
<category>Utility</category>
|
||||
</categories>
|
||||
|
||||
<url type="homepage">https://github.com/shadowdao/triple-c</url>
|
||||
<url type="bugtracker">https://github.com/shadowdao/triple-c/issues</url>
|
||||
|
||||
<provides>
|
||||
<binary>triple-c</binary>
|
||||
</provides>
|
||||
|
||||
<releases>
|
||||
<release version="@VERSION@" date="@DATE@"/>
|
||||
</releases>
|
||||
|
||||
<content_rating type="oars-1.1"/>
|
||||
</component>
|
||||
@@ -1,6 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Drop the bundled libwayland-client.so.0 out of a built AppImage.
|
||||
# Post-process a built AppImage: make it start on modern Mesa, and make it
|
||||
# adoptable and updatable by an AppImage manager.
|
||||
#
|
||||
# Tauri hands off to linuxdeploy, which offers no hook between building the
|
||||
# AppDir and packing it, so both jobs are done by unpacking the finished image
|
||||
# and repacking it. That is also why the update information is embedded here
|
||||
# rather than passed to the bundler.
|
||||
#
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. The bundled Wayland client
|
||||
# ---------------------------------------------------------------------------
|
||||
#
|
||||
# linuxdeploy-plugin-gtk bundles libwayland-client.so.0 as a dependency of
|
||||
# GTK, and `AppRun.wrapped` puts the bundled lib directory ahead of the host's
|
||||
@@ -44,7 +54,34 @@
|
||||
# LD_LIBRARY_PATH after its own AppDir entries, so anything the hook exports
|
||||
# lands last: a fallback, never an override.
|
||||
#
|
||||
# Usage: unbundle-wayland-client.sh <directory holding the .AppImage>
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. Metadata an AppImage manager needs
|
||||
# ---------------------------------------------------------------------------
|
||||
#
|
||||
# Two things, neither of which the bundler produces:
|
||||
#
|
||||
# * AppStream metadata, so a manager can show what the app is rather than a
|
||||
# bare filename. appimagetool warns about its absence on every build.
|
||||
# * Update information embedded in the image — the string that tells a
|
||||
# manager where to look for a newer build. Without it the app can be
|
||||
# adopted but never updated, which is the whole point.
|
||||
#
|
||||
# The update URL is a **fixed** tag on the GitHub mirror, which is where
|
||||
# updates are pulled from, rather than `releases/latest`. `latest` follows
|
||||
# whatever release is newest, and the Gitea-to-GitHub backfill creates one
|
||||
# GitHub release per Gitea tag — including the `-win` and `-mac` tags, which
|
||||
# carry no AppImage. A fixed tag cannot be pointed at a release that has none,
|
||||
# and is equally immune to a release marked prerelease.
|
||||
#
|
||||
# The output is named for the fixed tag too. zsync records the filename it was
|
||||
# generated for and a client resolves it relative to the .zsync URL, so a
|
||||
# versioned name would send every client looking for the version it already
|
||||
# has. The versioned copy is written afterwards for the normal release.
|
||||
#
|
||||
# It also fills in `Categories=`, which linuxdeploy leaves empty — that is what
|
||||
# a desktop menu and most managers use to file the application.
|
||||
#
|
||||
# Usage: finalize-appimage.sh <directory holding the .AppImage>
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -53,6 +90,15 @@ FALLBACK_DIR="usr/lib/wayland-fallback"
|
||||
HOOK="apprun-hooks/triple-c-wayland-fallback.sh"
|
||||
APPIMAGE_TOOL_URL="https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
|
||||
APP_ID="com.triple-c.desktop"
|
||||
STABLE_NAME="Triple-C_x86_64.AppImage"
|
||||
UPDATE_TAG="linux-latest"
|
||||
UPDATE_INFO="zsync|https://github.com/shadowdao/triple-c/releases/download/${UPDATE_TAG}/${STABLE_NAME}.zsync"
|
||||
CATEGORIES="Development;Utility;"
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
appdata_src="$repo_root/packaging/appimage/$APP_ID.appdata.xml"
|
||||
|
||||
dir="${1:?usage: unbundle-wayland-client.sh <bundle/appimage directory>}"
|
||||
cd "$dir"
|
||||
|
||||
@@ -133,6 +179,30 @@ open(path, "w").write(src)
|
||||
PATCH_EOF
|
||||
fi
|
||||
|
||||
# --- metadata -------------------------------------------------------------
|
||||
|
||||
# Version comes from the artifact rather than a second source that could drift.
|
||||
version="$(printf '%s' "$appimage" | sed -n 's/.*_\([0-9][0-9.]*\)_.*/\1/p')"
|
||||
[ -n "$version" ] || { echo "Could not read a version out of $appimage" >&2; exit 1; }
|
||||
|
||||
if [ -f "$appdata_src" ]; then
|
||||
mkdir -p "$root/usr/share/metainfo"
|
||||
sed -e "s/@VERSION@/$version/" -e "s/@DATE@/$(date -u +%Y-%m-%d)/" \
|
||||
"$appdata_src" > "$root/usr/share/metainfo/$APP_ID.appdata.xml"
|
||||
echo "Added AppStream metadata for $version."
|
||||
else
|
||||
echo "No AppStream source at $appdata_src — skipping." >&2
|
||||
fi
|
||||
|
||||
# linuxdeploy emits `Categories=` empty, which files the app nowhere.
|
||||
for desktop in "$root"/*.desktop; do
|
||||
[ -e "$desktop" ] || continue
|
||||
if grep -q "^Categories=$" "$desktop"; then
|
||||
sed -i "s/^Categories=$/Categories=$CATEGORIES/" "$desktop"
|
||||
echo "Filled in Categories for $(basename "$desktop")."
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Demoted $LIB to $FALLBACK_DIR; repacking."
|
||||
|
||||
tool="$work/appimagetool"
|
||||
@@ -140,7 +210,14 @@ curl -fsSL -o "$tool" "$APPIMAGE_TOOL_URL"
|
||||
chmod +x "$tool"
|
||||
|
||||
# --appimage-extract-and-run: CI runners generally have no FUSE.
|
||||
ARCH=x86_64 "$tool" --appimage-extract-and-run "$root" "$appimage" >/dev/null
|
||||
# -u embeds the update string and writes "$STABLE_NAME.zsync" beside the image.
|
||||
ARCH=x86_64 "$tool" --appimage-extract-and-run \
|
||||
-u "$UPDATE_INFO" "$root" "$STABLE_NAME" >/dev/null
|
||||
chmod +x "$STABLE_NAME"
|
||||
|
||||
# The versioned name is what the per-version release publishes; the stable one
|
||||
# and its .zsync go to the rolling tag. Same bytes, two names.
|
||||
cp "$STABLE_NAME" "$appimage"
|
||||
chmod +x "$appimage"
|
||||
|
||||
# The guards are the test. Each one is a way the repack could look like it
|
||||
@@ -156,4 +233,25 @@ fail() { echo "FAILED: $1" >&2; exit 1; }
|
||||
grep -q "triple-c-wayland-fallback" "$out/AppRun" || fail "AppRun does not source the hook."
|
||||
[ -x "$out/usr/bin/triple-c" ] || fail "no executable usr/bin/triple-c."
|
||||
|
||||
echo "OK: $appimage now prefers the host $LIB, with a bundled fallback."
|
||||
# An empty Categories or missing metadata ships an image a manager cannot file
|
||||
# or describe, and both fail silently at runtime rather than at build time.
|
||||
grep -q "^Categories=.\+" "$out"/*.desktop || fail "Categories is still empty."
|
||||
[ -f "$appdata_src" ] && { [ -e "$out/usr/share/metainfo/$APP_ID.appdata.xml" ] \
|
||||
|| fail "AppStream metadata did not make it into the image."; }
|
||||
|
||||
# The update string is the difference between adoptable and updatable. It
|
||||
# lives in the image's own `.upd_info` ELF section, not in the .zsync — the
|
||||
# .zsync only records a *relative* filename, which a client resolves against
|
||||
# the URL it fetched the .zsync from. That is exactly why the output is named
|
||||
# for the fixed tag: a versioned name here resolves to the build the client
|
||||
# already has.
|
||||
[ -e "$STABLE_NAME" ] || fail "the stable-named image is missing."
|
||||
[ -e "$STABLE_NAME.zsync" ] || fail "appimagetool wrote no $STABLE_NAME.zsync."
|
||||
|
||||
readelf -p .upd_info "$STABLE_NAME" 2>/dev/null | grep -q "$UPDATE_TAG" \
|
||||
|| fail "the image carries no update information for the $UPDATE_TAG tag."
|
||||
grep -aq "^Filename: $STABLE_NAME$" "$STABLE_NAME.zsync" \
|
||||
|| fail "the .zsync names something other than $STABLE_NAME."
|
||||
|
||||
echo "OK: $appimage prefers the host $LIB (fallback kept), carries AppStream"
|
||||
echo " metadata, and updates from the $UPDATE_TAG tag via $STABLE_NAME.zsync."
|
||||
Executable
+95
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Publish the AppImage and its .zsync to the fixed `linux-latest` tag on the
|
||||
# GitHub mirror — the URL every installed copy checks for updates.
|
||||
#
|
||||
# This exists because the update URL has to be one that never moves.
|
||||
# `releases/latest` does move: it follows whatever release is newest, and the
|
||||
# Gitea-to-GitHub backfill creates one GitHub release per Gitea tag, including
|
||||
# the `-win` and `-mac` tags that carry no AppImage. Pointing a million
|
||||
# installed copies at a URL that can resolve to a release with no AppImage in
|
||||
# it is a failure that shows up on users' machines and nowhere else.
|
||||
#
|
||||
# So this tag holds exactly two files, replaced in place on every release.
|
||||
# The versioned per-release artifacts are published separately and are what a
|
||||
# human downloads; this is what the updater reads.
|
||||
#
|
||||
# It writes to GitHub rather than Gitea because that mirror is where updates
|
||||
# are pulled from. Needs GH_PAT with contents write on the mirror.
|
||||
#
|
||||
# Usage: GH_PAT=... publish-update-channel.sh <directory holding the artifacts>
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO="shadowdao/triple-c"
|
||||
TAG="linux-latest"
|
||||
API="https://api.github.com/repos/$REPO"
|
||||
ASSETS=("Triple-C_x86_64.AppImage" "Triple-C_x86_64.AppImage.zsync")
|
||||
|
||||
: "${GH_PAT:?GH_PAT is required to publish the update channel}"
|
||||
dir="${1:?usage: publish-update-channel.sh <artifacts directory>}"
|
||||
cd "$dir"
|
||||
|
||||
for asset in "${ASSETS[@]}"; do
|
||||
[ -e "$asset" ] || { echo "Missing $asset in $dir" >&2; exit 1; }
|
||||
done
|
||||
|
||||
gh() { curl -sf -H "Authorization: Bearer $GH_PAT" -H "Accept: application/vnd.github+json" "$@"; }
|
||||
|
||||
echo "==> Looking for the $TAG release"
|
||||
release="$(gh "$API/releases/tags/$TAG" 2>/dev/null || true)"
|
||||
release_id="$(printf '%s' "$release" | python3 -c 'import sys,json;print(json.load(sys.stdin).get("id",""))' 2>/dev/null || true)"
|
||||
|
||||
if [ -z "$release_id" ]; then
|
||||
echo "==> Creating it"
|
||||
# Not a prerelease, but deliberately not the "latest" release either: this
|
||||
# tag is a channel, and it must never displace the versioned release a
|
||||
# person lands on from the releases page.
|
||||
release="$(gh -X POST "$API/releases" -d "$(python3 -c '
|
||||
import json
|
||||
print(json.dumps({
|
||||
"tag_name": "'"$TAG"'",
|
||||
"name": "Linux update channel",
|
||||
"body": "Rolling AppImage build that Triple-C’s in-app updater reads. "
|
||||
"The two files here are replaced on every release; for a specific "
|
||||
"version, use the versioned releases instead.",
|
||||
"draft": False,
|
||||
"prerelease": False,
|
||||
"make_latest": "false",
|
||||
}))')")"
|
||||
release_id="$(printf '%s' "$release" | python3 -c 'import sys,json;print(json.load(sys.stdin)["id"])')"
|
||||
fi
|
||||
|
||||
echo "==> Removing superseded assets from release $release_id"
|
||||
printf '%s' "$release" | python3 -c '
|
||||
import sys, json
|
||||
keep = set(sys.argv[1:])
|
||||
for a in json.load(sys.stdin).get("assets", []):
|
||||
if a["name"] in keep:
|
||||
print(a["id"])
|
||||
' "${ASSETS[@]}" | while read -r asset_id; do
|
||||
[ -n "$asset_id" ] || continue
|
||||
gh -X DELETE "$API/releases/assets/$asset_id" >/dev/null || true
|
||||
done
|
||||
|
||||
for asset in "${ASSETS[@]}"; do
|
||||
echo "==> Uploading $asset ($(du -h "$asset" | cut -f1))"
|
||||
curl -sf -X POST \
|
||||
-H "Authorization: Bearer $GH_PAT" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary "@$asset" \
|
||||
"https://uploads.github.com/repos/$REPO/releases/$release_id/assets?name=$asset" >/dev/null
|
||||
done
|
||||
|
||||
# The updater is only as good as this URL, and a silent failure here means
|
||||
# every installed copy quietly stops updating. Confirm both are actually
|
||||
# fetchable at the address the AppImage was built to check.
|
||||
echo "==> Verifying the published URLs"
|
||||
for asset in "${ASSETS[@]}"; do
|
||||
url="https://github.com/$REPO/releases/download/$TAG/$asset"
|
||||
code="$(curl -s -o /dev/null -w '%{http_code}' -L "$url")"
|
||||
[ "$code" = "200" ] || { echo "FAILED: $url returned $code" >&2; exit 1; }
|
||||
echo " $code $url"
|
||||
done
|
||||
|
||||
echo "OK: $TAG updated."
|
||||
Reference in New Issue
Block a user