v1.1.3
Citizen Launcher CI / arch-package (push) Failing after 22s
Citizen Launcher CI / rpm-package (push) Failing after 29s
Citizen Launcher CI / verify (push) Successful in 2m50s

This commit is contained in:
2026-09-01 20:17:04 +02:00
parent 5aadfd3427
commit 7bc0c63743
23 changed files with 332 additions and 126 deletions
+38 -4
View File
@@ -30,17 +30,51 @@ jobs:
rpm-package:
runs-on: ubuntu-latest
container: fedora:44
env:
WORKSPACE: ${{ gitea.workspace }}
steps:
- name: Build dependencies
run: dnf -y install git golang rpm-build systemd-rpm-macros curl python3
- uses: actions/checkout@v4
- name: Build backend and RPM
- name: Bootstrap minimal checkout dependency
shell: bash
run: |
set -euo pipefail
mkdir -p "$WORKSPACE/.dnf-cache"
dnf -y \
--setopt=system_cachedir="$WORKSPACE/.dnf-cache" \
--setopt=install_weak_deps=False \
--setopt=tsflags=nodocs \
install git-core
find "$WORKSPACE/.dnf-cache" -type f -name '*.rpm' -delete 2>/dev/null || true
df -h /
- uses: actions/checkout@v4
- name: Build backend with minimal Go toolchain
shell: bash
run: |
set -euo pipefail
dnf -y \
--setopt=system_cachedir="$WORKSPACE/.dnf-cache" \
--setopt=install_weak_deps=False \
--setopt=tsflags=nodocs \
install golang-bin
find "$WORKSPACE/.dnf-cache" -type f -name '*.rpm' -delete 2>/dev/null || true
bash ./build.sh
# The backend is fully static; release the compiler before bringing in rpmbuild.
dnf -y --setopt=system_cachedir="$WORKSPACE/.dnf-cache" remove golang-bin || true
find "$WORKSPACE/.dnf-cache" -type f -name '*.rpm' -delete 2>/dev/null || true
df -h /
- name: Build RPM in low-disk mode
shell: bash
run: |
set -euo pipefail
dnf -y \
--setopt=system_cachedir="$WORKSPACE/.dnf-cache" \
--setopt=install_weak_deps=False \
--setopt=tsflags=nodocs \
install rpm-build
find "$WORKSPACE/.dnf-cache" -type f -name '*.rpm' -delete 2>/dev/null || true
bash ./packaging/build-rpm.sh
VERSION="$(tr -d '[:space:]' < VERSION)"
rpm -qpi "dist/citizen-launcher-${VERSION}-1.linux.x86_64.rpm"
df -h /
arch-package:
runs-on: ubuntu-latest
+38 -3
View File
@@ -73,21 +73,56 @@ jobs:
container: fedora:44
env:
CITIZEN_LAUNCHER_RELEASE_REPO: gitea:${{ gitea.api_url }}/repos/${{ gitea.repository }}
WORKSPACE: ${{ gitea.workspace }}
steps:
- name: Build dependencies
run: dnf -y install git golang rpm-build systemd-rpm-macros curl python3
- name: Bootstrap minimal checkout/release dependencies
shell: bash
run: |
set -euo pipefail
mkdir -p "$WORKSPACE/.dnf-cache"
dnf -y \
--setopt=system_cachedir="$WORKSPACE/.dnf-cache" \
--setopt=install_weak_deps=False \
--setopt=tsflags=nodocs \
install git-core jq
find "$WORKSPACE/.dnf-cache" -type f -name '*.rpm' -delete 2>/dev/null || true
df -h /
- uses: actions/checkout@v4
- name: Verify tag and build RPM
- name: Verify tag and build backend
shell: bash
run: |
set -euo pipefail
VERSION="$(tr -d '[:space:]' < VERSION)"
test "$TAG_NAME" = "v${VERSION}"
dnf -y \
--setopt=system_cachedir="$WORKSPACE/.dnf-cache" \
--setopt=install_weak_deps=False \
--setopt=tsflags=nodocs \
install golang-bin
find "$WORKSPACE/.dnf-cache" -type f -name '*.rpm' -delete 2>/dev/null || true
bash ./build.sh
# The backend is static, so free the compiler before installing rpmbuild.
dnf -y --setopt=system_cachedir="$WORKSPACE/.dnf-cache" remove golang-bin || true
find "$WORKSPACE/.dnf-cache" -type f -name '*.rpm' -delete 2>/dev/null || true
df -h /
- name: Build RPM in low-disk mode
shell: bash
run: |
set -euo pipefail
dnf -y \
--setopt=system_cachedir="$WORKSPACE/.dnf-cache" \
--setopt=install_weak_deps=False \
--setopt=tsflags=nodocs \
install rpm-build
find "$WORKSPACE/.dnf-cache" -type f -name '*.rpm' -delete 2>/dev/null || true
bash ./packaging/build-rpm.sh
VERSION="$(tr -d '[:space:]' < VERSION)"
rpm -qpi "dist/citizen-launcher-${VERSION}-1.linux.x86_64.rpm"
df -h /
- name: Upload RPM to Gitea
shell: bash
env:
CITIZEN_JSON_BACKEND: jq
run: |
set -euo pipefail
VERSION="$(tr -d '[:space:]' < VERSION)"
+24 -3
View File
@@ -1,6 +1,6 @@
# Gitea Actions setup
Citizen Launcher 1.1.2 uses Gitea Actions natively. Workflows are in `.gitea/workflows/`; the old `.github/workflows/` directory is intentionally absent.
Citizen Launcher 1.1.3 uses Gitea Actions natively. Workflows are in `.gitea/workflows/`; the old `.github/workflows/` directory is intentionally absent.
## Requirements
@@ -26,8 +26,8 @@ If your runner uses a different label, replace `runs-on: ubuntu-latest` in both
Push a version tag matching `VERSION`, for example:
```bash
git tag v1.1.2
git push origin v1.1.2
git tag v1.1.3
git push origin v1.1.3
```
`.gitea/workflows/release.yml` then:
@@ -70,3 +70,24 @@ Existing `github:owner/repo` and legacy `owner/repo` sources remain supported.
## Reruns
The release helper `scripts/gitea-release.sh` is intentionally rerun-safe. Existing same-named attachments are removed before a replacement is uploaded, so rerunning a failed release does not create duplicate package assets.
## Small runner / Fedora RPM jobs
The Fedora jobs are intentionally written for constrained `act_runner` Docker roots. Do not replace the staged dependency setup with one large command such as:
```text
dnf install git golang rpm-build systemd-rpm-macros curl python3
```
That pulls Fedora's full Go source package, weak RPM build dependencies and other tooling at the same time and can exceed a small container root filesystem before `rpmbuild` starts.
The 1.1.3 workflow instead:
1. installs only `git-core` for checkout;
2. stores DNF cache data on `${{ gitea.workspace }}` rather than `/var/cache/libdnf5`;
3. disables weak dependencies and docs in the disposable build container;
4. installs `golang-bin`, builds the static backend, then removes the compiler;
5. installs `rpm-build` only after Go has been removed;
6. uses `jq` instead of Python for the RPM release upload path.
The workflow prints `df -h /` after the major phases. If a runner still cannot fit the native Fedora build after this reduction, increase the Docker/container root storage rather than silently dropping RPM verification.
+6 -6
View File
@@ -1,4 +1,4 @@
# Citizen Launcher 1.1.2
# Citizen Launcher 1.1.3
Citizen Launcher is a cross-distribution Star Citizen setup, launch, repair and maintenance application for Linux. The same static Go core runs on Debian/Ubuntu, Fedora/RHEL derivatives, Arch derivatives, openSUSE and generic glibc-based desktop Linux. Omarchy support is an optional integration, not a runtime requirement.
@@ -8,7 +8,7 @@ Citizen Launcher is a cross-distribution Star Citizen setup, launch, repair and
The launcher owns the fragile user-space gaming stack so users do not have to pick Wine builds, copy DXVK DLLs or rebuild prefixes by hand. Kernel, GPU driver, firmware and base-distribution upgrades remain owned by the Linux distribution.
The 1.0.1 gaming path was confirmed end-to-end on real hardware: launcher, RSI installation and Star Citizen playability. 1.1.2 keeps that gaming core and adds native multi-distribution packaging/update integration.
The 1.0.1 gaming path was confirmed end-to-end on real hardware: launcher, RSI installation and Star Citizen playability. 1.1.3 keeps that gaming core, the multi-distribution packaging/update layer, and hardens Fedora RPM CI for small Gitea runners by staging build tools instead of installing the whole toolchain at once.
## Supported Linux families
@@ -32,25 +32,25 @@ The installer detects the distro family, prefers a native package found in `dist
### Debian / Ubuntu / Mint
```bash
sudo apt install ./dist/citizen-launcher_1.1.2_amd64.deb
sudo apt install ./dist/citizen-launcher_1.1.3_amd64.deb
```
### Fedora / Nobara / RHEL family
```bash
sudo dnf install ./dist/citizen-launcher-1.1.2-1.linux.x86_64.rpm
sudo dnf install ./dist/citizen-launcher-1.1.3-1.linux.x86_64.rpm
```
### openSUSE Tumbleweed / Slowroll
```bash
sudo zypper install ./dist/citizen-launcher-1.1.2-1.linux.x86_64.rpm
sudo zypper install ./dist/citizen-launcher-1.1.3-1.linux.x86_64.rpm
```
### Arch / Manjaro / EndeavourOS / CachyOS / Omarchy
```bash
sudo pacman -U ./dist/citizen-launcher-1.1.2-1-x86_64.pkg.tar.zst
sudo pacman -U ./dist/citizen-launcher-1.1.3-1-x86_64.pkg.tar.zst
```
### Generic / immutable desktop Linux
+19 -23
View File
@@ -1,35 +1,31 @@
# Citizen Launcher 1.1.2
# Citizen Launcher 1.1.3
## Gitea-native CI/CD release
## Gitea Fedora/RPM runner hardening
1.1.2 keeps the confirmed playable multi-distribution 1.1.x runtime and hardens the Gitea Actions pipeline introduced in 1.1.1.
1.1.3 keeps the confirmed playable multi-distribution 1.1.x runtime and fixes the next real Gitea `act_runner` failure found in the Fedora RPM job.
### Gitea workflows
### Root cause
- workflows now live exclusively under `.gitea/workflows/`
- CI keeps the full Go/race/package verification plus Fedora RPM and Arch package builds
- tag releases are created with Gitea's REST API and built-in `GITEA_TOKEN`
- release publishing no longer depends on the `gh` CLI
- release jobs upload `.deb`, `.rpm`, `.pkg.tar.zst`, generic tarball and one combined `SHA256SUMS.txt`
- upload is idempotent: a rerun replaces same-named release attachments instead of duplicating them
The previous workflow installed `git`, the full `golang` meta package, `rpm-build`, `systemd-rpm-macros`, `curl` and `python3` in one Fedora transaction. Fedora also enabled weak dependencies by default. On a small Docker root filesystem this expanded into hundreds of packages and exhausted `/` before the RPM build even started.
### Gitea-aware self-update
### Fix
Packages produced by Gitea Actions embed an exact `gitea:<api-repository-url>` update source. The launcher can now resolve Gitea's latest-release API and hydrate per-asset SHA-256 values from the workflow-generated `SHA256SUMS.txt`. GitHub release sources remain supported for existing installations.
- Fedora jobs now use `git-core` instead of the full Git package.
- Go builds use `golang-bin` rather than the `golang` meta package, avoiding the large source package.
- `systemd-rpm-macros`, Python and other unnecessary RPM-build dependencies are no longer installed in the Fedora build phase.
- DNF weak dependencies are disabled and documentation payloads are skipped in CI containers.
- DNF's root cache is redirected to the mounted Gitea workspace volume.
- Downloaded RPM cache files are deleted after each transaction.
- The static Go backend is built first, then `golang-bin` is removed before `rpm-build` is installed. The two heavy toolchains no longer occupy the container root simultaneously.
- The Gitea release helper now supports a `jq` JSON backend, so the Fedora release job does not need the full Python runtime just to upload an RPM.
- Disk usage is printed between phases to make future runner-capacity problems immediately visible.
For privileged updates, a configured Gitea source must use HTTPS. This preserves the fail-closed package-update model.
### Regression guards
### Runner portability
The release flow does not depend on cross-job `upload-artifact` compatibility. Each native build uploads its package directly to the Gitea Release, and the final job downloads those release attachments to create the checksum manifest. This works across a wider range of act_runner versions.
- `tests/rpm-ci-footprint.sh` asserts the low-disk policy in both CI and release RPM jobs.
- Gitea release-helper tests now exercise both Python and `jq` JSON backends.
- The earlier `0644`/`Permission denied` workflow hardening remains in place.
### Runtime
Wine, DXVK, RSI Launcher setup, hardware checks, single-instance protection, repair, support bundles and the already confirmed playable Star Citizen path are unchanged.
## Gitea CI hardening
- Gitea Actions invokes repository shell scripts explicitly through `bash`.
- Nested test, build and release scripts use the same mode-independent convention.
- Added a regression guard against direct `.sh` execution in the critical CI graph.
- Fixes Gitea/act exit code 126 (`Permission denied`) when checkout files are mode `0644`.
+39 -35
View File
@@ -1,14 +1,20 @@
# Citizen Launcher 1.1.2 – Verification Report
# Citizen Launcher 1.1.3 – Verification Report
Date: 2026-09-01
## Release scope
Citizen Launcher 1.1.2 keeps the confirmed playable 1.1.x multi-distribution gaming core and hardens the Gitea-native CI/CD introduced in 1.1.1 against checkout permission differences.
Citizen Launcher 1.1.3 keeps the confirmed playable multi-distribution 1.1.x gaming core and hardens Gitea-native RPM CI against constrained Fedora job-container storage.
## Failure reproduced from real Gitea runner log
The real Fedora 44 job reached dependency installation but failed before checkout/build because the transaction could not fit on `/`. The original dependency set expanded to hundreds of packages. The log ultimately reported that packages needed roughly 407 MB more root filesystem space and the `Build dependencies` step exited with status 1.
1.1.3 therefore treats CI container footprint as a release property, not a runner-specific workaround.
## Automated release gate
The 1.1.2 tree passes the local release gate with:
The 1.1.3 tree passes the local release gate with:
- shell syntax checks for installers, packaging, Gitea release helper and tests
- `gofmt` cleanliness
@@ -21,14 +27,30 @@ The 1.1.2 tree passes the local release gate with:
- generic Linux amd64 tarball build and execution check
- Gitea workflow YAML parsing
- assertion that legacy `.github/workflows/` does not shadow `.gitea/workflows/`
- assertion that the release workflow does not use `gh release` or cross-job artifact actions
- mocked Gitea REST API test covering release creation, release update on rerun, asset upload, same-name asset replacement and asset download
- assertion that release publishing does not use `gh release` or cross-job artifact actions
- mocked Gitea REST API test covering release creation, update on rerun, asset upload, replacement and download
- Gitea release helper exercised with both Python and `jq` JSON backends
- Gitea release-source parsing and `SHA256SUMS.txt` parser regression tests
- static validation of RPM spec and Arch PKGBUILD/package hooks
- multi-distro platform-family and immutable-host regression tests
- native package self-update parser/asset-selection tests for DEB, RPM and pacman formats
- full regression suite repeated successfully after forcing every repository `*.sh` file to mode `0644`; CI does not depend on executable bits
- regression guard rejects direct repository `.sh` execution in Gitea workflow entry points
- mode-independent shell invocation checks for Gitea/act checkouts without execute bits
- low-disk Fedora RPM workflow policy regression test
## Fedora RPM low-disk policy
Both `.gitea/workflows/ci.yml` and `.gitea/workflows/release.yml` now enforce this shape:
- DNF cache moved to the mounted Gitea workspace via `system_cachedir`
- `install_weak_deps=False`
- `tsflags=nodocs`
- `git-core`, not the full `git` package
- `golang-bin`, not the `golang` meta package
- `golang-bin` removed before `rpm-build` is installed
- no explicit `systemd-rpm-macros` in the build container
- no Python requirement for Fedora release upload; `jq` is used by `gitea-release.sh`
`tests/rpm-ci-footprint.sh` fails if the heavy one-shot dependency pattern is reintroduced.
## Gitea CI/CD design verified
@@ -37,40 +59,22 @@ Workflows live in:
- `.gitea/workflows/ci.yml`
- `.gitea/workflows/release.yml`
The release workflow uses Gitea-native contexts (`gitea.api_url`, `gitea.repository`, `gitea.ref_name`, `gitea.sha`, `gitea.token`) and the built-in job token with `code: read` / `releases: write` permissions.
Release packages are uploaded directly to the Gitea Release rather than moved between jobs with `actions/upload-artifact`. The final job downloads the native release packages and publishes one deterministic `SHA256SUMS.txt`.
The release helper is rerun-safe: an existing release is refreshed and same-named attachments are replaced instead of duplicated.
## Gitea-aware launcher self-update
A Gitea workflow build injects this form as the launcher's trusted update source:
```text
gitea:<gitea.api_url>/repos/<owner>/<repo>
```
The launcher resolves Gitea's latest release API and maps the release `SHA256SUMS.txt` back onto the package assets before a privileged update is allowed. Privileged Gitea sources require HTTPS. Existing GitHub release-source syntax remains supported for migration/backward compatibility.
A separate build check confirmed that a `gitea:https://.../api/v1/repos/owner/repo` source is successfully embedded into the static binary and reported by `self-update status`.
Release packages are uploaded directly to the Gitea Release. The final job downloads the native packages and publishes a deterministic `SHA256SUMS.txt`. The helper is rerun-safe and replaces same-named attachments.
## Native package build coverage
The current local build environment contains Debian packaging tools, therefore these artifacts can be built and inspected locally:
The local verification environment builds and inspects:
- `dist/citizen-launcher_1.1.2_amd64.deb`
- `dist/citizen-launcher-1.1.2-linux-amd64.tar.gz`
- `dist/citizen-launcher_1.1.3_amd64.deb`
- `dist/citizen-launcher-1.1.3-linux-amd64.tar.gz`
The local environment does not provide native `rpmbuild` / Arch `makepkg`; the Gitea workflows build those in Fedora and Arch job containers:
The Gitea workflows build these in native job containers:
- `citizen-launcher-1.1.2-1.linux.x86_64.rpm`
- `citizen-launcher-1.1.2-1-x86_64.pkg.tar.zst`
- `citizen-launcher-1.1.3-1.linux.x86_64.rpm`
- `citizen-launcher-1.1.3-1-x86_64.pkg.tar.zst`
The current sandbox does not provide Docker/rpmbuild, so the exact Fedora container transaction cannot be executed locally. Instead, the workflow structure is regression-tested and the full application/package suite is executed locally. The next Gitea Fedora run is the authoritative integration check for the runner's actual storage quota.
## Gaming-core acceptance
The Star Citizen install/play path is unchanged from the already accepted 1.0.1/1.1.0 line. The CI migration changes release and update plumbing, not Wine/DXVK/RSI launch behavior.
## Checkout permission regression
The complete `tests/full-verify.sh` suite was repeated after forcing every repository `*.sh` file to Unix mode `0644`. It still completed successfully. This reproduces the Gitea/act checkout condition that caused exit code 126 and verifies that CI/CD no longer depends on executable bits for repository shell scripts. Distributed archives still mark shell scripts executable for convenience.
The Star Citizen install/play path is unchanged from the already accepted 1.0.1/1.1.x line. This release changes CI/release plumbing, not Wine/DXVK/RSI launch behavior.
+1 -1
View File
@@ -1 +1 @@
1.1.2
1.1.3
Binary file not shown.
+1 -1
View File
@@ -16,7 +16,7 @@ import (
)
var (
appVersion = "1.1.2"
appVersion = "1.1.3"
releaseRepo = "github:sendnwv/omarchy-sc"
)
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -12,7 +12,7 @@ Panel {
property var anchorItem: null
property var hostWidget: null
property string pluginVersion: "1.1.2"
property string pluginVersion: "1.1.3"
property string health: "checking"
property string depsState: "checking"
property string depsMissing: ""
@@ -106,7 +106,7 @@ Panel {
values[lines[i].slice(0, p)] = lines[i].slice(p + 1)
}
pluginVersion = values.plugin_version || "1.1.2"
pluginVersion = values.plugin_version || "1.1.3"
health = values.health || "setup"
depsState = values.deps || "missing"
depsMissing = values.deps_missing || ""
+1 -1
View File
@@ -2,7 +2,7 @@
set -u
PLUGIN_ID="local.omarchy-citizen"
PLUGIN_VERSION="1.1.2"
PLUGIN_VERSION="1.1.3"
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
+1 -1
View File
@@ -2,7 +2,7 @@
"schemaVersion": 1,
"id": "local.omarchy-citizen",
"name": "Citizen Launcher · Omarchy",
"version": "1.1.2",
"version": "1.1.3",
"author": "Community prototype",
"license": "MIT",
"description": "Optional Omarchy bar integration for the distro-neutral Citizen Launcher.",
+2 -2
View File
@@ -104,7 +104,7 @@ fi
%config(noreplace) %{_sysconfdir}/citizen-launcher/release-repo
%changelog
* Tue Sep 01 2026 Citizen Launcher Project - 1.1.2-1
- Gitea Actions checkout permission hardening
* Tue Sep 01 2026 Citizen Launcher Project - 1.1.3-1
- Low-disk Gitea Fedora RPM build and release hardening
* Tue Sep 01 2026 Citizen Launcher Project - 1.1.1-1
- Multi-distribution native package support
@@ -13,6 +13,6 @@
<url type="homepage">https://github.com/sendnwv/omarchy-sc</url>
<categories><category>Game</category></categories>
<provides><binary>citizen-launcher</binary></provides>
<releases><release version="1.1.2" date="2026-09-01"/><release version="1.1.1" date="2026-09-01"/><release version="1.0.1" date="2026-08-31"/><release version="1.0.0" date="2026-08-31"/></releases>
<releases><release version="1.1.3" date="2026-09-01"/><release version="1.1.1" date="2026-09-01"/><release version="1.0.1" date="2026-08-31"/><release version="1.0.0" date="2026-08-31"/></releases>
<content_rating type="oars-1.1"/>
</component>
+2 -2
View File
@@ -104,7 +104,7 @@ fi
%config(noreplace) %{_sysconfdir}/citizen-launcher/release-repo
%changelog
* Tue Sep 01 2026 Citizen Launcher Project - 1.1.2-1
- Gitea Actions checkout permission hardening
* Tue Sep 01 2026 Citizen Launcher Project - 1.1.3-1
- Low-disk Gitea Fedora RPM build and release hardening
* Tue Sep 01 2026 Citizen Launcher Project - 1.1.1-1
- Multi-distribution native package support
+96 -29
View File
@@ -8,8 +8,41 @@ set -euo pipefail
api_base="${GITEA_API_URL%/}/repos/${GITEA_REPOSITORY}"
auth=( -H "Authorization: token ${GITEA_TOKEN}" )
select_json_backend() {
case "${CITIZEN_JSON_BACKEND:-auto}" in
python|python3)
command -v python3 >/dev/null 2>&1 || { echo "python3 is required by CITIZEN_JSON_BACKEND" >&2; exit 2; }
printf '%s\n' python
;;
jq)
command -v jq >/dev/null 2>&1 || { echo "jq is required by CITIZEN_JSON_BACKEND" >&2; exit 2; }
printf '%s\n' jq
;;
auto|"")
if command -v python3 >/dev/null 2>&1; then
printf '%s\n' python
elif command -v jq >/dev/null 2>&1; then
printf '%s\n' jq
else
echo "Gitea release helper needs python3 or jq" >&2
exit 2
fi
;;
*)
echo "Unknown CITIZEN_JSON_BACKEND=${CITIZEN_JSON_BACKEND}" >&2
exit 2
;;
esac
}
JSON_BACKEND="$(select_json_backend)"
urlencode() {
python3 -c 'import sys,urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$1"
if [[ "$JSON_BACKEND" == python ]]; then
python3 -c 'import sys,urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$1"
else
jq -rn --arg value "$1" '$value | @uri'
fi
}
release_json() {
@@ -19,8 +52,10 @@ release_json() {
}
release_payload() {
local tag="$1" title="$2" body_file="$3" target="${4:-}"
python3 - "$tag" "$title" "$body_file" "$target" <<'PY'
local tag="$1" title="$2" body_file="$3" target="${4:-}" body=""
[[ -f "$body_file" ]] && body="$(cat "$body_file")"
if [[ "$JSON_BACKEND" == python ]]; then
python3 - "$tag" "$title" "$body_file" "$target" <<'PY'
import json, pathlib, sys
body_path = pathlib.Path(sys.argv[3])
body = body_path.read_text(encoding='utf-8') if body_path.exists() else ''
@@ -33,6 +68,55 @@ print(json.dumps({
'target_commitish': sys.argv[4],
}))
PY
else
jq -cn \
--arg tag "$tag" \
--arg title "$title" \
--arg body "$body" \
--arg target "$target" \
'{tag_name:$tag,name:$title,body:$body,draft:false,prerelease:false,target_commitish:$target}'
fi
}
json_release_id() {
if [[ "$JSON_BACKEND" == python ]]; then
python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])'
else
jq -er '.id'
fi
}
json_matching_asset_ids() {
local name="$1"
if [[ "$JSON_BACKEND" == python ]]; then
python3 -c 'import json,sys; name=sys.argv[1]; [print(a["id"]) for a in json.load(sys.stdin).get("assets",[]) if a.get("name")==name]' "$name"
else
jq -er --arg name "$name" '.assets[]? | select(.name == $name) | .id' 2>/dev/null || true
fi
}
json_downloadable_assets_tsv() {
if [[ "$JSON_BACKEND" == python ]]; then
python3 -c '
import json, sys
release = json.load(sys.stdin)
for asset in release.get("assets", []):
name = asset.get("name", "")
url = asset.get("browser_download_url", "")
if not name or not url or name == "SHA256SUMS.txt":
continue
if name.endswith(".deb") or name.endswith(".rpm") or name.endswith(".pkg.tar.zst") or name.endswith("-linux-amd64.tar.gz"):
print(f"{name}\t{url}")
'
else
jq -r '
.assets[]?
| select(.name != null and .browser_download_url != null and .name != "SHA256SUMS.txt")
| select(.name | endswith(".deb") or endswith(".rpm") or endswith(".pkg.tar.zst") or endswith("-linux-amd64.tar.gz"))
| [.name, .browser_download_url]
| @tsv
'
fi
}
ensure_release() {
@@ -40,7 +124,7 @@ ensure_release() {
local payload current id
payload="$(release_payload "$tag" "$title" "$body_file" "$target")"
if current="$(release_json "$tag" 2>/dev/null)"; then
id="$(printf '%s' "$current" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"
id="$(printf '%s' "$current" | json_release_id)"
curl -fsS "${auth[@]}" -H 'Content-Type: application/json' \
-X PATCH -d "$payload" "${api_base}/releases/${id}" >/dev/null
echo "Updated Gitea release ${tag}"
@@ -56,10 +140,10 @@ upload_asset() {
[[ -s "$file" ]] || { echo "Asset missing/empty: $file" >&2; exit 1; }
local rel id name enc existing_ids
rel="$(release_json "$tag")"
id="$(printf '%s' "$rel" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"
id="$(printf '%s' "$rel" | json_release_id)"
name="$(basename "$file")"
enc="$(urlencode "$name")"
existing_ids="$(printf '%s' "$rel" | python3 -c 'import json,sys; name=sys.argv[1]; [print(a["id"]) for a in json.load(sys.stdin).get("assets",[]) if a.get("name")==name]' "$name")"
existing_ids="$(printf '%s' "$rel" | json_matching_asset_ids "$name")"
if [[ -n "$existing_ids" ]]; then
while IFS= read -r aid; do
[[ -n "$aid" ]] || continue
@@ -75,30 +159,13 @@ upload_asset() {
download_assets() {
local tag="$1" dir="$2"
mkdir -p "$dir"
local rel
local rel name url
rel="$(release_json "$tag")"
printf '%s' "$rel" | python3 -c '
import json, os, pathlib, sys, urllib.request
out = pathlib.Path(sys.argv[1])
release = json.load(sys.stdin)
for asset in release.get("assets", []):
name = asset.get("name", "")
if not name or name == "SHA256SUMS.txt":
continue
if not (name.endswith(".deb") or name.endswith(".rpm") or name.endswith(".pkg.tar.zst") or name.endswith("-linux-amd64.tar.gz")):
continue
req = urllib.request.Request(asset["browser_download_url"])
token = os.environ.get("GITEA_TOKEN", "")
if token:
req.add_header("Authorization", f"token {token}")
with urllib.request.urlopen(req, timeout=120) as r, open(out / name, "wb") as f:
while True:
block = r.read(1024 * 1024)
if not block:
break
f.write(block)
print(name)
' "$dir"
while IFS=$'\t' read -r name url; do
[[ -n "$name" && -n "$url" ]] || continue
curl -fsSL "${auth[@]}" "$url" -o "$dir/$name"
echo "$name"
done < <(printf '%s' "$rel" | json_downloadable_assets_tsv)
}
case "${1:-}" in
+1
View File
@@ -3,6 +3,7 @@ set -euo pipefail
ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
bash "$ROOT/tests/verify.sh"
bash "$ROOT/tests/mode-independence.sh"
bash "$ROOT/tests/rpm-ci-footprint.sh"
(cd "$ROOT/backend" && go test -race ./...)
bash "$ROOT/backend/integration-test.sh"
bash "$ROOT/tests/gitea-release-helper.sh"
+21 -10
View File
@@ -25,7 +25,7 @@ class H(http.server.BaseHTTPRequestHandler):
return r
def do_GET(self):
path=urllib.parse.urlparse(self.path).path
if path.endswith('/releases/tags/v1.1.2'):
if path.endswith('/releases/tags/v1.1.3'):
if release is None: self.send_error(404); return
self.sendj(200,self.rel()); return
if path.startswith('/download/'):
@@ -78,12 +78,23 @@ export GITEA_API_URL="http://127.0.0.1:${PORT}/api/v1"
export GITEA_REPOSITORY="owner/repo"
export GITEA_TOKEN="test-token"
echo first > "$TMP/citizen-launcher_1.1.2_amd64.deb"
bash "$ROOT/scripts/gitea-release.sh" ensure v1.1.2 'Citizen Launcher 1.1.2' "$ROOT/RELEASE_NOTES.md" deadbeef
bash "$ROOT/scripts/gitea-release.sh" ensure v1.1.2 'Citizen Launcher 1.1.2' "$ROOT/RELEASE_NOTES.md" deadbeef
bash "$ROOT/scripts/gitea-release.sh" upload v1.1.2 "$TMP/citizen-launcher_1.1.2_amd64.deb"
echo replacement > "$TMP/citizen-launcher_1.1.2_amd64.deb"
bash "$ROOT/scripts/gitea-release.sh" upload v1.1.2 "$TMP/citizen-launcher_1.1.2_amd64.deb"
bash "$ROOT/scripts/gitea-release.sh" download-assets v1.1.2 "$TMP/download"
cmp "$TMP/citizen-launcher_1.1.2_amd64.deb" "$TMP/download/citizen-launcher_1.1.2_amd64.deb"
echo 'Gitea release helper verification: OK'
echo first > "$TMP/citizen-launcher_1.1.3_amd64.deb"
bash "$ROOT/scripts/gitea-release.sh" ensure v1.1.3 'Citizen Launcher 1.1.3' "$ROOT/RELEASE_NOTES.md" deadbeef
bash "$ROOT/scripts/gitea-release.sh" ensure v1.1.3 'Citizen Launcher 1.1.3' "$ROOT/RELEASE_NOTES.md" deadbeef
bash "$ROOT/scripts/gitea-release.sh" upload v1.1.3 "$TMP/citizen-launcher_1.1.3_amd64.deb"
echo replacement > "$TMP/citizen-launcher_1.1.3_amd64.deb"
bash "$ROOT/scripts/gitea-release.sh" upload v1.1.3 "$TMP/citizen-launcher_1.1.3_amd64.deb"
bash "$ROOT/scripts/gitea-release.sh" download-assets v1.1.3 "$TMP/download"
cmp "$TMP/citizen-launcher_1.1.3_amd64.deb" "$TMP/download/citizen-launcher_1.1.3_amd64.deb"
# Fedora RPM jobs intentionally avoid Python to keep the container footprint low.
# Exercise the jq backend against the same mock Gitea API.
command -v jq >/dev/null 2>&1 || { echo 'jq required for Gitea helper jq test' >&2; exit 1; }
export CITIZEN_JSON_BACKEND=jq
echo jq-backend > "$TMP/citizen-launcher-1.1.3-1.linux.x86_64.rpm"
bash "$ROOT/scripts/gitea-release.sh" ensure v1.1.3 'Citizen Launcher 1.1.3' "$ROOT/RELEASE_NOTES.md" deadbeef
bash "$ROOT/scripts/gitea-release.sh" upload v1.1.3 "$TMP/citizen-launcher-1.1.3-1.linux.x86_64.rpm"
bash "$ROOT/scripts/gitea-release.sh" download-assets v1.1.3 "$TMP/download-jq"
cmp "$TMP/citizen-launcher-1.1.3-1.linux.x86_64.rpm" "$TMP/download-jq/citizen-launcher-1.1.3-1.linux.x86_64.rpm"
echo 'Gitea release helper verification: OK (python + jq)'
+1 -1
View File
@@ -9,7 +9,7 @@ root = Path(sys.argv[1])
check = [
root/'build.sh', root/'install-omarchy.sh', root/'INSTALLIEREN.sh',
root/'tests/full-verify.sh', root/'tests/verify.sh', root/'tests/package-verify.sh',
root/'tests/gitea-release-helper.sh', root/'packaging/build-all.sh',
root/'tests/gitea-release-helper.sh', root/'tests/rpm-ci-footprint.sh', root/'packaging/build-all.sh',
root/'.gitea/workflows/ci.yml', root/'.gitea/workflows/release.yml',
]
for p in check:
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
python3 - "$ROOT" <<'PY'
from pathlib import Path
import re, sys, yaml
root = Path(sys.argv[1])
checks = [
(root/'.gitea/workflows/ci.yml', 'rpm-package'),
(root/'.gitea/workflows/release.yml', 'rpm'),
]
for path, job_name in checks:
data = yaml.safe_load(path.read_text())
job = data['jobs'][job_name]
runs = '\n'.join(str(step.get('run','')) for step in job.get('steps',[]))
flat = re.sub(r'\\\n\s*', ' ', runs)
flat = re.sub(r'\s+', ' ', flat)
required = [
'system_cachedir=',
'install_weak_deps=False',
'tsflags=nodocs',
'install git-core',
'install golang-bin',
'remove golang-bin',
'install rpm-build',
]
for needle in required:
if needle not in flat:
raise SystemExit(f'{path.name}:{job_name} missing low-disk guard: {needle}')
forbidden = ['systemd-rpm-macros', 'install git golang', 'install golang rpm-build', 'install python3']
for needle in forbidden:
if needle in flat:
raise SystemExit(f'{path.name}:{job_name} reintroduced heavy dependency set: {needle}')
if flat.index('install golang-bin') > flat.index('remove golang-bin') or flat.index('remove golang-bin') > flat.index('install rpm-build'):
raise SystemExit(f'{path.name}:{job_name} no longer stages Go before rpmbuild')
print('RPM CI low-disk dependency policy: OK')
PY
+1 -1
View File
@@ -5,7 +5,7 @@ for f in \
"$ROOT/install.sh" "$ROOT/uninstall.sh" "$ROOT/install-omarchy.sh" "$ROOT/INSTALLIEREN.sh" \
"$ROOT/build.sh" "$ROOT/packaging/build-deb.sh" "$ROOT/packaging/build-rpm.sh" \
"$ROOT/packaging/build-arch.sh" "$ROOT/packaging/build-tarball.sh" "$ROOT/packaging/build-all.sh" \
"$ROOT/scripts/gitea-release.sh" "$ROOT/tests/gitea-release-helper.sh" "$ROOT/tests/mode-independence.sh"; do
"$ROOT/scripts/gitea-release.sh" "$ROOT/tests/gitea-release-helper.sh" "$ROOT/tests/mode-independence.sh" "$ROOT/tests/rpm-ci-footprint.sh"; do
bash -n "$f"
done
(cd "$ROOT/backend" && gofmt -w cmd/citizen-launcher && go test ./... && go vet ./...)