Skip to content

Commit 2ba19fb

Browse files
authored
build: disable CI AppImage publishing (#79)
1 parent 855aefa commit 2ba19fb

File tree

6 files changed

+163
-129
lines changed

6 files changed

+163
-129
lines changed

.github/workflows/build-desktop-tauri.yml

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,8 @@ jobs:
211211
shell: bash
212212
run: |
213213
set -euo pipefail
214-
if [[ -n "${TAURI_SIGNING_PRIVATE_KEY-}" && -n "${TAURI_SIGNING_PRIVATE_KEY_PASSWORD-}" ]]; then
215-
echo "TAURI signing secrets detected; building deb, rpm, and AppImage bundles."
216-
cargo tauri build --bundles deb,rpm,appimage
217-
else
218-
echo "TAURI signing secrets missing; building deb and rpm bundles only."
219-
cargo tauri build --bundles deb,rpm
220-
fi
214+
echo "Building Linux release bundles (deb and rpm only)."
215+
cargo tauri build --bundles deb,rpm
221216
222217
- name: Smoke test backend startup (Linux)
223218
shell: bash
@@ -234,16 +229,6 @@ jobs:
234229
src-tauri/target/release/bundle/**/*.deb
235230
src-tauri/target/release/bundle/**/*.rpm
236231
237-
- name: Upload AppImage artifacts (Linux)
238-
if: ${{ hashFiles('src-tauri/target/release/bundle/**/*.AppImage', 'src-tauri/target/release/bundle/**/*.AppImage.sig') != '' }}
239-
uses: actions/upload-artifact@v6.0.0
240-
with:
241-
name: astrbot-desktop-tauri-${{ needs.resolve_build_context.outputs.astrbot_version }}-linux-${{ matrix.arch }}-appimage
242-
if-no-files-found: ignore
243-
path: |
244-
src-tauri/target/release/bundle/**/*.AppImage
245-
src-tauri/target/release/bundle/**/*.AppImage.sig
246-
247232
build-macos:
248233
needs:
249234
- resolve_build_context
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Disable CI AppImage Publishing Design
2+
3+
**Goal:** Stop publishing Linux AppImage artifacts from CI and remove AppImage entries from the official updater release pipeline, while keeping local AppImage builds available for manual validation.
4+
5+
## Context
6+
7+
The current Linux workflow still builds and uploads AppImage bundles in CI, and the release manifest generator publishes Linux AppImage updater entries. That turns AppImage into an upstream-supported release target.
8+
9+
Recent AppImage platform guidance does not support treating that target as low-risk infrastructure:
10+
11+
- AppImage runtime behavior still depends on host FUSE availability, and AppImage's own troubleshooting guidance documents distro-specific install and recovery steps.
12+
- AppImage's Wayland notes document display-server integration issues, including cases where bundled Qt stacks miss the required Wayland platform plugin and need XWayland or environment workarounds.
13+
- AppImage best-practice guidance also expects broad target validation against older Linux bases and bundled dependency compatibility, which our current GitHub Actions packaging path does not prove.
14+
15+
Given that gap, upstream CI should stop producing and advertising AppImage release artifacts until Linux graphics/runtime compatibility is better validated.
16+
17+
## Chosen Approach
18+
19+
Remove AppImage from the official CI and release-manifest pipeline, but keep runtime detection and local build capability untouched.
20+
21+
This means:
22+
23+
1. Linux GitHub Actions builds produce only `deb` and `rpm` bundles.
24+
2. CI no longer uploads `.AppImage` or `.AppImage.sig` artifacts.
25+
3. Release manifest generation no longer recognizes or emits Linux AppImage updater platforms.
26+
4. Tests covering AppImage artifact normalization and manifest inclusion are removed or updated to reflect the new release contract.
27+
5. The upstream PR body explicitly explains that AppImage release publishing is paused because Linux graphics/runtime compatibility is not stable enough for automated upstream distribution.
28+
29+
## Alternatives Considered
30+
31+
### 1. Only remove AppImage from the Linux workflow
32+
33+
Rejected because the release-manifest tooling and tests would still advertise AppImage as an official updater platform, leaving dead or misleading release logic in place.
34+
35+
### 2. Remove CI, release-manifest handling, and runtime AppImage updater logic
36+
37+
Rejected for now because it broadens the change from release-scope rollback into product-behavior rollback. Local experiments and future re-enablement are easier if runtime support remains isolated.
38+
39+
## Impact
40+
41+
- Official upstream releases stop shipping AppImage updater assets.
42+
- Official `latest.json` payloads stop containing `linux-*-appimage` entries.
43+
- Local developers can still build AppImage manually, but that path is no longer an upstream-published release guarantee.
44+
45+
## Verification
46+
47+
- Linux workflow contains no `appimage` bundle target and no AppImage artifact upload step.
48+
- Updater manifest generation tests pass without Linux AppImage support.
49+
- Release artifact normalization tests no longer assert AppImage canonicalization for `latest.json` generation.
50+
- PR description explains the FUSE / Wayland / Linux compatibility rationale for temporarily removing upstream AppImage publishing.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Disable CI AppImage Publishing Implementation Plan
2+
3+
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4+
5+
**Goal:** Remove Linux AppImage from the upstream CI and release manifest pipeline while preserving local AppImage build capability.
6+
7+
**Architecture:** Shrink the Linux GitHub Actions build matrix output to `deb` and `rpm`, then remove AppImage handling from updater-manifest generation and release artifact normalization tests. Keep runtime AppImage detection untouched so local/manual AppImage builds still work outside the upstream release path.
8+
9+
**Tech Stack:** GitHub Actions YAML, Python, Node.js tests, gh CLI
10+
11+
---
12+
13+
### Task 1: Lock the release-pipeline contract in tests
14+
15+
**Files:**
16+
- Modify: `scripts/ci/test_generate_tauri_latest_json.py`
17+
- Modify: `scripts/ci/release-updater-artifacts.test.mjs`
18+
19+
**Step 1: Write the failing test changes**
20+
21+
Remove or rewrite AppImage-specific release-manifest expectations so the suite reflects the new contract: no AppImage updater artifacts should be recognized for published releases.
22+
23+
**Step 2: Run tests to verify they fail**
24+
25+
Run:
26+
27+
- `python3 -m unittest scripts.ci.test_generate_tauri_latest_json`
28+
- `node --test scripts/ci/release-updater-artifacts.test.mjs`
29+
30+
Expected: FAIL because the implementation still recognizes AppImage release artifacts.
31+
32+
### Task 2: Remove AppImage from CI and release-manifest generation
33+
34+
**Files:**
35+
- Modify: `.github/workflows/build-desktop-tauri.yml`
36+
- Modify: `scripts/ci/generate_tauri_latest_json.py`
37+
38+
**Step 1: Update Linux CI build output**
39+
40+
Make Linux CI build only `deb,rpm` bundles and remove the AppImage upload step.
41+
42+
**Step 2: Remove AppImage updater manifest handling**
43+
44+
Delete Linux AppImage platform-key, filename, parsing, and collection logic from `generate_tauri_latest_json.py`.
45+
46+
**Step 3: Re-run targeted tests**
47+
48+
Run:
49+
50+
- `python3 -m unittest scripts.ci.test_generate_tauri_latest_json`
51+
- `node --test scripts/ci/release-updater-artifacts.test.mjs`
52+
53+
Expected: PASS.
54+
55+
### Task 3: Update PR context and verify the change
56+
57+
**Files:**
58+
- Review/Update PR body via `gh pr edit`
59+
60+
**Step 1: Run final verification**
61+
62+
Run:
63+
64+
- `python3 -m unittest scripts.ci.test_generate_tauri_latest_json`
65+
- `node --test scripts/ci/release-updater-artifacts.test.mjs`
66+
67+
Expected: PASS.
68+
69+
**Step 2: Commit and push**
70+
71+
```bash
72+
git add .github/workflows/build-desktop-tauri.yml scripts/ci/generate_tauri_latest_json.py scripts/ci/test_generate_tauri_latest_json.py scripts/ci/release-updater-artifacts.test.mjs
73+
git commit -m "build: disable CI AppImage publishing"
74+
git push
75+
```
76+
77+
**Step 3: Update upstream PR description**
78+
79+
Use `gh pr edit` to explain that Linux AppImage publishing is temporarily disabled in upstream CI because AppImage release compatibility still depends on Linux graphics/runtime details such as FUSE availability, Wayland/XWayland behavior, and broader target-system validation.

scripts/ci/generate_tauri_latest_json.py

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from scripts.ci.lib.nightly_version import NIGHTLY_CANONICAL_FORMAT, NIGHTLY_VERSION_RE
1212
from scripts.ci.lib.release_artifacts import (
1313
ARTIFACT_EXTENSIONS,
14-
LINUX_APPIMAGE_UPDATER_PATTERNS,
1514
MACOS_UPDATER_ARCHIVE_EXTENSION,
1615
MACOS_UPDATER_ARCHIVE_PATTERNS,
1716
MACOS_UPDATER_SIGNATURE_EXTENSION,
@@ -59,15 +58,6 @@ def platform_key_for_macos(arch: str) -> str:
5958
raise ValueError(f"Unsupported macOS arch: {arch}")
6059

6160

62-
def platform_key_for_linux_appimage(arch: str) -> str:
63-
arch = normalize_arch(arch)
64-
if arch == "amd64":
65-
return "linux-x86_64-appimage"
66-
if arch == "arm64":
67-
return "linux-aarch64-appimage"
68-
raise ValueError(f"Unsupported Linux AppImage arch: {arch}")
69-
70-
7161
def derive_release_metadata(version: str, channel: str | None) -> tuple[str, str, str]:
7262
inferred_channel = "nightly" if "nightly" in version.lower() else "stable"
7363
effective_channel = channel or inferred_channel
@@ -111,14 +101,6 @@ def canonical_macos_filename(
111101
return f"{name}_{base_version}_macos_{arch}{nightly_suffix}{MACOS_UPDATER_ARCHIVE_EXTENSION}"
112102

113103

114-
def canonical_linux_appimage_filename(
115-
name: str, arch: str, version: str, channel: str
116-
) -> str:
117-
_, base_version, nightly_suffix = derive_release_metadata(version, channel)
118-
arch = normalize_arch(arch)
119-
return f"{name}_{base_version}_linux_{arch}{nightly_suffix}.AppImage"
120-
121-
122104
def parse_windows_artifact_name(source_name: str) -> re.Match[str]:
123105
match = match_any(source_name, WINDOWS_UPDATER_PATTERNS)
124106
if match:
@@ -147,19 +129,6 @@ def parse_macos_artifact_name(source_name: str) -> re.Match[str]:
147129
return match
148130

149131

150-
def parse_linux_appimage_artifact_name(source_name: str) -> re.Match[str]:
151-
match = match_any(source_name, LINUX_APPIMAGE_UPDATER_PATTERNS)
152-
if match:
153-
return match
154-
raise ValueError(
155-
"Unexpected Linux AppImage artifact name: "
156-
f"{source_name}. Expected format: "
157-
"<name>_<version>_linux_<arch>.AppImage or legacy "
158-
"<name>_<version>_<arch>.AppImage "
159-
"(nightly builds may append _nightly_<sha> before .AppImage)."
160-
)
161-
162-
163132
def add_platform(
164133
platforms: dict[str, dict[str, str]],
165134
platform_key: str,
@@ -241,26 +210,6 @@ def collect_platforms(
241210
)
242211
continue
243212

244-
if sig_name.endswith(".AppImage.sig"):
245-
source_name = sig_name[:-4]
246-
match = parse_linux_appimage_artifact_name(source_name)
247-
artifact_name = canonical_linux_appimage_filename(
248-
match.group("name"),
249-
match.group("arch"),
250-
version,
251-
channel,
252-
)
253-
add_platform(
254-
platforms,
255-
platform_key_for_linux_appimage(match.group("arch")),
256-
"Linux AppImage",
257-
artifact_name,
258-
sig_path,
259-
repo,
260-
tag,
261-
)
262-
continue
263-
264213
unsupported_signature_files.append(sig_name)
265214

266215
if unsupported_signature_files:

scripts/ci/release-updater-artifacts.test.mjs

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ test('release artifact normalization keeps updater signatures aligned for latest
305305
}
306306
});
307307

308-
test('release artifact normalization canonicalizes linux AppImage assets for latest.json generation', async () => {
308+
test('release artifact normalization leaves linux AppImage assets unsupported for latest.json generation', async () => {
309309
const tempDir = await mkdtemp(path.join(os.tmpdir(), 'astrbot-release-artifacts-'));
310310

311311
try {
@@ -343,29 +343,26 @@ test('release artifact normalization canonicalizes linux AppImage assets for lat
343343
await access(normalizedLinux, fsConstants.F_OK);
344344
await access(normalizedLinuxSig, fsConstants.F_OK);
345345

346-
const outputPath = path.join(artifactsDir, 'latest.json');
347-
runPython(
348-
generateModule,
349-
[
350-
'--artifacts-root',
351-
artifactsDir,
352-
'--repo',
353-
'AstrBotDevs/AstrBot-desktop',
354-
'--tag',
355-
'nightly',
356-
'--version',
357-
'4.19.2-nightly.20260306.7ac169c5',
358-
'--output',
359-
outputPath,
360-
],
361-
projectRoot,
346+
assert.throws(
347+
() =>
348+
runPython(
349+
generateModule,
350+
[
351+
'--artifacts-root',
352+
artifactsDir,
353+
'--repo',
354+
'AstrBotDevs/AstrBot-desktop',
355+
'--tag',
356+
'nightly',
357+
'--version',
358+
'4.19.2-nightly.20260306.7ac169c5',
359+
'--output',
360+
path.join(artifactsDir, 'latest.json'),
361+
],
362+
projectRoot,
363+
),
364+
/Unsupported updater signature files under artifacts root/,
362365
);
363-
364-
const payload = JSON.parse(await readFile(outputPath, 'utf8'));
365-
assert.deepEqual(payload.platforms['linux-aarch64-appimage'], {
366-
signature: 'linux-signature',
367-
url: 'https://github.com/AstrBotDevs/AstrBot-desktop/releases/download/nightly/AstrBot_4.19.2_linux_arm64_nightly_7ac169c5.AppImage',
368-
});
369366
} finally {
370367
await rm(tempDir, { recursive: true, force: true });
371368
}

scripts/ci/test_generate_tauri_latest_json.py

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,6 @@ def test_platform_key_for_macos_unsupported_arch(self):
4343
with self.assertRaisesRegex(ValueError, r"Unsupported macOS arch: ppc64le"):
4444
MODULE.platform_key_for_macos("ppc64le")
4545

46-
def test_platform_key_for_linux_appimage_unsupported_arch(self):
47-
with self.assertRaisesRegex(
48-
ValueError, r"Unsupported Linux AppImage arch: ppc64le"
49-
):
50-
MODULE.platform_key_for_linux_appimage("ppc64le")
51-
5246
def test_derive_release_metadata_validates_and_returns_expected_values(self):
5347
self.assertEqual(
5448
MODULE.derive_release_metadata("4.29.0", None),
@@ -122,23 +116,6 @@ def test_canonical_macos_filename_outputs_expected_names(self):
122116
"AstrBot_4.29.0_macos_arm64_nightly_abcd1234.app.tar.gz",
123117
)
124118

125-
def test_canonical_linux_appimage_filename_outputs_expected_names(self):
126-
self.assertEqual(
127-
MODULE.canonical_linux_appimage_filename(
128-
"AstrBot", "arm64", "4.29.0", "stable"
129-
),
130-
"AstrBot_4.29.0_linux_arm64.AppImage",
131-
)
132-
self.assertEqual(
133-
MODULE.canonical_linux_appimage_filename(
134-
"AstrBot",
135-
"aarch64",
136-
"4.29.0-nightly.20260307.abcd1234",
137-
"nightly",
138-
),
139-
"AstrBot_4.29.0_linux_arm64_nightly_abcd1234.AppImage",
140-
)
141-
142119
def test_main_writes_expected_manifest_json(self):
143120
with tempfile.TemporaryDirectory() as tmpdir:
144121
root = Path(tmpdir)
@@ -483,27 +460,24 @@ def test_collect_platforms_ignores_non_artifact_sig_files(self):
483460

484461
self.assertIn("darwin-aarch64", platforms)
485462

486-
def test_collect_platforms_accepts_linux_appimage_canonical_name(self):
463+
def test_collect_platforms_rejects_linux_appimage_signature_files(self):
487464
with tempfile.TemporaryDirectory() as tmpdir:
488465
root = Path(tmpdir)
489466
(
490467
root / "AstrBot_4.29.0_linux_arm64_nightly_abcd1234.AppImage.sig"
491468
).write_text("sig-linux")
492469

493-
platforms = MODULE.collect_platforms(
494-
root,
495-
"AstrBotDevs/AstrBot-desktop",
496-
"nightly",
497-
version="4.29.0-nightly.20260307.abcd1234",
498-
channel="nightly",
499-
)
500-
501-
self.assertIn("linux-aarch64-appimage", platforms)
502-
self.assertEqual(
503-
platforms["linux-aarch64-appimage"]["url"],
504-
"https://github.com/AstrBotDevs/AstrBot-desktop/releases/download/nightly/"
505-
"AstrBot_4.29.0_linux_arm64_nightly_abcd1234.AppImage",
506-
)
470+
with self.assertRaisesRegex(
471+
ValueError,
472+
"Unsupported updater signature files under artifacts root",
473+
):
474+
MODULE.collect_platforms(
475+
root,
476+
"AstrBotDevs/AstrBot-desktop",
477+
"nightly",
478+
version="4.29.0-nightly.20260307.abcd1234",
479+
channel="nightly",
480+
)
507481

508482
def test_collect_platforms_invalid_windows_sig_raises(self):
509483
with tempfile.TemporaryDirectory() as tmpdir:

0 commit comments

Comments
 (0)