From c7b66e08205a252d82abc4d255428fed2ac429bc Mon Sep 17 00:00:00 2001 From: Shaun Arman Date: Sun, 29 Mar 2026 13:28:49 -0500 Subject: [PATCH] ci: migrate pipelines to Woodpecker 2.x + Gitea MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert pipeline: map format → steps: list format (Woodpecker 2.x) - Add per-step labels for agent routing (platform: linux/amd64 / arm64) - Add native build-linux-arm64 step (routes to local arm64 agent) - Arm64 step self-clones via host IP (isolated workspace per agent) - Arm64 step uploads artifacts inline to Gitea API - Replace gogs_app → gitea_app in all clone/upload URLs - Remove Woodpecker 0.15.4 per-step platform routing workaround note - Update wiki: Gitea migration notes, new pipeline format docs, agent labels Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .woodpecker/release.yml | 84 +++++++++--- .woodpecker/test.yml | 14 +- docs/wiki/CICD-Pipeline.md | 253 +++++++++++++++---------------------- 3 files changed, 176 insertions(+), 175 deletions(-) diff --git a/.woodpecker/release.yml b/.woodpecker/release.yml index 28a01eff..20ee3953 100644 --- a/.woodpecker/release.yml +++ b/.woodpecker/release.yml @@ -1,9 +1,11 @@ --- # Release pipeline — triggered on v* tags # Agents: -# linux/amd64 → woodpecker_agent (native x86_64 on 172.0.0.29) -# linux/arm64 → woodpecker-agent.service on sarman's local arm64 machine (native) -# macOS requires a separate Mac runner — not covered here. +# linux/amd64 → woodpecker_agent (native x86_64 on 172.0.0.29, gogs_default network) +# linux/arm64 → woodpecker-agent.service on sarman's local arm64 machine (direct IP access) +# +# Note: amd64 steps share a workspace (same agent). The arm64 step runs on a separate +# agent with its own workspace and clones the repo directly via host IP. clone: git: @@ -11,17 +13,19 @@ clone: network_mode: gogs_default commands: - git init -b master - - git remote add origin http://gogs_app:3000/sarman/tftsr-devops_investigation.git + - git remote add origin http://gitea_app:3000/sarman/tftsr-devops_investigation.git - git fetch --depth=1 origin +refs/tags/${CI_COMMIT_TAG}:refs/tags/${CI_COMMIT_TAG} - git checkout ${CI_COMMIT_TAG} -pipeline: - build-linux-amd64: +steps: + - name: build-linux-amd64 image: rust:1.88-slim + labels: + platform: linux/amd64 environment: TARGET: x86_64-unknown-linux-gnu when: - event: tag + - event: tag commands: - apt-get update -qq && apt-get install -y -qq libwebkit2gtk-4.1-dev libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev patchelf pkg-config curl perl - curl -fsSL https://deb.nodesource.com/setup_22.x | bash - @@ -33,8 +37,10 @@ pipeline: - mkdir -p artifacts/linux-amd64 - find src-tauri/target/$TARGET/release/bundle -name "*.deb" -o -name "*.rpm" -o -name "*.AppImage" | xargs -I{} cp {} artifacts/linux-amd64/ - build-windows-amd64: + - name: build-windows-amd64 image: rust:1.88-slim + labels: + platform: linux/amd64 environment: TARGET: x86_64-pc-windows-gnu CC_x86_64_pc_windows_gnu: x86_64-w64-mingw32-gcc @@ -42,7 +48,7 @@ pipeline: AR_x86_64_pc_windows_gnu: x86_64-w64-mingw32-ar CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER: x86_64-w64-mingw32-gcc when: - event: tag + - event: tag commands: - apt-get update -qq && apt-get install -y -qq mingw-w64 curl nsis perl make - curl -fsSL https://deb.nodesource.com/setup_22.x | bash - @@ -54,23 +60,65 @@ pipeline: - mkdir -p artifacts/windows-amd64 - find src-tauri/target/$TARGET/release/bundle -name "*.exe" -o -name "*.msi" | xargs -I{} cp {} artifacts/windows-amd64/ 2>/dev/null || true - # NOTE: linux/arm64 is built locally via 'make release-arm64 GOGS_TOKEN=' - # Woodpecker 0.15.4 does not support per-step agent platform routing — - # when: platform: is evaluated at compile time (server=amd64) and drops the step. + - name: build-linux-arm64 + image: rust:1.88-slim + labels: + platform: linux/arm64 + environment: + TARGET: aarch64-unknown-linux-gnu + when: + - event: tag + secrets: [GOGS_TOKEN] + commands: + - apt-get update -qq && apt-get install -y -qq libwebkit2gtk-4.1-dev libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev patchelf pkg-config curl perl git + - curl -fsSL https://deb.nodesource.com/setup_22.x | bash - + - apt-get install -y nodejs + # Clone repo directly (arm64 agent is on local machine, not on gogs_default network) + - git init -b master + - git remote add origin http://172.0.0.29:3000/sarman/tftsr-devops_investigation.git + - git fetch --depth=1 origin +refs/tags/${CI_COMMIT_TAG}:refs/tags/${CI_COMMIT_TAG} + - git checkout ${CI_COMMIT_TAG} + - npm ci --legacy-peer-deps + - rustup target add $TARGET + - cargo install tauri-cli --version "^2" --locked + - CI=true cargo tauri build --target $TARGET + - mkdir -p artifacts/linux-arm64 + - find src-tauri/target/$TARGET/release/bundle -name "*.deb" -o -name "*.rpm" -o -name "*.AppImage" | xargs -I{} cp {} artifacts/linux-arm64/ + # Upload arm64 artifacts inline (uses host IP, accessible from local arm64 machine) + - | + TAG=${CI_COMMIT_TAG} + REPO=${CI_REPO} + API="http://172.0.0.29:3000/api/v1" + curl -sf -X POST "$API/repos/$REPO/releases" \ + -H "Authorization: token $GOGS_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"tag_name\":\"$TAG\",\"name\":\"TFTSR $TAG\",\"body\":\"Release $TAG\",\"draft\":false}" || true + RELEASE_ID=$(curl -sf "$API/repos/$REPO/releases/tags/$TAG" \ + -H "Authorization: token $GOGS_TOKEN" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2) + echo "Release ID: $RELEASE_ID" + for f in artifacts/linux-arm64/*; do + [ -f "$f" ] || continue + echo "Uploading $f..." + curl -sf -X POST "$API/repos/$REPO/releases/$RELEASE_ID/assets" \ + -H "Authorization: token $GOGS_TOKEN" \ + -F "attachment=@$f;filename=$(basename $f)" && echo "OK" || echo "Upload failed: $f" + done - upload-release: + - name: upload-release image: curlimages/curl:latest + labels: + platform: linux/amd64 network_mode: gogs_default when: - event: tag + - event: tag secrets: [GOGS_TOKEN] commands: - | TAG=${CI_COMMIT_TAG} REPO=${CI_REPO} - API="http://gogs_app:3000/api/v1" + API="http://gitea_app:3000/api/v1" - # Create release + # Create release (idempotent — arm64 step may have already created it) curl -sf -X POST "$API/repos/$REPO/releases" \ -H "Authorization: token $GOGS_TOKEN" \ -H "Content-Type: application/json" \ @@ -81,8 +129,8 @@ pipeline: -H "Authorization: token $GOGS_TOKEN" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2) echo "Release ID: $RELEASE_ID" - # Upload all available artifacts - for dir in artifacts/linux-amd64 artifacts/linux-arm64 artifacts/windows-amd64; do + # Upload linux-amd64 and windows-amd64 artifacts + for dir in artifacts/linux-amd64 artifacts/windows-amd64; do [ -d "$dir" ] || continue for f in "$dir"/*; do [ -f "$f" ] || continue diff --git a/.woodpecker/test.yml b/.woodpecker/test.yml index fb2dd924..3b9856a0 100644 --- a/.woodpecker/test.yml +++ b/.woodpecker/test.yml @@ -4,35 +4,35 @@ clone: image: woodpeckerci/plugin-git network_mode: gogs_default environment: - - CI_REPO_CLONE_URL=http://gogs_app:3000/sarman/tftsr-devops_investigation.git + - CI_REPO_CLONE_URL=http://gitea_app:3000/sarman/tftsr-devops_investigation.git -pipeline: - rust-fmt-check: +steps: + - name: rust-fmt-check image: rust:1.88-slim commands: - rustup component add rustfmt - cargo fmt --manifest-path src-tauri/Cargo.toml --check - rust-clippy: + - name: rust-clippy image: rust:1.88-slim commands: - apt-get update -qq && apt-get install -y -qq libwebkit2gtk-4.1-dev libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev patchelf pkg-config perl - rustup component add clippy - cargo clippy --manifest-path src-tauri/Cargo.toml -- -D warnings - rust-tests: + - name: rust-tests image: rust:1.88-slim commands: - apt-get update -qq && apt-get install -y -qq libwebkit2gtk-4.1-dev libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev patchelf pkg-config perl - cargo test --manifest-path src-tauri/Cargo.toml - frontend-typecheck: + - name: frontend-typecheck image: node:22-alpine commands: - npm ci --legacy-peer-deps - npx tsc --noEmit - frontend-tests: + - name: frontend-tests image: node:22-alpine commands: - npm ci --legacy-peer-deps diff --git a/docs/wiki/CICD-Pipeline.md b/docs/wiki/CICD-Pipeline.md index 6802e48a..c5bae857 100644 --- a/docs/wiki/CICD-Pipeline.md +++ b/docs/wiki/CICD-Pipeline.md @@ -4,10 +4,10 @@ | Component | URL | Notes | |-----------|-----|-------| -| Gogs | `https://gogs.tftsr.com` / `http://172.0.0.29:3000` | Git server, version 0.14 | -| Woodpecker CI (direct) | `http://172.0.0.29:8084` | v0.15.4 | -| Woodpecker CI (proxy) | `http://172.0.0.29:8085` | nginx with custom login page | -| PostgreSQL (Gogs DB) | Container: `gogs_postgres_db` | DB: `gogsdb`, User: `gogs` | +| Gitea | `https://gogs.tftsr.com` / `http://172.0.0.29:3000` | Git server (migrated from Gogs 0.14) | +| Woodpecker CI (direct) | `http://172.0.0.29:8084` | v2.x | +| Woodpecker CI (proxy) | `http://172.0.0.29:8085` | nginx reverse proxy | +| PostgreSQL (Gitea DB) | Container: `gogs_postgres_db` | DB: `gogsdb`, User: `gogs` | ### CI Agents @@ -17,6 +17,10 @@ | `woodpecker-agent` (systemd) | `linux/arm64` | sarman's local machine | Native aarch64 — arm64 release builds | | `woodpecker_agent_arm64` (Docker) | `linux/arm64` | 172.0.0.29 | QEMU fallback — kept as backup | +Agent labels configured via `WOODPECKER_LABELS`: +- Docker agents: `WOODPECKER_LABELS=platform=linux/amd64` (or arm64) +- Local systemd agent: `~/.config/woodpecker-agent/config.env` → `WOODPECKER_LABELS=platform=linux/arm64` + --- ## Test Pipeline (`.woodpecker/test.yml`) @@ -36,23 +40,24 @@ Pipeline steps: - `rust:1.88-slim` — Rust steps (minimum for cookie_store + time + darling) - `node:22-alpine` — Frontend steps -**Pipeline YAML format (Woodpecker 0.15.4 — legacy MAP format):** +**Pipeline YAML format (Woodpecker 2.x — steps list format):** ```yaml clone: git: image: woodpeckerci/plugin-git network_mode: gogs_default # requires repo_trusted=1 environment: - - CI_REPO_CLONE_URL=http://gogs_app:3000/sarman/tftsr-devops_investigation.git + - CI_REPO_CLONE_URL=http://gitea_app:3000/sarman/tftsr-devops_investigation.git -pipeline: - step-name: # KEY = step name (MAP, not list!) +steps: + - name: step-name # LIST format (- name:) image: rust:1.88-slim commands: - cargo test ``` -> ⚠️ **Do NOT** use the newer `steps:` list format — Woodpecker 0.15.4 uses the Drone-legacy map format. Using `steps:` causes "Invalid or missing pipeline section" error. +> ⚠️ Woodpecker 2.x uses the `steps:` list format. The legacy `pipeline:` map format from +> Woodpecker 0.15.4 is no longer supported. --- @@ -60,23 +65,40 @@ pipeline: **Triggers:** Git tags matching `v*` -**Active config path:** Woodpecker DB must have `repo_config_path = .woodpecker/release.yml` when the tag is pushed. Switch back to `test.yml` after tagging to restore PR/push CI. - ``` Pipeline steps: - 1. clone → alpine/git with explicit tag fetch + checkout - 2. build-linux-amd64 → cargo tauri build (x86_64-unknown-linux-gnu) - → artifacts/linux-amd64/{.deb, .rpm, .AppImage} - 3. build-windows-amd64 → cargo tauri build (x86_64-pc-windows-gnu) - → artifacts/windows-amd64/{.exe, .msi} - 4. upload-release → Create Gogs release + upload all artifacts - -linux/arm64 (manual): make release-arm64 GOGS_TOKEN= (see below) + 1. clone (amd64 workspace) → alpine/git with explicit tag fetch + checkout + 2. build-linux-amd64 → cargo tauri build (x86_64-unknown-linux-gnu) + → artifacts/linux-amd64/{.deb, .rpm, .AppImage} + 3. build-windows-amd64 → cargo tauri build (x86_64-pc-windows-gnu) + → artifacts/windows-amd64/{.exe, .msi} + 4. build-linux-arm64 → cargo tauri build (aarch64-unknown-linux-gnu) + → artifacts/linux-arm64/{.deb, .rpm, .AppImage} + → uploads arm64 artifacts inline to Gitea release + 5. upload-release → Create Gitea release + upload amd64 + windows artifacts ``` -**Clone override (release.yml):** +**Per-step agent routing (Woodpecker 2.x labels):** -Release builds use `alpine/git` with explicit commands because `woodpeckerci/plugin-git:latest` uses `git switch` which fails on tag refs: +```yaml +steps: + - name: build-linux-amd64 + labels: + platform: linux/amd64 # → woodpecker_agent on 172.0.0.29 + + - name: build-linux-arm64 + labels: + platform: linux/arm64 # → woodpecker-agent.service on local arm64 machine +``` + +**Multi-agent workspace isolation:** + +Steps routed to different agents do **not** share a workspace. The arm64 step clones +the repo directly within its commands (using `http://172.0.0.29:3000`, accessible from +the local machine) and uploads its artifacts inline. The `upload-release` step (amd64) +handles amd64 + windows artifacts only. + +**Clone override (release.yml — amd64 workspace):** ```yaml clone: @@ -85,7 +107,7 @@ clone: network_mode: gogs_default commands: - git init -b master - - git remote add origin http://gogs_app:3000/sarman/tftsr-devops_investigation.git + - git remote add origin http://gitea_app:3000/sarman/tftsr-devops_investigation.git - git fetch --depth=1 origin +refs/tags/${CI_COMMIT_TAG}:refs/tags/${CI_COMMIT_TAG} - git checkout ${CI_COMMIT_TAG} ``` @@ -101,130 +123,69 @@ environment: **Artifacts per platform:** - Linux amd64: `.deb`, `.rpm`, `.AppImage` - Windows amd64: `.exe` (NSIS installer), `.msi` -- Linux arm64: `.deb`, `.rpm`, `.AppImage` — built via `make release-arm64` (see below) +- Linux arm64: `.deb`, `.rpm`, `.AppImage` -**Linux arm64 build (Woodpecker 0.15.4 workaround):** - -Woodpecker 0.15.4 evaluates `when: platform:` at compile time against the server's -platform (amd64), dropping arm64 steps before any agent can claim them. Per-step -agent routing is a Woodpecker 2.x feature. - -To build and upload arm64 artifacts from the local aarch64 machine: -```bash -# On the local arm64 machine (Fedora Asahi 42) -cd ~/Documents/tftsr-devops_investigation -make release-arm64 TAG=v0.1.0-alpha GOGS_TOKEN= -``` - -`make build-arm64` runs the full Tauri build inside a `rust:1.88-slim` ARM64 Docker -container. `make upload-arm64` uploads the resulting artifacts to the Gogs release. - -**Important:** Artifacts must be written to the **workspace** (relative paths like `artifacts/linux-amd64/`), not to absolute paths like `/artifacts/`. Only the workspace is shared between pipeline steps via Docker volume. - -**Upload step (requires gogs_default network):** +**Upload step (requires gogs_default network for amd64, host IP for arm64):** ```yaml +# amd64 upload step upload-release: image: curlimages/curl:latest - network_mode: gogs_default # host firewall blocks default bridge from reaching Gogs API + labels: + platform: linux/amd64 + network_mode: gogs_default secrets: [GOGS_TOKEN] ``` -The `GOGS_TOKEN` Woodpecker secret is inserted into the DB: -```python -conn.execute(""" - INSERT INTO secrets (secret_repo_id, secret_name, secret_value, secret_images, secret_events, secret_skip_verify, secret_conceal) - VALUES (1, 'GOGS_TOKEN', '', '', 'tag', 0, 1) -""") -``` +The `GOGS_TOKEN` Woodpecker secret must be created via the Woodpecker UI or API after +migration. The secret name stays `GOGS_TOKEN` for pipeline compatibility. -**Gogs Release API:** +**Gitea Release API (replaces Gogs API — same endpoints, different container name):** ```bash # Create release -POST http://gogs_app:3000/api/v1/repos/sarman/tftsr-devops_investigation/releases +POST http://gitea_app:3000/api/v1/repos/sarman/tftsr-devops_investigation/releases Authorization: token $GOGS_TOKEN # Upload artifact -POST http://gogs_app:3000/api/v1/repos/sarman/tftsr-devops_investigation/releases/{id}/assets +POST http://gitea_app:3000/api/v1/repos/sarman/tftsr-devops_investigation/releases/{id}/assets ``` +From the arm64 agent (local machine), use `http://172.0.0.29:3000/api/v1` instead. + --- -## Switching Between Test and Release Config +## Multi-File Pipeline Support (Woodpecker 2.x) -Woodpecker 0.15.4 supports only **one config file per repo**. The workflow: +Woodpecker 2.x supports multiple pipeline files in the `.woodpecker/` directory. +All `.yml` files are evaluated on every trigger; `when:` conditions control which +pipelines actually run. -```bash -# For regular pushes/PRs — use test pipeline -python3 -c "conn.execute(\"UPDATE repos SET repo_config_path='.woodpecker/test.yml'\")" +Current files: +- `.woodpecker/test.yml` — runs on every push/PR +- `.woodpecker/release.yml` — runs on `v*` tags only -# Before pushing a release tag — switch to release pipeline -python3 -c "conn.execute(\"UPDATE repos SET repo_config_path='.woodpecker/release.yml'\")" -git tag -a v1.0.0 -m "Release v1.0.0" -git push origin v1.0.0 -# → Switch back to test.yml after build starts -``` +No DB config path switching needed (unlike Woodpecker 0.15.4). --- ## Webhook Configuration -**Hook ID:** 9 (in Gogs, `http://gogs.tftsr.com`) -**Events:** `create`, `push`, `pull_request` -**URL:** `http://172.0.0.29:8084/hook?access_token=` +**Woodpecker 2.x with Gitea OAuth2:** -**JWT signing:** -- Algorithm: HS256 -- Secret: `repo_hash` from Woodpecker DB (`dK8zFWtAu67qfKd3Et6N8LptqTmedumJ`) -- Payload: `{"text":"sarman/tftsr-devops_investigation","type":"hook","iat":}` +After migration, Woodpecker 2.x registers webhooks automatically when a repo is +activated via the UI. No manual JWT-signed webhook setup required. -**Regenerate JWT when stale:** -```python -import base64, hmac, hashlib, json, time - -def b64url(data): - if isinstance(data, str): data = data.encode() - return base64.urlsafe_b64encode(data).rstrip(b'=').decode() - -header = b64url(json.dumps({'alg':'HS256','typ':'JWT'}, separators=(',',':'))) -payload = b64url(json.dumps({'text':'sarman/tftsr-devops_investigation','type':'hook','iat':int(time.time())}, separators=(',',':'))) -msg = f'{header}.{payload}' -sig = hmac.new(b'dK8zFWtAu67qfKd3Et6N8LptqTmedumJ', msg.encode(), hashlib.sha256).digest() -print(f'{msg}.{b64url(sig)}') -``` - -Then update the webhook in Gogs via API: -```bash -curl -X DELETE http://172.0.0.29:3000/api/v1/repos/sarman/tftsr-devops_investigation/hooks/ -curl -X POST http://172.0.0.29:3000/api/v1/repos/sarman/tftsr-devops_investigation/hooks \ - -H "Authorization: token " \ - -H "Content-Type: application/json" \ - -d '{"type":"gogs","config":{"url":"http://172.0.0.29:8084/hook?access_token=","content_type":"json","secret":"af5dc60e0984f2680d0969f4a087e7100a4ece7e"},"events":["push","pull_request","create"],"active":true}' -``` - ---- - -## Woodpecker DB State - -SQLite at `/docker_mounts/woodpecker/data/woodpecker.sqlite` (on host `172.0.0.29`). - -```sql --- Verify config -SELECT user_token IS NOT NULL AND user_token != '' AS token_set FROM users WHERE user_login='sarman'; - -SELECT repo_active, repo_trusted, repo_config_path, repo_hash -FROM repos WHERE repo_full_name='sarman/tftsr-devops_investigation'; --- repo_active=1, repo_trusted=1 --- repo_config_path='.woodpecker/test.yml' (or release.yml during release) --- repo_hash='dK8zFWtAu67qfKd3Et6N8LptqTmedumJ' -``` +1. Log in at `http://172.0.0.29:8085` via Gitea OAuth2 +2. Add repo `sarman/tftsr-devops_investigation` +3. Woodpecker creates webhook in Gitea automatically --- ## Branch Protection -Master branch is protected: all changes require a PR. Direct pushes are blocked. +Master branch is protected: all changes require a PR. ```sql +-- Gitea branch protection (via psql on gogs_postgres_db container) -- Check protection SELECT name, protected, require_pull_request FROM protect_branch WHERE repo_id=42; @@ -234,71 +195,63 @@ UPDATE protect_branch SET protected=false WHERE repo_id=42 AND name='master'; UPDATE protect_branch SET protected=true, require_pull_request=true WHERE repo_id=42 AND name='master'; ``` -> Gogs 0.14 does **not** enforce required CI status checks before merging. Only `require_pull_request=true` is supported. - --- ## Known Issues & Fixes -### Webhook JWT Must Use `?access_token=` -`token.ParseRequest()` in Woodpecker 0.15.4 does **not** read `?token=` URL params. Use `?access_token=` instead. - -### Directory-Based Config Not Supported -Woodpecker 0.15.4 only supports a **single config file**. Multi-file pipelines require v2.x+. - -### Empty Clone URL in Push Events -Woodpecker 0.15.4's `go-gogs-client` `PayloadRepo` struct lacks `CloneURL`, so `build_remote` is always empty. Fix: set `CI_REPO_CLONE_URL` in the clone step environment. - -### Step Containers Cannot Reach `gogs_app` -Default Docker bridge containers cannot resolve `gogs_app` or reach `172.0.0.29:3000` (host firewall). Fix: use `network_mode: gogs_default` in any step that needs Gogs access. Requires `repo_trusted=1`. +### Step Containers Cannot Reach `gitea_app` +Default Docker bridge containers cannot resolve `gitea_app` or reach `172.0.0.29:3000` +(host firewall). Fix: use `network_mode: gogs_default` in any step that needs Gitea +access. Requires `repo_trusted=1`. ### `CI=woodpecker` Rejected by Tauri CLI -Woodpecker sets `CI=woodpecker`; `cargo tauri build` expects a boolean. Fix: prefix with `CI=true cargo tauri build`. +Woodpecker sets `CI=woodpecker`; `cargo tauri build` expects a boolean. Fix: prefix with +`CI=true cargo tauri build`. ### Agent Stalls After Server Restart -After restarting the Woodpecker server, the agent may enter a loop cleaning up orphaned containers and stop picking up new builds. Fix: +After restarting the Woodpecker server, the agent may enter a loop cleaning up orphaned +containers and stop picking up new builds. Fix: ```bash -# Kill orphan containers and volumes docker rm -f $(docker ps -aq --filter 'name=0_') docker volume rm $(docker volume ls -q | grep '0_') -# Restart agent docker restart woodpecker_agent ``` -### Per-Step Agent Platform Routing Not Supported -Woodpecker 0.15.4 evaluates `when: platform:` conditions at pipeline compile time -against the **server's** platform (amd64). Steps filtered by platform are dropped -before any agent can claim them, so arm64 steps never reach the arm64 agent. - -The `platform:` step-level key (e.g. `platform: linux/arm64`) is treated as a plugin -attribute and causes `Cannot configure both commands and custom attributes [platform]`. - -Workaround: build arm64 artifacts locally via `make release-arm64`. This is fixed in -Woodpecker 2.x which supports proper per-step label-based agent routing. - ### Windows DLL Export Ordinal Too Large `/usr/bin/x86_64-w64-mingw32-ld: error: export ordinal too large: 106290` -MinGW's `ld` auto-exports ALL public Rust symbols into the DLL export table. With a -large dependency tree (~106k symbols), this exceeds the 65,535 PE ordinal limit. - -Fix: `src-tauri/.cargo/config.toml` tells `ld` to suppress auto-export: +Fix: `src-tauri/.cargo/config.toml`: ```toml [target.x86_64-pc-windows-gnu] rustflags = ["-C", "link-arg=-Wl,--exclude-all-symbols"] ``` -The desktop `main.exe` links against `rlib` (static), so the cdylib export table is -unused at runtime. An empty export table is valid for a DLL. -### Gogs OAuth2 Limitation -Gogs 0.14 has no OAuth2 provider support, blocking upgrade to Woodpecker 2.x. +### GOGS_TOKEN Secret Must Be Recreated After Migration +After migrating from Woodpecker 0.15.4 to 2.x, recreate the `GOGS_TOKEN` secret: +1. Log in to Gitea, create a new API token under Settings → Applications +2. In Woodpecker UI → Repository → Secrets, add secret `GOGS_TOKEN` with the token value --- -## Gogs PostgreSQL Access +## Gitea PostgreSQL Access ```bash docker exec gogs_postgres_db psql -U gogs -d gogsdb -c "SELECT id, lower_name FROM repository;" ``` -> Database name is `gogsdb`, not `gogs`. +> Database name is `gogsdb` (unchanged from Gogs migration). + +--- + +## Migration Notes (Gogs 0.14 → Gitea) + +Gitea auto-migrates the Gogs PostgreSQL schema on first start. Users, repos, teams, and +issues are preserved. API tokens stored in the DB are also migrated but should be +regenerated for security. + +Key changes after migration: +- Container name: `gogs_app` → `gitea_app` +- Config dir: `/data/gitea` (was `/data/gogs` inside container, same host volume) +- Repo dir: `gogs-repositories` → `gitea-repositories` (renamed on host during migration) +- OAuth2 provider: Gitea now supports OAuth2 (Woodpecker 2.x uses this for login) +- Woodpecker 2.x multi-file pipeline support enabled (no more single config file limitation)