From ce061c19772a2052a0dff8728a853ab043d62f19 Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Tue, 3 Mar 2026 00:28:02 +0800 Subject: [PATCH 1/9] fix: scope deploy triggers and cancel stale workflow runs Limit workflow path triggers to each workflow file, add concurrency groups to cancel outdated runs, and checkout the exact triggering SHA for deterministic deploys. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/deploy-claude-dev-dev.yml | 13 +++++++++++-- .gitea/workflows/deploy-dev.yml | 15 ++++++++++++--- .gitea/workflows/deploy.yml | 15 ++++++++++++--- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/.gitea/workflows/deploy-claude-dev-dev.yml b/.gitea/workflows/deploy-claude-dev-dev.yml index 6756c50..36f56b7 100644 --- a/.gitea/workflows/deploy-claude-dev-dev.yml +++ b/.gitea/workflows/deploy-claude-dev-dev.yml @@ -11,6 +11,10 @@ on: description: 'Optional full image ref (for rollback), e.g. claude-dev:dev-abc123' required: false +concurrency: + group: deploy-claude-dev-dev + cancel-in-progress: true + jobs: deploy-claude-dev-dev: runs-on: ubuntu-latest @@ -19,8 +23,13 @@ jobs: - /var/packages/ContainerManager/target/usr/bin/docker:/usr/bin/docker - /volume1/docker/claude-dev:/claude-dev-runtime steps: - - name: Checkout dev branch - run: git clone --depth 1 --branch dev http://gitea:3000/jimmy/nas-tools.git . + - name: Checkout exact commit + run: | + set -euo pipefail + git init . + git remote add origin http://gitea:3000/jimmy/nas-tools.git + git fetch --depth 1 origin "$GITHUB_SHA" + git checkout --detach FETCH_HEAD - name: Resolve image tags run: | diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 49e83b7..50ed66f 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -4,7 +4,11 @@ on: branches: [dev] paths: - 'dashboard/**' - - '.gitea/workflows/**' + - '.gitea/workflows/deploy-dev.yml' + +concurrency: + group: deploy-dashboard-dev + cancel-in-progress: true jobs: deploy-dev: @@ -14,8 +18,13 @@ jobs: - /var/packages/ContainerManager/target/usr/bin/docker:/usr/bin/docker - /volume1/docker/nas-dashboard:/nas-dashboard steps: - - name: Checkout dev branch - run: git clone --depth 1 --branch dev http://gitea:3000/jimmy/nas-tools.git . + - name: Checkout exact commit + run: | + set -euo pipefail + git init . + git remote add origin http://gitea:3000/jimmy/nas-tools.git + git fetch --depth 1 origin "$GITHUB_SHA" + git checkout --detach FETCH_HEAD - name: Build dev image run: DOCKER_BUILDKIT=0 docker build --cache-from nas-dashboard-dev:latest -t nas-dashboard-dev:latest dashboard/ - name: Deploy dev diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 1d5abd9..4f5906d 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -4,7 +4,11 @@ on: branches: [main] paths: - 'dashboard/**' - - '.gitea/workflows/**' + - '.gitea/workflows/deploy.yml' + +concurrency: + group: deploy-dashboard-main + cancel-in-progress: true jobs: deploy: @@ -14,8 +18,13 @@ jobs: - /var/packages/ContainerManager/target/usr/bin/docker:/usr/bin/docker - /volume1/docker/nas-dashboard:/nas-dashboard steps: - - name: Checkout - run: git clone --depth 1 http://gitea:3000/jimmy/nas-tools.git . + - name: Checkout exact commit + run: | + set -euo pipefail + git init . + git remote add origin http://gitea:3000/jimmy/nas-tools.git + git fetch --depth 1 origin "$GITHUB_SHA" + git checkout --detach FETCH_HEAD - name: Build run: DOCKER_BUILDKIT=0 docker build -t nas-dashboard:latest dashboard/ - name: Deploy -- 2.52.0 From 19001edfbd331cef9beb804129fd92d095b959b4 Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Tue, 3 Mar 2026 00:56:02 +0800 Subject: [PATCH 2/9] fix: speed up claude-dev base image availability Switch claude-dev to node:20-bookworm-slim and preload the base image from server2 in CI to avoid slow pulls on the NAS runner. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/deploy-claude-dev-dev.yml | 6 ++++++ claude-dev/Dockerfile | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/deploy-claude-dev-dev.yml b/.gitea/workflows/deploy-claude-dev-dev.yml index 36f56b7..cc32cbc 100644 --- a/.gitea/workflows/deploy-claude-dev-dev.yml +++ b/.gitea/workflows/deploy-claude-dev-dev.yml @@ -52,6 +52,12 @@ jobs: echo "CLAUDE_DEV_IMAGE_TAG=${image_tag}" >> "$GITHUB_ENV" echo "CLAUDE_DEV_IMAGE=${image_ref}" >> "$GITHUB_ENV" + - name: Preload base image from server2 + if: env.ROLLBACK_ONLY == '0' + run: | + set -euo pipefail + ssh -o StrictHostKeyChecking=accept-new server2 "podman pull docker.io/library/node:20-bookworm-slim >/dev/null && podman save docker.io/library/node:20-bookworm-slim" | docker load + - name: Build claude-dev image if: env.ROLLBACK_ONLY == '0' run: | diff --git a/claude-dev/Dockerfile b/claude-dev/Dockerfile index d281067..5eeecab 100644 --- a/claude-dev/Dockerfile +++ b/claude-dev/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20-bookworm +FROM node:20-bookworm-slim ENV DEBIAN_FRONTEND=noninteractive -- 2.52.0 From 88c378594edcedf2826e96e52462c9ea22aadb4a Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Tue, 3 Mar 2026 00:59:00 +0800 Subject: [PATCH 3/9] fix: use explicit server2 SSH target in claude-dev preload Replace the runner-only host alias with an explicit SSH user@host so the preload step can resolve and stream the base image tar reliably. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/deploy-claude-dev-dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/deploy-claude-dev-dev.yml b/.gitea/workflows/deploy-claude-dev-dev.yml index cc32cbc..f1e792d 100644 --- a/.gitea/workflows/deploy-claude-dev-dev.yml +++ b/.gitea/workflows/deploy-claude-dev-dev.yml @@ -56,7 +56,7 @@ jobs: if: env.ROLLBACK_ONLY == '0' run: | set -euo pipefail - ssh -o StrictHostKeyChecking=accept-new server2 "podman pull docker.io/library/node:20-bookworm-slim >/dev/null && podman save docker.io/library/node:20-bookworm-slim" | docker load + ssh -o StrictHostKeyChecking=accept-new jimmyg@158.101.140.85 "podman pull docker.io/library/node:20-bookworm-slim >/dev/null && podman save docker.io/library/node:20-bookworm-slim" | docker load - name: Build claude-dev image if: env.ROLLBACK_ONLY == '0' -- 2.52.0 From 8c23aabd97262d2fb1d1524bfb6941d0078e8eac Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Tue, 3 Mar 2026 01:02:06 +0800 Subject: [PATCH 4/9] fix: make claude-dev preload non-blocking in CI Treat server2 preload as best-effort so missing SSH keys do not fail deployment; fall back to normal registry pull during image build. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/deploy-claude-dev-dev.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/deploy-claude-dev-dev.yml b/.gitea/workflows/deploy-claude-dev-dev.yml index f1e792d..f083fe8 100644 --- a/.gitea/workflows/deploy-claude-dev-dev.yml +++ b/.gitea/workflows/deploy-claude-dev-dev.yml @@ -56,7 +56,11 @@ jobs: if: env.ROLLBACK_ONLY == '0' run: | set -euo pipefail - ssh -o StrictHostKeyChecking=accept-new jimmyg@158.101.140.85 "podman pull docker.io/library/node:20-bookworm-slim >/dev/null && podman save docker.io/library/node:20-bookworm-slim" | docker load + if ssh -o StrictHostKeyChecking=accept-new jimmyg@158.101.140.85 "podman pull docker.io/library/node:20-bookworm-slim >/dev/null && podman save docker.io/library/node:20-bookworm-slim" | docker load; then + echo "Preloaded node:20-bookworm-slim from server2" + else + echo "Preload from server2 failed; continuing with registry pull during docker build" + fi - name: Build claude-dev image if: env.ROLLBACK_ONLY == '0' -- 2.52.0 From d7b2cb3885951aa0f7e87bb95104309568bf0bca Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Tue, 3 Mar 2026 01:22:24 +0800 Subject: [PATCH 5/9] fix: mount SSH key for server2 preload in runner job Mount a read-only SSH key into the claude-dev deploy runner container and use it explicitly for server2 preload so the fast-path image transfer can authenticate. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/deploy-claude-dev-dev.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/deploy-claude-dev-dev.yml b/.gitea/workflows/deploy-claude-dev-dev.yml index f083fe8..c518716 100644 --- a/.gitea/workflows/deploy-claude-dev-dev.yml +++ b/.gitea/workflows/deploy-claude-dev-dev.yml @@ -22,6 +22,7 @@ jobs: volumes: - /var/packages/ContainerManager/target/usr/bin/docker:/usr/bin/docker - /volume1/docker/claude-dev:/claude-dev-runtime + - /volume1/docker/nas-dashboard/ssh/vps_terminal:/runner-ssh/server2_key:ro steps: - name: Checkout exact commit run: | @@ -56,7 +57,8 @@ jobs: if: env.ROLLBACK_ONLY == '0' run: | set -euo pipefail - if ssh -o StrictHostKeyChecking=accept-new jimmyg@158.101.140.85 "podman pull docker.io/library/node:20-bookworm-slim >/dev/null && podman save docker.io/library/node:20-bookworm-slim" | docker load; then + chmod 600 /runner-ssh/server2_key + if ssh -i /runner-ssh/server2_key -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new jimmyg@158.101.140.85 "podman pull docker.io/library/node:20-bookworm-slim >/dev/null && podman save docker.io/library/node:20-bookworm-slim" | docker load; then echo "Preloaded node:20-bookworm-slim from server2" else echo "Preload from server2 failed; continuing with registry pull during docker build" -- 2.52.0 From a683321d92b87ce8092b83ca8b45719531ed469b Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Tue, 3 Mar 2026 01:30:01 +0800 Subject: [PATCH 6/9] fix: remove chmod on read-only mounted preload key Drop chmod on the read-only mounted server2 SSH key so preload can execute without failing the workflow before the SSH attempt. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/deploy-claude-dev-dev.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitea/workflows/deploy-claude-dev-dev.yml b/.gitea/workflows/deploy-claude-dev-dev.yml index c518716..9618dcc 100644 --- a/.gitea/workflows/deploy-claude-dev-dev.yml +++ b/.gitea/workflows/deploy-claude-dev-dev.yml @@ -57,7 +57,6 @@ jobs: if: env.ROLLBACK_ONLY == '0' run: | set -euo pipefail - chmod 600 /runner-ssh/server2_key if ssh -i /runner-ssh/server2_key -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new jimmyg@158.101.140.85 "podman pull docker.io/library/node:20-bookworm-slim >/dev/null && podman save docker.io/library/node:20-bookworm-slim" | docker load; then echo "Preloaded node:20-bookworm-slim from server2" else -- 2.52.0 From cb2a842ab619673dc8ee2dacd06c41dbc99d3952 Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Tue, 3 Mar 2026 01:42:30 +0800 Subject: [PATCH 7/9] fix: remove slow server2 preload from claude-dev deploy workflow Drop the server2 preload stage and rely on direct docker build pulls to avoid long-running preload stream stalls in CI. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/deploy-claude-dev-dev.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.gitea/workflows/deploy-claude-dev-dev.yml b/.gitea/workflows/deploy-claude-dev-dev.yml index 9618dcc..36f56b7 100644 --- a/.gitea/workflows/deploy-claude-dev-dev.yml +++ b/.gitea/workflows/deploy-claude-dev-dev.yml @@ -22,7 +22,6 @@ jobs: volumes: - /var/packages/ContainerManager/target/usr/bin/docker:/usr/bin/docker - /volume1/docker/claude-dev:/claude-dev-runtime - - /volume1/docker/nas-dashboard/ssh/vps_terminal:/runner-ssh/server2_key:ro steps: - name: Checkout exact commit run: | @@ -53,16 +52,6 @@ jobs: echo "CLAUDE_DEV_IMAGE_TAG=${image_tag}" >> "$GITHUB_ENV" echo "CLAUDE_DEV_IMAGE=${image_ref}" >> "$GITHUB_ENV" - - name: Preload base image from server2 - if: env.ROLLBACK_ONLY == '0' - run: | - set -euo pipefail - if ssh -i /runner-ssh/server2_key -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new jimmyg@158.101.140.85 "podman pull docker.io/library/node:20-bookworm-slim >/dev/null && podman save docker.io/library/node:20-bookworm-slim" | docker load; then - echo "Preloaded node:20-bookworm-slim from server2" - else - echo "Preload from server2 failed; continuing with registry pull during docker build" - fi - - name: Build claude-dev image if: env.ROLLBACK_ONLY == '0' run: | -- 2.52.0 From b384b2f462124c00aa7c64f1b46ffaa18cdd1962 Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Tue, 3 Mar 2026 02:05:52 +0800 Subject: [PATCH 8/9] fix: ensure claude-dev runtime directory exists before snapshot Create /claude-dev-runtime before writing previous-image.txt so post-build record step does not fail when the bind path is absent. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/deploy-claude-dev-dev.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitea/workflows/deploy-claude-dev-dev.yml b/.gitea/workflows/deploy-claude-dev-dev.yml index 36f56b7..6602437 100644 --- a/.gitea/workflows/deploy-claude-dev-dev.yml +++ b/.gitea/workflows/deploy-claude-dev-dev.yml @@ -89,6 +89,7 @@ jobs: - name: Record previous image run: | set -euo pipefail + mkdir -p /claude-dev-runtime previous_image="$(docker inspect -f '{{.Config.Image}}' claude-dev 2>/dev/null || true)" if [ -n "$previous_image" ]; then printf '%s\n' "$previous_image" > /claude-dev-runtime/previous-image.txt -- 2.52.0 From c49d34210dff694a37cf599b850d21741966f3d0 Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Tue, 3 Mar 2026 02:11:52 +0800 Subject: [PATCH 9/9] fix: remove stale claude-dev container before deploy Delete any existing claude-dev container before compose up so name conflicts do not block CI deployment. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/deploy-claude-dev-dev.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitea/workflows/deploy-claude-dev-dev.yml b/.gitea/workflows/deploy-claude-dev-dev.yml index 6602437..b179de7 100644 --- a/.gitea/workflows/deploy-claude-dev-dev.yml +++ b/.gitea/workflows/deploy-claude-dev-dev.yml @@ -104,6 +104,9 @@ jobs: cp claude-dev/docker-compose.yml /claude-dev-runtime/docker-compose.yml printf '%s\n' "$CLAUDE_DEV_IMAGE_TAG" > /claude-dev-runtime/target-tag.txt + - name: Remove stale claude-dev container + run: docker rm -f claude-dev || true + - name: Deploy claude-dev run: | set -euo pipefail -- 2.52.0