Some checks failed
Release / Test backend (push) Successful in 46s
Release / Check ui (push) Successful in 1m38s
Release / Docker / caddy (push) Successful in 49s
Release / Docker / backend (push) Successful in 2m54s
Release / Docker / runner (push) Successful in 2m52s
Release / Upload source maps (push) Successful in 1m39s
Release / Docker / ui (push) Failing after 1m34s
Release / Gitea Release (push) Has been skipped
The docker-ui job was rebuilding the UI from scratch inside Docker, producing chunk hashes and JS files that didn't match the source maps uploaded to GlitchTip, causing all stack traces to appear minified. Fix: - ui/Dockerfile: add PREBUILT=1 ARG; skip npm run build when set - release.yaml upload-sourcemaps: re-upload artifact after sentry-cli inject - release.yaml docker-ui: download injected artifact into ui/build/ and pass PREBUILT=1 so Docker reuses the exact same JS files whose debug IDs are in GlitchTip
342 lines
11 KiB
YAML
342 lines
11 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- "v*" # e.g. v1.0.0, v1.2.3
|
|
|
|
concurrency:
|
|
group: ${{ gitea.workflow }}-${{ gitea.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
# ── backend: vet & test ───────────────────────────────────────────────────────
|
|
test-backend:
|
|
name: Test backend
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: actions/setup-go@v5
|
|
with:
|
|
go-version-file: backend/go.mod
|
|
cache-dependency-path: backend/go.sum
|
|
|
|
- name: go vet
|
|
working-directory: backend
|
|
run: go vet ./...
|
|
|
|
- name: Run tests
|
|
working-directory: backend
|
|
run: go test -short -race -count=1 -timeout=60s ./...
|
|
|
|
# ── ui: type-check & build ────────────────────────────────────────────────────
|
|
check-ui:
|
|
name: Check ui
|
|
runs-on: ubuntu-latest
|
|
defaults:
|
|
run:
|
|
working-directory: ui
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: "22"
|
|
cache: npm
|
|
cache-dependency-path: ui/package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Type check
|
|
run: npm run check
|
|
|
|
- name: Build
|
|
run: npm run build
|
|
|
|
- name: Upload build artifacts
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: ui-build
|
|
path: ui/build
|
|
retention-days: 1
|
|
|
|
# ── docker: backend ───────────────────────────────────────────────────────────
|
|
docker-backend:
|
|
name: Docker / backend
|
|
runs-on: ubuntu-latest
|
|
needs: [test-backend]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Docker Hub
|
|
uses: docker/login-action@v3
|
|
with:
|
|
username: ${{ secrets.DOCKER_USER }}
|
|
password: ${{ secrets.DOCKER_TOKEN }}
|
|
|
|
- name: Docker meta
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ${{ secrets.DOCKER_USER }}/libnovel-backend
|
|
tags: |
|
|
type=semver,pattern={{version}}
|
|
type=semver,pattern={{major}}.{{minor}}
|
|
type=raw,value=latest
|
|
|
|
- name: Build and push
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: backend
|
|
target: backend
|
|
push: true
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
build-args: |
|
|
VERSION=${{ steps.meta.outputs.version }}
|
|
COMMIT=${{ gitea.sha }}
|
|
cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-backend:latest
|
|
cache-to: type=inline
|
|
|
|
# ── docker: runner ────────────────────────────────────────────────────────────
|
|
docker-runner:
|
|
name: Docker / runner
|
|
runs-on: ubuntu-latest
|
|
needs: [test-backend]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Docker Hub
|
|
uses: docker/login-action@v3
|
|
with:
|
|
username: ${{ secrets.DOCKER_USER }}
|
|
password: ${{ secrets.DOCKER_TOKEN }}
|
|
|
|
- name: Docker meta
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ${{ secrets.DOCKER_USER }}/libnovel-runner
|
|
tags: |
|
|
type=semver,pattern={{version}}
|
|
type=semver,pattern={{major}}.{{minor}}
|
|
type=raw,value=latest
|
|
|
|
- name: Build and push
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: backend
|
|
target: runner
|
|
push: true
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
build-args: |
|
|
VERSION=${{ steps.meta.outputs.version }}
|
|
COMMIT=${{ gitea.sha }}
|
|
cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-runner:latest
|
|
cache-to: type=inline
|
|
|
|
# ── ui: source map upload ─────────────────────────────────────────────────────
|
|
upload-sourcemaps:
|
|
name: Upload source maps
|
|
runs-on: ubuntu-latest
|
|
needs: [check-ui]
|
|
steps:
|
|
- name: Compute release version (strip leading v)
|
|
id: ver
|
|
run: |
|
|
V="${{ gitea.ref_name }}"
|
|
echo "version=${V#v}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Download build artifacts
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: ui-build
|
|
path: build
|
|
|
|
- name: Install sentry-cli
|
|
run: npm install -g @sentry/cli
|
|
|
|
- name: Inject debug IDs into build artifacts
|
|
run: sentry-cli sourcemaps inject ./build
|
|
env:
|
|
SENTRY_URL: https://errors.libnovel.cc/
|
|
SENTRY_AUTH_TOKEN: ${{ secrets.GLITCHTIP_AUTH_TOKEN }}
|
|
SENTRY_ORG: libnovel
|
|
SENTRY_PROJECT: ui
|
|
|
|
- name: Upload injected build (for docker-ui)
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: ui-build-injected
|
|
path: build
|
|
retention-days: 1
|
|
|
|
- name: Create GlitchTip release
|
|
run: sentry-cli releases new ${{ steps.ver.outputs.version }}
|
|
env:
|
|
SENTRY_URL: https://errors.libnovel.cc/
|
|
SENTRY_AUTH_TOKEN: ${{ secrets.GLITCHTIP_AUTH_TOKEN }}
|
|
SENTRY_ORG: libnovel
|
|
SENTRY_PROJECT: ui
|
|
|
|
- name: Upload source maps to GlitchTip
|
|
run: sentry-cli sourcemaps upload ./build --release ${{ steps.ver.outputs.version }}
|
|
env:
|
|
SENTRY_URL: https://errors.libnovel.cc/
|
|
SENTRY_AUTH_TOKEN: ${{ secrets.GLITCHTIP_AUTH_TOKEN }}
|
|
SENTRY_ORG: libnovel
|
|
SENTRY_PROJECT: ui
|
|
|
|
- name: Finalize GlitchTip release
|
|
run: sentry-cli releases finalize ${{ steps.ver.outputs.version }}
|
|
env:
|
|
SENTRY_URL: https://errors.libnovel.cc/
|
|
SENTRY_AUTH_TOKEN: ${{ secrets.GLITCHTIP_AUTH_TOKEN }}
|
|
SENTRY_ORG: libnovel
|
|
SENTRY_PROJECT: ui
|
|
|
|
- name: Prune old GlitchTip releases (keep latest 10)
|
|
run: |
|
|
set -euo pipefail
|
|
KEEP=10
|
|
OLD=$(curl -sf \
|
|
-H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
|
|
"$SENTRY_URL/api/0/organizations/$SENTRY_ORG/releases/?project=$SENTRY_PROJECT&per_page=100" \
|
|
| python3 -c "
|
|
import sys, json
|
|
releases = json.load(sys.stdin)
|
|
for r in releases[$KEEP:]:
|
|
print(r['version'])
|
|
" KEEP=$KEEP)
|
|
for ver in $OLD; do
|
|
echo "Deleting old release: $ver"
|
|
sentry-cli releases delete "$ver" || true
|
|
done
|
|
env:
|
|
SENTRY_URL: https://errors.libnovel.cc
|
|
SENTRY_AUTH_TOKEN: ${{ secrets.GLITCHTIP_AUTH_TOKEN }}
|
|
SENTRY_ORG: libnovel
|
|
SENTRY_PROJECT: ui
|
|
|
|
# ── docker: ui ────────────────────────────────────────────────────────────────
|
|
docker-ui:
|
|
name: Docker / ui
|
|
runs-on: ubuntu-latest
|
|
needs: [check-ui, upload-sourcemaps]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Download injected build (debug IDs already embedded)
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: ui-build-injected
|
|
path: ui/build
|
|
|
|
- uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Docker Hub
|
|
uses: docker/login-action@v3
|
|
with:
|
|
username: ${{ secrets.DOCKER_USER }}
|
|
password: ${{ secrets.DOCKER_TOKEN }}
|
|
|
|
- name: Docker meta
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ${{ secrets.DOCKER_USER }}/libnovel-ui
|
|
tags: |
|
|
type=semver,pattern={{version}}
|
|
type=semver,pattern={{major}}.{{minor}}
|
|
type=raw,value=latest
|
|
|
|
- name: Build and push
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: ui
|
|
push: true
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
build-args: |
|
|
BUILD_VERSION=${{ steps.meta.outputs.version }}
|
|
BUILD_COMMIT=${{ gitea.sha }}
|
|
BUILD_TIME=${{ gitea.event.head_commit.timestamp }}
|
|
PREBUILT=1
|
|
cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-ui:latest
|
|
cache-to: type=inline
|
|
|
|
# ── docker: caddy ─────────────────────────────────────────────────────────────
|
|
docker-caddy:
|
|
name: Docker / caddy
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Docker Hub
|
|
uses: docker/login-action@v3
|
|
with:
|
|
username: ${{ secrets.DOCKER_USER }}
|
|
password: ${{ secrets.DOCKER_TOKEN }}
|
|
|
|
- name: Docker meta
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ${{ secrets.DOCKER_USER }}/libnovel-caddy
|
|
tags: |
|
|
type=semver,pattern={{version}}
|
|
type=semver,pattern={{major}}.{{minor}}
|
|
type=raw,value=latest
|
|
|
|
- name: Build and push
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: caddy
|
|
push: true
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-caddy:latest
|
|
cache-to: type=inline
|
|
|
|
# ── Gitea release ─────────────────────────────────────────────────────────────
|
|
release:
|
|
name: Gitea Release
|
|
runs-on: ubuntu-latest
|
|
needs: [docker-backend, docker-runner, docker-ui, docker-caddy, upload-sourcemaps]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Extract release notes from tag commit
|
|
id: notes
|
|
run: |
|
|
set -euo pipefail
|
|
# Subject line (first line of commit message) → release title
|
|
SUBJECT=$(git log -1 --format="%s" "${{ gitea.sha }}")
|
|
# Body (everything after the blank line) → release body
|
|
BODY=$(git log -1 --format="%b" "${{ gitea.sha }}" | sed '/^Co-Authored-By:/d' | sed '/^[[:space:]]*$/{ N; /^\n$/d }' | sed 's/^[[:space:]]*$//' | awk 'NF || !p; {p = !NF}')
|
|
echo "title=${SUBJECT}" >> "$GITHUB_OUTPUT"
|
|
# Use a heredoc delimiter to safely handle multi-line body
|
|
{
|
|
echo "body<<RELEASE_BODY_EOF"
|
|
echo "${BODY}"
|
|
echo "RELEASE_BODY_EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Create release
|
|
uses: https://gitea.com/actions/gitea-release-action@v1
|
|
with:
|
|
token: ${{ secrets.GITEA_TOKEN }}
|
|
title: ${{ steps.notes.outputs.title }}
|
|
body: ${{ steps.notes.outputs.body }}
|