Merge feature/release-aur (v0.1.0 release + AUR)
@@ -193,6 +193,10 @@ let layer = LayerMaps::from_atlas(&body, "body", "clip000-walk", 0, 60, 330)?;
193
193
194
194
Highres is exactly 8× on both axes; batch targets are currently **1–256 pixels per axis** (highres max 2048). Larger project settings give a clear render error, not silently reduced supersampling. At most 500000 PNGs / 16 GiB of estimated uncompressed target data per run; output requires hard links. Production renders all glTF/GLB meshes with triangle primitives (see *Multiple meshes and skins*), base color factor × 8-bit albedo textures per material, and vertex colors. An FBX body goes through the normalized scene (`fbx_scene`) in the same batch: all animation stacks × frames × 60 angles, the same fixed camera, centre pivot and fixed zoom per body, and the same four maps. Equipment hangs on the animated bones of that FBX skeleton. Static bodies render one bind-pose sample per angle (see *Static bodies*). Live placement remains a lit, simplified view.
195
195
196
## Releases and packages
197
198
A pushed `vX.Y.Z` tag (protected pattern `v*`) runs the tag pipeline: tests, then the AppImage, Debian/Ubuntu `.deb`, Arch `.pkg.tar.zst` and Windows zip, a package check with `SHA256SUMS`, and the release job, which publishes those files as the release of that existing tag on BlueGit (`https://git.timfalken.com/golden-age/paperdoll-renderer/-/releases`). It then updates the AUR package `paperdoll-renderer-bin` from the release's `.deb` (`yay -S paperdoll-renderer-bin`).
199
196
200
## Open with
197
201
198
202
- **Windows:** run the unpacked `.exe` once to add the editor to *Open with* for the current account. Then choose **Open with → Paperdoll Renderer** on a `.ppd` (or select the `.exe` via Browse).
@@ -193,6 +193,10 @@ let layer = LayerMaps::from_atlas(&body, "body", "clip000-walk", 0, 60, 330)?;193
193
194
Highres is exactly 8× on both axes; batch targets are currently **1–256 pixels per axis** (highres max 2048). Larger project settings give a clear render error, not silently reduced supersampling. At most 500000 PNGs / 16 GiB of estimated uncompressed target data per run; output requires hard links. Production renders all glTF/GLB meshes with triangle primitives (see *Multiple meshes and skins*), base color factor × 8-bit albedo textures per material, and vertex colors. An FBX body goes through the normalized scene (`fbx_scene`) in the same batch: all animation stacks × frames × 60 angles, the same fixed camera, centre pivot and fixed zoom per body, and the same four maps. Equipment hangs on the animated bones of that FBX skeleton. Static bodies render one bind-pose sample per angle (see *Static bodies*). Live placement remains a lit, simplified view.194
Highres is exactly 8× on both axes; batch targets are currently **1–256 pixels per axis** (highres max 2048). Larger project settings give a clear render error, not silently reduced supersampling. At most 500000 PNGs / 16 GiB of estimated uncompressed target data per run; output requires hard links. Production renders all glTF/GLB meshes with triangle primitives (see *Multiple meshes and skins*), base color factor × 8-bit albedo textures per material, and vertex colors. An FBX body goes through the normalized scene (`fbx_scene`) in the same batch: all animation stacks × frames × 60 angles, the same fixed camera, centre pivot and fixed zoom per body, and the same four maps. Equipment hangs on the animated bones of that FBX skeleton. Static bodies render one bind-pose sample per angle (see *Static bodies*). Live placement remains a lit, simplified view.195
195
196
## Releases and packages197
198
A pushed `vX.Y.Z` tag (protected pattern `v*`) runs the tag pipeline: tests, then the AppImage, Debian/Ubuntu `.deb`, Arch `.pkg.tar.zst` and Windows zip, a package check with `SHA256SUMS`, and the release job, which publishes those files as the release of that existing tag on BlueGit (`https://git.timfalken.com/golden-age/paperdoll-renderer/-/releases`). It then updates the AUR package `paperdoll-renderer-bin` from the release's `.deb` (`yay -S paperdoll-renderer-bin`).199
196
## Open with200
## Open with197
201
198
- **Windows:** run the unpacked `.exe` once to add the editor to *Open with* for the current account. Then choose **Open with → Paperdoll Renderer** on a `.ppd` (or select the `.exe` via Browse).202
- **Windows:** run the unpacked `.exe` once to add the editor to *Open with* for the current account. Then choose **Open with → Paperdoll Renderer** on a `.ppd` (or select the `.exe` via Browse).@@ -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 publishes5
# timfa/minecart-trains and timfa/click-tween. The AUR job follows6
# 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 -> test9
# merge request and master/main push -> test10
# 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 publish11
# Windows build, artifact check, one release publish, then the AUR12
#12
#13
# Verified release limit, rechecked against api_routes.go on master: no route13
# Release (design.md, v0.1.0 decision, rechecked 7 November 2026 against the14
# attaches artifacts to an existing tag or release. POST /repos/$CI_PROJECT_PATH/releases14
# live OpenAPI): the release job publishes onto the tag that started this15
# 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 the18
# 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 green19
# 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 checkout21
# posprint notes two runner facts used below: jobs start in the checkout21
# (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
25
stages: [test, package, verify, release]26
stages: [test, package, verify, release, publish]26
27
27
variables:28
variables:28
CARGO_TERM_COLOR: always29
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: release166
resource_group: release166
script:167
script:168
- apk add --no-cache jq167
- bash scripts/ci/release.sh169
- bash scripts/ci/release.sh170
171
# AUR (approach of timfa/legacy-cycles): after the release, publish172
# paperdoll-renderer-bin from this tag's .deb release asset. Protected173
# 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: publish178
image: archlinux/archlinux:base-devel179
extends: .on_tag180
needs: [release]181
allow_failure: true182
resource_group: aur183
script:184
- pacman -Syu --noconfirm --needed git openssh curl coreutils shadow util-linux185
- bash scripts/ci/aur-ssh-setup.sh186
- bash scripts/ci/publish-aur.sh paperdoll-renderer-bin@@ -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.3
pkgname=paperdoll-renderer-bin4
pkgver=0.1.05
pkgrel=16
_tag=v0.1.07
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 root25
bsdtar -xf data.tar.* -C root26
}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 icon38
for icon in "$r"/share/icons/hicolor/*/apps/paperdoll-renderer.*; do39
install -Dm644 "$icon" "$pkgdir/usr/share/icons/hicolor/${icon#"$r/share/icons/hicolor/"}"40
done41
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,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 bash2
# 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 string7
# AUR_SSH_PRIVATE_KEY — raw OpenSSH private key (File type preferred), or raw key text8
# 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 pipefail12
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/null19
}20
21
normalize_key_file() {22
local tmp23
tmp="$(mktemp)"24
tr -d '\r' < "$KEY_PATH" > "$tmp"25
if [[ -s "$tmp" ]] && [[ "$(tail -c1 "$tmp" | wc -l)" -eq 0 ]]; then26
printf '\n' >> "$tmp"27
fi28
mv "$tmp" "$KEY_PATH"29
chmod 600 "$KEY_PATH"30
}31
32
decode_b64_to_key() {33
local src="$1"34
if [[ -f "$src" ]]; then35
tr -d '\r\n[:space:]' < "$src" | base64 -d > "$KEY_PATH"36
else37
printf '%s' "$src" | tr -d '\r\n[:space:]' | base64 -d > "$KEY_PATH"38
fi39
}40
41
if [[ -n "${AUR_SSH_PRIVATE_KEY_B64:-}" ]]; then42
decode_b64_to_key "$AUR_SSH_PRIVATE_KEY_B64"43
elif [[ -n "${AUR_SSH_PRIVATE_KEY:-}" && -f "${AUR_SSH_PRIVATE_KEY}" ]]; then44
if is_raw_ssh_key "$AUR_SSH_PRIVATE_KEY"; then45
cp "$AUR_SSH_PRIVATE_KEY" "$KEY_PATH"46
else47
decode_b64_to_key "$AUR_SSH_PRIVATE_KEY"48
fi49
elif [[ -n "${AUR_SSH_PRIVATE_KEY:-}" ]]; then50
if printf '%s' "$AUR_SSH_PRIVATE_KEY" | grep -qE 'BEGIN (OPENSSH |RSA |EC )?PRIVATE KEY'; then51
printf '%s\n' "$AUR_SSH_PRIVATE_KEY" > "$KEY_PATH"52
else53
decode_b64_to_key "$AUR_SSH_PRIVATE_KEY"54
fi55
elif [[ -f "$HOME/.ssh/id_ed25519" ]]; then56
cp "$HOME/.ssh/id_ed25519" "$KEY_PATH"57
else58
echo "No AUR SSH key found. Set AUR_SSH_PRIVATE_KEY_B64 or AUR_SSH_PRIVATE_KEY." >&259
exit 160
fi61
62
normalize_key_file63
64
if ! is_raw_ssh_key "$KEY_PATH"; then65
echo "AUR SSH key is not a valid OpenSSH private key after setup." >&266
echo "Use either:" >&267
echo " - AUR_SSH_PRIVATE_KEY as File with raw key (BEGIN ... PRIVATE KEY)" >&268
echo " - AUR_SSH_PRIVATE_KEY_B64 as Variable with one-line base64 of that key" >&269
echo "Tip: generate base64 from a LF-normalized key (see docs/CI.md)." >&270
exit 171
fi72
73
if ! ssh-keygen -y -f "$KEY_PATH" >/dev/null 2>&1; then74
echo "AUR SSH key failed ssh-keygen validation (often CRLF or truncated paste)." >&275
exit 176
fi77
78
ssh-keyscan aur.archlinux.org >> "$HOME/.ssh/known_hosts" 2>/dev/null || true@@ -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 bash2
# publish-aur.sh PKGNAME — adapted from timfa/legacy-cycles.3
# Runs in the tag pipeline after `release`: downloads this tag's .deb release4
# asset, sets pkgver/_tag/sha256sums in packaging/aur/PKGNAME/PKGBUILD,5
# regenerates .SRCINFO and pushes to aur.archlinux.org (the first push creates6
# the AUR package). Uses AUR_GIT_AUTHOR_NAME / AUR_GIT_AUTHOR_EMAIL; the SSH7
# key comes from aur-ssh-setup.sh (AUR_SSH_PRIVATE_KEY_B64).8
set -euo pipefail9
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 WORKDIR19
trap 'rm -rf "$WORKDIR"' EXIT20
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"; then27
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
fi30
git -C "$dest" symbolic-ref HEAD refs/heads/master31
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}')/" PKGBUILD35
36
useradd -m aurbuild 2>/dev/null || true37
chmod 755 "$WORKDIR"; chown -R aurbuild "$dest"38
runuser -u aurbuild -- makepkg --printsrcinfo > "$WORKDIR/srcinfo"39
mv "$WORKDIR/srcinfo" .SRCINFO40
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 -A45
if git diff --cached --quiet; then echo "AUR $pkg already up to date ($ver)"; exit 0; fi46
git commit -qm "$ver"47
git push -u origin HEAD:master48
echo "AUR updated: $pkg $ver"@@ -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 bash1
#!/usr/bin/env bash2
# 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.go4
# Publishes the release for the tag that started this pipeline with5
# opPublishRelease, release_replace.go checkReplace, gitrepo.Tag):5
# POST $CI_API_URL/repos/{owner}/{repo}/releases/{tag}/assets — BlueGit's6
# there is no route that attaches artifacts to an existing git tag or an6
# create-only route for an existing tag: an existing release is HTTP 409, it7
# existing release. POST /api/v1/repos/{owner}/{repo}/releases always creates7
# never creates, moves or deletes the tag, and the assets are artifacts of8
# the annotated tag. An existing tag returns HTTP 409 unless replace=true,8
# successful jobs of this same pipeline. `replace` is never sent and the9
# 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 send12
# replace. It exits 3 until BlueGit grows an attach route. It does not13
# invent a second tag and it does not switch the pipeline onto a branch14
# release. The required server change is recorded in design.md section 15.15
set -euo pipefail10
set -euo pipefail16
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 pipefail19
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"14
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"20
cd "$root"15
cd "$root"21
version="$(bash scripts/ci/package-version.sh)"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" >&239
echo "Release $tag on $CI_COMMIT_SHA (existing tag, create-only)"24
echo "tag ${CI_COMMIT_TAG} version ${version} commit ${CI_COMMIT_SHA} project ${CI_PROJECT_PATH}" >&240
resp="$(mktemp)"25
echo "BlueGit has no request that publishes these package artifacts onto the tag that already started this pipeline." >&241
code="$(curl -sS -o "$resp" -w '%{http_code}' -X POST \26
echo "The create-release route would make a new annotated tag. This script does not call it." >&242
"$CI_API_URL/repos/$CI_PROJECT_PATH/releases/$tag/assets" \27
echo "The overwrite flag is not sent. No second tag is created." >&243
-H "Authorization: Bearer $CI_JOB_TOKEN" -H "Content-Type: application/json" -d "$body")" || code=00028
exit 344
cat "$resp"; echo45
if [[ "$code" != 2* ]]; then46
echo "release API returned HTTP $code (see response above)" >&247
exit 148
fi