BlueGit

golden-age paperdoll-renderer

Release onto the existing tag (create-only route) and AUR paperdoll-renderer-bin job

timfa Grok Bot · pushed by timfa

Authored 2026-11-07 · 6 days ago

Hash
4c6a88eff878d6d5e129ad33b4358495ec5474d3
Parent
6789a60e
5 files changed +237 −28
blue-ci-cd.yml +29 −10
@@ -2,27 +2,28 @@
2 2 #
3 3 # Syntax checked on 6 November 2026 against GET /api/v1/ci/spec,
4 4 # timfa/bluegit docs/CI.md, and the public pipelines of timfa/posprint,
5 # timfa/minecart-trains and timfa/click-tween. legacy-cycles publishes
6 # releases only; its pipeline file is not public and was not copied.
5 # timfa/minecart-trains and timfa/click-tween. The AUR job follows
6 # timfa/legacy-cycles (aur-ssh-setup.sh, publish-aur.sh).
7 7 #
8 8 # Requested graph:
9 9 # merge request and master/main push -> test
10 10 # tag push, after tests succeed -> AppImage, Ubuntu package, Arch package,
11 # Windows build, artifact check, then one release publish
11 # Windows build, artifact check, one release publish, then the AUR
12 12 #
13 # Verified release limit, rechecked against api_routes.go on master: no route
14 # attaches artifacts to an existing tag or release. POST /repos/$CI_PROJECT_PATH/releases
15 # creates the git tag (409 if it exists). replace=true is 403 on a tag pipeline.
16 # scripts/ci/release.sh does not call that route and does not send replace.
17 # The release job exits 3 until BlueGit adds the attach route in design.md.
18 # This file does not create a tag. No release has been started here.
13 # Release (design.md, v0.1.0 decision, rechecked 7 November 2026 against the
14 # live OpenAPI): the release job publishes onto the tag that started this
15 # pipeline with POST /repos/$CI_PROJECT_PATH/releases/$CI_COMMIT_TAG/assets,
16 # BlueGit's create-only route for an existing tag (409 if a release exists;
17 # never creates, moves or deletes the tag). replace is never sent and the
18 # tag-creating release route is not called. Tags are pushed by hand on a green
19 # master; publish:aur then updates the AUR package paperdoll-renderer-bin.
19 20 #
20 21 # posprint notes two runner facts used below: jobs start in the checkout
21 22 # (CI_PROJECT_DIR is not set), and artifact paths are exact files.
22 23 # Windows is cross-compiled with MinGW, the same reason posprint gives:
23 24 # no Windows runner on BlueGit.
24 25
25 stages: [test, package, verify, release]
26 stages: [test, package, verify, release, publish]
26 27
27 28 variables:
28 29 CARGO_TERM_COLOR: always
@@ -164,4 +165,22 @@ release:
164 165 needs: [verify:packages, package:appimage, package:ubuntu, package:arch, package:windows]
165 166 resource_group: release
166 167 script:
168 - apk add --no-cache jq
167 169 - bash scripts/ci/release.sh
170
171 # AUR (approach of timfa/legacy-cycles): after the release, publish
172 # paperdoll-renderer-bin from this tag's .deb release asset. Protected
173 # variables (AUR_SSH_PRIVATE_KEY_B64, AUR_GIT_AUTHOR_NAME, AUR_GIT_AUTHOR_EMAIL)
174 # reach only protected refs; v* is a protected tag pattern.
175 # allow_failure: an AUR outage does not turn the release red.
176 publish:aur:
177 stage: publish
178 image: archlinux/archlinux:base-devel
179 extends: .on_tag
180 needs: [release]
181 allow_failure: true
182 resource_group: aur
183 script:
184 - pacman -Syu --noconfirm --needed git openssh curl coreutils shadow util-linux
185 - bash scripts/ci/aur-ssh-setup.sh
186 - bash scripts/ci/publish-aur.sh paperdoll-renderer-bin
@@ -2,27 +2,28 @@
2#
2#
3# Syntax checked on 6 November 2026 against GET /api/v1/ci/spec,
3# Syntax checked on 6 November 2026 against GET /api/v1/ci/spec,
4# timfa/bluegit docs/CI.md, and the public pipelines of timfa/posprint,
4# timfa/bluegit docs/CI.md, and the public pipelines of timfa/posprint,
5# timfa/minecart-trains and timfa/click-tween. legacy-cycles publishes
5# timfa/minecart-trains and timfa/click-tween. The AUR job follows
6# releases only; its pipeline file is not public and was not copied.
6# timfa/legacy-cycles (aur-ssh-setup.sh, publish-aur.sh).
7#
7#
8# Requested graph:
8# Requested graph:
9# merge request and master/main push -> test
9# merge request and master/main push -> test
10# tag push, after tests succeed -> AppImage, Ubuntu package, Arch package,
10# tag push, after tests succeed -> AppImage, Ubuntu package, Arch package,
11# Windows build, artifact check, then one release publish
11# Windows build, artifact check, one release publish, then the AUR
12#
12#
13# Verified release limit, rechecked against api_routes.go on master: no route
13# Release (design.md, v0.1.0 decision, rechecked 7 November 2026 against the
14# attaches artifacts to an existing tag or release. POST /repos/$CI_PROJECT_PATH/releases
14# live OpenAPI): the release job publishes onto the tag that started this
15# creates the git tag (409 if it exists). replace=true is 403 on a tag pipeline.
15# pipeline with POST /repos/$CI_PROJECT_PATH/releases/$CI_COMMIT_TAG/assets,
16# scripts/ci/release.sh does not call that route and does not send replace.
16# BlueGit's create-only route for an existing tag (409 if a release exists;
17# The release job exits 3 until BlueGit adds the attach route in design.md.
17# never creates, moves or deletes the tag). replace is never sent and the
18# This file does not create a tag. No release has been started here.
18# tag-creating release route is not called. Tags are pushed by hand on a green
19# master; publish:aur then updates the AUR package paperdoll-renderer-bin.
19#
20#
20# posprint notes two runner facts used below: jobs start in the checkout
21# posprint notes two runner facts used below: jobs start in the checkout
21# (CI_PROJECT_DIR is not set), and artifact paths are exact files.
22# (CI_PROJECT_DIR is not set), and artifact paths are exact files.
22# Windows is cross-compiled with MinGW, the same reason posprint gives:
23# Windows is cross-compiled with MinGW, the same reason posprint gives:
23# no Windows runner on BlueGit.
24# no Windows runner on BlueGit.
24
25
25stages: [test, package, verify, release]
26stages: [test, package, verify, release, publish]
26
27
27variables:
28variables:
28 CARGO_TERM_COLOR: always
29 CARGO_TERM_COLOR: always
@@ -164,4 +165,22 @@ release:
164 needs: [verify:packages, package:appimage, package:ubuntu, package:arch, package:windows]
165 needs: [verify:packages, package:appimage, package:ubuntu, package:arch, package:windows]
165 resource_group: release
166 resource_group: release
166 script:
167 script:
168 - apk add --no-cache jq
167 - bash scripts/ci/release.sh
169 - bash scripts/ci/release.sh
170
171# AUR (approach of timfa/legacy-cycles): after the release, publish
172# paperdoll-renderer-bin from this tag's .deb release asset. Protected
173# variables (AUR_SSH_PRIVATE_KEY_B64, AUR_GIT_AUTHOR_NAME, AUR_GIT_AUTHOR_EMAIL)
174# reach only protected refs; v* is a protected tag pattern.
175# allow_failure: an AUR outage does not turn the release red.
176publish:aur:
177 stage: publish
178 image: archlinux/archlinux:base-devel
179 extends: .on_tag
180 needs: [release]
181 allow_failure: true
182 resource_group: aur
183 script:
184 - pacman -Syu --noconfirm --needed git openssh curl coreutils shadow util-linux
185 - bash scripts/ci/aur-ssh-setup.sh
186 - bash scripts/ci/publish-aur.sh paperdoll-renderer-bin
packaging/aur/paperdoll-renderer-bin/PKGBUILD added +44 −0
@@ -0,0 +1,44 @@
1 # Maintainer: Tim Falken <tim@timfalken.com>
2 # CI (scripts/ci/publish-aur.sh) sets pkgver, _tag and sha256sums.
3 pkgname=paperdoll-renderer-bin
4 pkgver=0.1.0
5 pkgrel=1
6 _tag=v0.1.0
7 pkgdesc='Paperdoll Renderer: sprite/paperdoll renders from glTF/FBX bodies with a live preview (prebuilt binary)'
8 arch=('x86_64')
9 url='https://git.timfalken.com/golden-age/paperdoll-renderer'
10 license=('MIT' 'custom:Sketchfab-Standard')
11 depends=('gcc-libs' 'glibc' 'libxcb' 'libx11' 'libxkbcommon' 'libxkbcommon-x11' 'libglvnd'
12 'shared-mime-info' 'desktop-file-utils' 'xdg-desktop-portal' 'zenity')
13 provides=('paperdoll-renderer')
14 conflicts=('paperdoll-renderer')
15 options=('!strip' '!debug')
16 source=("paperdoll-renderer-${_tag}-amd64.deb::${url}/-/releases/${_tag}/assets/paperdoll-renderer-${_tag}-amd64.deb")
17 sha256sums=('SKIP')
18 noextract=("paperdoll-renderer-${_tag}-amd64.deb")
19
20 prepare() {
21 mkdir -p "$srcdir/deb"
22 cd "$srcdir/deb"
23 bsdtar -xf "$srcdir/paperdoll-renderer-${_tag}-amd64.deb"
24 mkdir -p root
25 bsdtar -xf data.tar.* -C root
26 }
27
28 package() {
29 local r="$srcdir/deb/root/usr"
30 install -Dm755 "$r/bin/paperdoll-renderer" "$pkgdir/usr/bin/paperdoll-renderer"
31 install -Dm644 "$r/share/applications/paperdoll-renderer.desktop" \
32 "$pkgdir/usr/share/applications/paperdoll-renderer.desktop"
33 install -Dm644 "$r/share/mime/packages/paperdoll-project.xml" \
34 "$pkgdir/usr/share/mime/packages/paperdoll-project.xml"
35 install -Dm644 "$r/share/metainfo/paperdoll-renderer.metainfo.xml" \
36 "$pkgdir/usr/share/metainfo/paperdoll-renderer.metainfo.xml"
37 local icon
38 for icon in "$r"/share/icons/hicolor/*/apps/paperdoll-renderer.*; do
39 install -Dm644 "$icon" "$pkgdir/usr/share/icons/hicolor/${icon#"$r/share/icons/hicolor/"}"
40 done
41 install -Dm644 "$r/share/licenses/paperdoll-renderer/LICENSE" "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
42 install -Dm644 "$r/share/licenses/paperdoll-renderer/THIRD_PARTY_NOTICES.md" \
43 "$pkgdir/usr/share/licenses/$pkgname/THIRD_PARTY_NOTICES.md"
44 }
@@ -0,0 +1,44 @@
1# Maintainer: Tim Falken <tim@timfalken.com>
2# CI (scripts/ci/publish-aur.sh) sets pkgver, _tag and sha256sums.
3pkgname=paperdoll-renderer-bin
4pkgver=0.1.0
5pkgrel=1
6_tag=v0.1.0
7pkgdesc='Paperdoll Renderer: sprite/paperdoll renders from glTF/FBX bodies with a live preview (prebuilt binary)'
8arch=('x86_64')
9url='https://git.timfalken.com/golden-age/paperdoll-renderer'
10license=('MIT' 'custom:Sketchfab-Standard')
11depends=('gcc-libs' 'glibc' 'libxcb' 'libx11' 'libxkbcommon' 'libxkbcommon-x11' 'libglvnd'
12 'shared-mime-info' 'desktop-file-utils' 'xdg-desktop-portal' 'zenity')
13provides=('paperdoll-renderer')
14conflicts=('paperdoll-renderer')
15options=('!strip' '!debug')
16source=("paperdoll-renderer-${_tag}-amd64.deb::${url}/-/releases/${_tag}/assets/paperdoll-renderer-${_tag}-amd64.deb")
17sha256sums=('SKIP')
18noextract=("paperdoll-renderer-${_tag}-amd64.deb")
19
20prepare() {
21 mkdir -p "$srcdir/deb"
22 cd "$srcdir/deb"
23 bsdtar -xf "$srcdir/paperdoll-renderer-${_tag}-amd64.deb"
24 mkdir -p root
25 bsdtar -xf data.tar.* -C root
26}
27
28package() {
29 local r="$srcdir/deb/root/usr"
30 install -Dm755 "$r/bin/paperdoll-renderer" "$pkgdir/usr/bin/paperdoll-renderer"
31 install -Dm644 "$r/share/applications/paperdoll-renderer.desktop" \
32 "$pkgdir/usr/share/applications/paperdoll-renderer.desktop"
33 install -Dm644 "$r/share/mime/packages/paperdoll-project.xml" \
34 "$pkgdir/usr/share/mime/packages/paperdoll-project.xml"
35 install -Dm644 "$r/share/metainfo/paperdoll-renderer.metainfo.xml" \
36 "$pkgdir/usr/share/metainfo/paperdoll-renderer.metainfo.xml"
37 local icon
38 for icon in "$r"/share/icons/hicolor/*/apps/paperdoll-renderer.*; do
39 install -Dm644 "$icon" "$pkgdir/usr/share/icons/hicolor/${icon#"$r/share/icons/hicolor/"}"
40 done
41 install -Dm644 "$r/share/licenses/paperdoll-renderer/LICENSE" "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
42 install -Dm644 "$r/share/licenses/paperdoll-renderer/THIRD_PARTY_NOTICES.md" \
43 "$pkgdir/usr/share/licenses/$pkgname/THIRD_PARTY_NOTICES.md"
44}
scripts/ci/aur-ssh-setup.sh added +78 −0
@@ -0,0 +1,78 @@
1 #!/usr/bin/env bash
2 # Write ~/.ssh/id_ed25519 for AUR pushes from CI or local scripts.
3 #
4 # Supported CI variables (pick one):
5 # AUR_SSH_PRIVATE_KEY_B64 — base64 of the private key (Variable type, one line; Masked OK)
6 # or File type whose contents are that base64 string
7 # AUR_SSH_PRIVATE_KEY — raw OpenSSH private key (File type preferred), or raw key text
8 # File contents may also be base64 (auto-detected)
9 #
10 # Always normalizes CRLF → LF (Windows pastes into GitLab often break OpenSSH otherwise).
11 set -euo pipefail
12
13 KEY_PATH="${1:-$HOME/.ssh/id_ed25519}"
14
15 install -d -m 700 "$(dirname "$KEY_PATH")"
16
17 is_raw_ssh_key() {
18 grep -qE 'BEGIN (OPENSSH |RSA |EC )?PRIVATE KEY' "$1" 2>/dev/null
19 }
20
21 normalize_key_file() {
22 local tmp
23 tmp="$(mktemp)"
24 tr -d '\r' < "$KEY_PATH" > "$tmp"
25 if [[ -s "$tmp" ]] && [[ "$(tail -c1 "$tmp" | wc -l)" -eq 0 ]]; then
26 printf '\n' >> "$tmp"
27 fi
28 mv "$tmp" "$KEY_PATH"
29 chmod 600 "$KEY_PATH"
30 }
31
32 decode_b64_to_key() {
33 local src="$1"
34 if [[ -f "$src" ]]; then
35 tr -d '\r\n[:space:]' < "$src" | base64 -d > "$KEY_PATH"
36 else
37 printf '%s' "$src" | tr -d '\r\n[:space:]' | base64 -d > "$KEY_PATH"
38 fi
39 }
40
41 if [[ -n "${AUR_SSH_PRIVATE_KEY_B64:-}" ]]; then
42 decode_b64_to_key "$AUR_SSH_PRIVATE_KEY_B64"
43 elif [[ -n "${AUR_SSH_PRIVATE_KEY:-}" && -f "${AUR_SSH_PRIVATE_KEY}" ]]; then
44 if is_raw_ssh_key "$AUR_SSH_PRIVATE_KEY"; then
45 cp "$AUR_SSH_PRIVATE_KEY" "$KEY_PATH"
46 else
47 decode_b64_to_key "$AUR_SSH_PRIVATE_KEY"
48 fi
49 elif [[ -n "${AUR_SSH_PRIVATE_KEY:-}" ]]; then
50 if printf '%s' "$AUR_SSH_PRIVATE_KEY" | grep -qE 'BEGIN (OPENSSH |RSA |EC )?PRIVATE KEY'; then
51 printf '%s\n' "$AUR_SSH_PRIVATE_KEY" > "$KEY_PATH"
52 else
53 decode_b64_to_key "$AUR_SSH_PRIVATE_KEY"
54 fi
55 elif [[ -f "$HOME/.ssh/id_ed25519" ]]; then
56 cp "$HOME/.ssh/id_ed25519" "$KEY_PATH"
57 else
58 echo "No AUR SSH key found. Set AUR_SSH_PRIVATE_KEY_B64 or AUR_SSH_PRIVATE_KEY." >&2
59 exit 1
60 fi
61
62 normalize_key_file
63
64 if ! is_raw_ssh_key "$KEY_PATH"; then
65 echo "AUR SSH key is not a valid OpenSSH private key after setup." >&2
66 echo "Use either:" >&2
67 echo " - AUR_SSH_PRIVATE_KEY as File with raw key (BEGIN ... PRIVATE KEY)" >&2
68 echo " - AUR_SSH_PRIVATE_KEY_B64 as Variable with one-line base64 of that key" >&2
69 echo "Tip: generate base64 from a LF-normalized key (see docs/CI.md)." >&2
70 exit 1
71 fi
72
73 if ! ssh-keygen -y -f "$KEY_PATH" >/dev/null 2>&1; then
74 echo "AUR SSH key failed ssh-keygen validation (often CRLF or truncated paste)." >&2
75 exit 1
76 fi
77
78 ssh-keyscan aur.archlinux.org >> "$HOME/.ssh/known_hosts" 2>/dev/null || true
@@ -0,0 +1,78 @@
1#!/usr/bin/env bash
2# Write ~/.ssh/id_ed25519 for AUR pushes from CI or local scripts.
3#
4# Supported CI variables (pick one):
5# AUR_SSH_PRIVATE_KEY_B64 — base64 of the private key (Variable type, one line; Masked OK)
6# or File type whose contents are that base64 string
7# AUR_SSH_PRIVATE_KEY — raw OpenSSH private key (File type preferred), or raw key text
8# File contents may also be base64 (auto-detected)
9#
10# Always normalizes CRLF → LF (Windows pastes into GitLab often break OpenSSH otherwise).
11set -euo pipefail
12
13KEY_PATH="${1:-$HOME/.ssh/id_ed25519}"
14
15install -d -m 700 "$(dirname "$KEY_PATH")"
16
17is_raw_ssh_key() {
18 grep -qE 'BEGIN (OPENSSH |RSA |EC )?PRIVATE KEY' "$1" 2>/dev/null
19}
20
21normalize_key_file() {
22 local tmp
23 tmp="$(mktemp)"
24 tr -d '\r' < "$KEY_PATH" > "$tmp"
25 if [[ -s "$tmp" ]] && [[ "$(tail -c1 "$tmp" | wc -l)" -eq 0 ]]; then
26 printf '\n' >> "$tmp"
27 fi
28 mv "$tmp" "$KEY_PATH"
29 chmod 600 "$KEY_PATH"
30}
31
32decode_b64_to_key() {
33 local src="$1"
34 if [[ -f "$src" ]]; then
35 tr -d '\r\n[:space:]' < "$src" | base64 -d > "$KEY_PATH"
36 else
37 printf '%s' "$src" | tr -d '\r\n[:space:]' | base64 -d > "$KEY_PATH"
38 fi
39}
40
41if [[ -n "${AUR_SSH_PRIVATE_KEY_B64:-}" ]]; then
42 decode_b64_to_key "$AUR_SSH_PRIVATE_KEY_B64"
43elif [[ -n "${AUR_SSH_PRIVATE_KEY:-}" && -f "${AUR_SSH_PRIVATE_KEY}" ]]; then
44 if is_raw_ssh_key "$AUR_SSH_PRIVATE_KEY"; then
45 cp "$AUR_SSH_PRIVATE_KEY" "$KEY_PATH"
46 else
47 decode_b64_to_key "$AUR_SSH_PRIVATE_KEY"
48 fi
49elif [[ -n "${AUR_SSH_PRIVATE_KEY:-}" ]]; then
50 if printf '%s' "$AUR_SSH_PRIVATE_KEY" | grep -qE 'BEGIN (OPENSSH |RSA |EC )?PRIVATE KEY'; then
51 printf '%s\n' "$AUR_SSH_PRIVATE_KEY" > "$KEY_PATH"
52 else
53 decode_b64_to_key "$AUR_SSH_PRIVATE_KEY"
54 fi
55elif [[ -f "$HOME/.ssh/id_ed25519" ]]; then
56 cp "$HOME/.ssh/id_ed25519" "$KEY_PATH"
57else
58 echo "No AUR SSH key found. Set AUR_SSH_PRIVATE_KEY_B64 or AUR_SSH_PRIVATE_KEY." >&2
59 exit 1
60fi
61
62normalize_key_file
63
64if ! is_raw_ssh_key "$KEY_PATH"; then
65 echo "AUR SSH key is not a valid OpenSSH private key after setup." >&2
66 echo "Use either:" >&2
67 echo " - AUR_SSH_PRIVATE_KEY as File with raw key (BEGIN ... PRIVATE KEY)" >&2
68 echo " - AUR_SSH_PRIVATE_KEY_B64 as Variable with one-line base64 of that key" >&2
69 echo "Tip: generate base64 from a LF-normalized key (see docs/CI.md)." >&2
70 exit 1
71fi
72
73if ! ssh-keygen -y -f "$KEY_PATH" >/dev/null 2>&1; then
74 echo "AUR SSH key failed ssh-keygen validation (often CRLF or truncated paste)." >&2
75 exit 1
76fi
77
78ssh-keyscan aur.archlinux.org >> "$HOME/.ssh/known_hosts" 2>/dev/null || true
scripts/ci/publish-aur.sh added +48 −0
@@ -0,0 +1,48 @@
1 #!/usr/bin/env bash
2 # publish-aur.sh PKGNAME — adapted from timfa/legacy-cycles.
3 # Runs in the tag pipeline after `release`: downloads this tag's .deb release
4 # asset, sets pkgver/_tag/sha256sums in packaging/aur/PKGNAME/PKGBUILD,
5 # regenerates .SRCINFO and pushes to aur.archlinux.org (the first push creates
6 # the AUR package). Uses AUR_GIT_AUTHOR_NAME / AUR_GIT_AUTHOR_EMAIL; the SSH
7 # key comes from aur-ssh-setup.sh (AUR_SSH_PRIVATE_KEY_B64).
8 set -euo pipefail
9 pkg="$1"
10 ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
11 SRC="$ROOT/packaging/aur/$pkg"
12 : "${CI_COMMIT_TAG:?}" "${CI_PROJECT_URL:?}" "${AUR_GIT_AUTHOR_NAME:?}" "${AUR_GIT_AUTHOR_EMAIL:?}"
13 tag="$CI_COMMIT_TAG"
14 [[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "not a release tag: $tag" >&2; exit 1; }
15 ver="${tag#v}"
16 url="$CI_PROJECT_URL/-/releases/$tag/assets/paperdoll-renderer-${tag}-amd64.deb"
17
18 WORKDIR="$(mktemp -d)"; export WORKDIR
19 trap 'rm -rf "$WORKDIR"' EXIT
20 curl -fsSL "$url" -o "$WORKDIR/asset.deb"
21 sha="$(sha256sum "$WORKDIR/asset.deb" | awk '{print $1}')"
22 echo "$pkg $ver $url $sha"
23
24 dest="$WORKDIR/$pkg"
25 remote="ssh://aur@aur.archlinux.org/${pkg}.git"
26 if ! git clone "$remote" "$dest"; then
27 echo "AUR repo $pkg does not exist yet; the first push creates it"
28 mkdir -p "$dest"; git -C "$dest" init -q -b master; git -C "$dest" remote add origin "$remote"
29 fi
30 git -C "$dest" symbolic-ref HEAD refs/heads/master
31 find "$dest" -mindepth 1 -maxdepth 1 ! -name .git -exec rm -rf {} +
32 cp -a "$SRC/." "$dest/"
33 cd "$dest"
34 sed -i "s/^pkgver=.*/pkgver=${ver}/; s/^pkgrel=.*/pkgrel=1/; s/^_tag=.*/_tag=${tag}/; s/^sha256sums=.*/sha256sums=('${sha}')/" PKGBUILD
35
36 useradd -m aurbuild 2>/dev/null || true
37 chmod 755 "$WORKDIR"; chown -R aurbuild "$dest"
38 runuser -u aurbuild -- makepkg --printsrcinfo > "$WORKDIR/srcinfo"
39 mv "$WORKDIR/srcinfo" .SRCINFO
40 chown -R root:root "$dest"
41 git config --global --add safe.directory '*'
42 git config user.name "$AUR_GIT_AUTHOR_NAME"
43 git config user.email "$AUR_GIT_AUTHOR_EMAIL"
44 git add -A
45 if git diff --cached --quiet; then echo "AUR $pkg already up to date ($ver)"; exit 0; fi
46 git commit -qm "$ver"
47 git push -u origin HEAD:master
48 echo "AUR updated: $pkg $ver"
@@ -0,0 +1,48 @@
1#!/usr/bin/env bash
2# publish-aur.sh PKGNAME — adapted from timfa/legacy-cycles.
3# Runs in the tag pipeline after `release`: downloads this tag's .deb release
4# asset, sets pkgver/_tag/sha256sums in packaging/aur/PKGNAME/PKGBUILD,
5# regenerates .SRCINFO and pushes to aur.archlinux.org (the first push creates
6# the AUR package). Uses AUR_GIT_AUTHOR_NAME / AUR_GIT_AUTHOR_EMAIL; the SSH
7# key comes from aur-ssh-setup.sh (AUR_SSH_PRIVATE_KEY_B64).
8set -euo pipefail
9pkg="$1"
10ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
11SRC="$ROOT/packaging/aur/$pkg"
12: "${CI_COMMIT_TAG:?}" "${CI_PROJECT_URL:?}" "${AUR_GIT_AUTHOR_NAME:?}" "${AUR_GIT_AUTHOR_EMAIL:?}"
13tag="$CI_COMMIT_TAG"
14[[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "not a release tag: $tag" >&2; exit 1; }
15ver="${tag#v}"
16url="$CI_PROJECT_URL/-/releases/$tag/assets/paperdoll-renderer-${tag}-amd64.deb"
17
18WORKDIR="$(mktemp -d)"; export WORKDIR
19trap 'rm -rf "$WORKDIR"' EXIT
20curl -fsSL "$url" -o "$WORKDIR/asset.deb"
21sha="$(sha256sum "$WORKDIR/asset.deb" | awk '{print $1}')"
22echo "$pkg $ver $url $sha"
23
24dest="$WORKDIR/$pkg"
25remote="ssh://aur@aur.archlinux.org/${pkg}.git"
26if ! git clone "$remote" "$dest"; then
27 echo "AUR repo $pkg does not exist yet; the first push creates it"
28 mkdir -p "$dest"; git -C "$dest" init -q -b master; git -C "$dest" remote add origin "$remote"
29fi
30git -C "$dest" symbolic-ref HEAD refs/heads/master
31find "$dest" -mindepth 1 -maxdepth 1 ! -name .git -exec rm -rf {} +
32cp -a "$SRC/." "$dest/"
33cd "$dest"
34sed -i "s/^pkgver=.*/pkgver=${ver}/; s/^pkgrel=.*/pkgrel=1/; s/^_tag=.*/_tag=${tag}/; s/^sha256sums=.*/sha256sums=('${sha}')/" PKGBUILD
35
36useradd -m aurbuild 2>/dev/null || true
37chmod 755 "$WORKDIR"; chown -R aurbuild "$dest"
38runuser -u aurbuild -- makepkg --printsrcinfo > "$WORKDIR/srcinfo"
39mv "$WORKDIR/srcinfo" .SRCINFO
40chown -R root:root "$dest"
41git config --global --add safe.directory '*'
42git config user.name "$AUR_GIT_AUTHOR_NAME"
43git config user.email "$AUR_GIT_AUTHOR_EMAIL"
44git add -A
45if git diff --cached --quiet; then echo "AUR $pkg already up to date ($ver)"; exit 0; fi
46git commit -qm "$ver"
47git push -u origin HEAD:master
48echo "AUR updated: $pkg $ver"
scripts/ci/release.sh +38 −18
@@ -1,17 +1,12 @@
1 1 #!/usr/bin/env bash
2 # Tag-pipeline publish step.
2 # Tag-pipeline publish step (design.md, "v0.1.0 release" decision).
3 3 #
4 # Inspected BlueGit master on 6 November 2026 (api_routes.go, ops_ci.go
5 # opPublishRelease, release_replace.go checkReplace, gitrepo.Tag):
6 # there is no route that attaches artifacts to an existing git tag or an
7 # existing release. POST /api/v1/repos/{owner}/{repo}/releases always creates
8 # the annotated tag. An existing tag returns HTTP 409 unless replace=true,
9 # and replace=true is HTTP 403 on a tag pipeline.
10 #
11 # This script therefore does not call that endpoint and does not send
12 # replace. It exits 3 until BlueGit grows an attach route. It does not
13 # invent a second tag and it does not switch the pipeline onto a branch
14 # release. The required server change is recorded in design.md section 15.
4 # Publishes the release for the tag that started this pipeline with
5 # POST $CI_API_URL/repos/{owner}/{repo}/releases/{tag}/assets — BlueGit's
6 # create-only route for an existing tag: an existing release is HTTP 409, it
7 # never creates, moves or deletes the tag, and the assets are artifacts of
8 # successful jobs of this same pipeline. `replace` is never sent and the
9 # tag-creating route POST .../releases is never called.
15 10 set -euo pipefail
16 11
17 12 : "${CI_API_URL:?}" "${CI_JOB_TOKEN:?}" "${CI_COMMIT_SHA:?}" "${CI_PROJECT_PATH:?}" "${CI_COMMIT_TAG:?}"
@@ -19,10 +14,35 @@ set -euo pipefail
19 14 root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
20 15 cd "$root"
21 16 version="$(bash scripts/ci/package-version.sh)"
17 tag="$CI_COMMIT_TAG"
18 [[ "$tag" == "v$version" ]] || { echo "tag $tag does not match package version $version" >&2; exit 1; }
19
20 b="paperdoll-renderer-${tag}"
21 asset() { jq -n --arg j "$1" --arg p "$2" --arg n "$3" '{job:$j,path:$p,name:$n}'; }
22 assets="$(jq -s . \
23 <(asset package:appimage dist/paperdoll-renderer-x86_64.AppImage "${b}-x86_64.AppImage") \
24 <(asset package:ubuntu dist/paperdoll-renderer_amd64.deb "${b}-amd64.deb") \
25 <(asset package:arch dist/paperdoll-renderer-x86_64.pkg.tar.zst "${b}-x86_64.pkg.tar.zst") \
26 <(asset package:windows dist/paperdoll-renderer-windows-x86_64.zip "${b}-windows-x86_64.zip") \
27 <(asset verify:packages dist/SHA256SUMS "${b}-SHA256SUMS.txt"))"
28 desc="Paperdoll Renderer ${version}.
29
30 * Linux AppImage (portable).
31 * Debian/Ubuntu .deb: /usr/bin/paperdoll-renderer, desktop entry, icons, .ppd MIME type.
32 * Arch .pkg.tar.zst, built from packaging/arch/PKGBUILD. AUR: paperdoll-renderer-bin.
33 * Windows zip (x86_64, MinGW build).
34 * SHA256SUMS of the package files.
35
36 The default starter bodies are \"Animated walking Male Base Mesh\" and \"Animated Female Base Mesh\" by assetfactory (Sketchfab Standard licence); see THIRD_PARTY_NOTICES.md."
37 body="$(jq -n --arg n "Paperdoll Renderer ${tag}" --arg b "$desc" --argjson a "$assets" '{name:$n,body:$b,assets:$a}')"
22 38
23 echo "release-blocked: no-attach-endpoint" >&2
24 echo "tag ${CI_COMMIT_TAG} version ${version} commit ${CI_COMMIT_SHA} project ${CI_PROJECT_PATH}" >&2
25 echo "BlueGit has no request that publishes these package artifacts onto the tag that already started this pipeline." >&2
26 echo "The create-release route would make a new annotated tag. This script does not call it." >&2
27 echo "The overwrite flag is not sent. No second tag is created." >&2
28 exit 3
39 echo "Release $tag on $CI_COMMIT_SHA (existing tag, create-only)"
40 resp="$(mktemp)"
41 code="$(curl -sS -o "$resp" -w '%{http_code}' -X POST \
42 "$CI_API_URL/repos/$CI_PROJECT_PATH/releases/$tag/assets" \
43 -H "Authorization: Bearer $CI_JOB_TOKEN" -H "Content-Type: application/json" -d "$body")" || code=000
44 cat "$resp"; echo
45 if [[ "$code" != 2* ]]; then
46 echo "release API returned HTTP $code (see response above)" >&2
47 exit 1
48 fi
@@ -1,17 +1,12 @@
1#!/usr/bin/env bash
1#!/usr/bin/env bash
2# Tag-pipeline publish step.
2# Tag-pipeline publish step (design.md, "v0.1.0 release" decision).
3#
3#
4# Inspected BlueGit master on 6 November 2026 (api_routes.go, ops_ci.go
4# Publishes the release for the tag that started this pipeline with
5# opPublishRelease, release_replace.go checkReplace, gitrepo.Tag):
5# POST $CI_API_URL/repos/{owner}/{repo}/releases/{tag}/assets — BlueGit's
6# there is no route that attaches artifacts to an existing git tag or an
6# create-only route for an existing tag: an existing release is HTTP 409, it
7# existing release. POST /api/v1/repos/{owner}/{repo}/releases always creates
7# never creates, moves or deletes the tag, and the assets are artifacts of
8# the annotated tag. An existing tag returns HTTP 409 unless replace=true,
8# successful jobs of this same pipeline. `replace` is never sent and the
9# and replace=true is HTTP 403 on a tag pipeline.
9# tag-creating route POST .../releases is never called.
10#
11# This script therefore does not call that endpoint and does not send
12# replace. It exits 3 until BlueGit grows an attach route. It does not
13# invent a second tag and it does not switch the pipeline onto a branch
14# release. The required server change is recorded in design.md section 15.
15set -euo pipefail
10set -euo pipefail
16
11
17: "${CI_API_URL:?}" "${CI_JOB_TOKEN:?}" "${CI_COMMIT_SHA:?}" "${CI_PROJECT_PATH:?}" "${CI_COMMIT_TAG:?}"
12: "${CI_API_URL:?}" "${CI_JOB_TOKEN:?}" "${CI_COMMIT_SHA:?}" "${CI_PROJECT_PATH:?}" "${CI_COMMIT_TAG:?}"
@@ -19,10 +14,35 @@ set -euo pipefail
19root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
14root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
20cd "$root"
15cd "$root"
21version="$(bash scripts/ci/package-version.sh)"
16version="$(bash scripts/ci/package-version.sh)"
17tag="$CI_COMMIT_TAG"
18[[ "$tag" == "v$version" ]] || { echo "tag $tag does not match package version $version" >&2; exit 1; }
19
20b="paperdoll-renderer-${tag}"
21asset() { jq -n --arg j "$1" --arg p "$2" --arg n "$3" '{job:$j,path:$p,name:$n}'; }
22assets="$(jq -s . \
23 <(asset package:appimage dist/paperdoll-renderer-x86_64.AppImage "${b}-x86_64.AppImage") \
24 <(asset package:ubuntu dist/paperdoll-renderer_amd64.deb "${b}-amd64.deb") \
25 <(asset package:arch dist/paperdoll-renderer-x86_64.pkg.tar.zst "${b}-x86_64.pkg.tar.zst") \
26 <(asset package:windows dist/paperdoll-renderer-windows-x86_64.zip "${b}-windows-x86_64.zip") \
27 <(asset verify:packages dist/SHA256SUMS "${b}-SHA256SUMS.txt"))"
28desc="Paperdoll Renderer ${version}.
29
30* Linux AppImage (portable).
31* Debian/Ubuntu .deb: /usr/bin/paperdoll-renderer, desktop entry, icons, .ppd MIME type.
32* Arch .pkg.tar.zst, built from packaging/arch/PKGBUILD. AUR: paperdoll-renderer-bin.
33* Windows zip (x86_64, MinGW build).
34* SHA256SUMS of the package files.
35
36The default starter bodies are \"Animated walking Male Base Mesh\" and \"Animated Female Base Mesh\" by assetfactory (Sketchfab Standard licence); see THIRD_PARTY_NOTICES.md."
37body="$(jq -n --arg n "Paperdoll Renderer ${tag}" --arg b "$desc" --argjson a "$assets" '{name:$n,body:$b,assets:$a}')"
22
38
23echo "release-blocked: no-attach-endpoint" >&2
39echo "Release $tag on $CI_COMMIT_SHA (existing tag, create-only)"
24echo "tag ${CI_COMMIT_TAG} version ${version} commit ${CI_COMMIT_SHA} project ${CI_PROJECT_PATH}" >&2
40resp="$(mktemp)"
25echo "BlueGit has no request that publishes these package artifacts onto the tag that already started this pipeline." >&2
41code="$(curl -sS -o "$resp" -w '%{http_code}' -X POST \
26echo "The create-release route would make a new annotated tag. This script does not call it." >&2
42 "$CI_API_URL/repos/$CI_PROJECT_PATH/releases/$tag/assets" \
27echo "The overwrite flag is not sent. No second tag is created." >&2
43 -H "Authorization: Bearer $CI_JOB_TOKEN" -H "Content-Type: application/json" -d "$body")" || code=000
28exit 3
44cat "$resp"; echo
45if [[ "$code" != 2* ]]; then
46 echo "release API returned HTTP $code (see response above)" >&2
47 exit 1
48fi