name: Deploy Claude Dev (Dev) on: push: branches: [dev] paths: - 'claude-dev/**' - '.gitea/workflows/deploy-claude-dev-dev.yml' workflow_dispatch: inputs: rollback_image: 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 container: volumes: - /var/packages/ContainerManager/target/usr/bin/docker:/usr/bin/docker - /volume1/docker/claude-dev:/claude-dev-runtime steps: - 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: | set -euo pipefail if [ -n "${{ inputs.rollback_image }}" ]; then image_ref="${{ inputs.rollback_image }}" image_tag="${image_ref#claude-dev:}" if [ "$image_ref" = "$image_tag" ]; then echo "rollback_image must be in claude-dev: format" >&2 exit 1 fi echo "ROLLBACK_ONLY=1" >> "$GITHUB_ENV" else short_sha="$(git rev-parse --short=12 HEAD)" date_tag="$(date +%Y%m%d%H%M%S)" image_tag="dev-${date_tag}-${short_sha}" image_ref="claude-dev:${image_tag}" echo "ROLLBACK_ONLY=0" >> "$GITHUB_ENV" fi echo "CLAUDE_DEV_IMAGE_TAG=${image_tag}" >> "$GITHUB_ENV" echo "CLAUDE_DEV_IMAGE=${image_ref}" >> "$GITHUB_ENV" - name: Build claude-dev image if: env.ROLLBACK_ONLY == '0' run: | set -euo pipefail DOCKER_BUILDKIT=0 docker build \ --cache-from claude-dev:latest \ -t "$CLAUDE_DEV_IMAGE" \ -t claude-dev:latest \ claude-dev/ - name: Smoke test required tools if: env.ROLLBACK_ONLY == '0' run: | set -euo pipefail docker run --rm "$CLAUDE_DEV_IMAGE" bash /opt/claude-dev/scripts/smoke-tools.sh - name: Smoke test network assumptions if: env.ROLLBACK_ONLY == '0' run: | set -euo pipefail docker run --rm --network host "$CLAUDE_DEV_IMAGE" bash /opt/claude-dev/scripts/smoke-network.sh - name: Smoke test auth and mount expectations if: env.ROLLBACK_ONLY == '0' run: | set -euo pipefail docker run --rm --network host \ -e REQUIRE_MOUNTS=1 \ -v /volume1/docker/claude-dev/claude-config:/root/.claude \ -v /volume1/docker/claude-dev/claude-config/.claude.json:/root/.claude.json \ -v /volume1/docker/claude-dev/gitea_token:/root/.gitea_token:ro \ "$CLAUDE_DEV_IMAGE" \ bash /opt/claude-dev/scripts/smoke-auth.sh - 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 echo "Saved previous image: $previous_image" else echo "No existing claude-dev container found" fi - name: Sync compose and target tag run: | set -euo pipefail 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 CLAUDE_DEV_IMAGE_TAG="$CLAUDE_DEV_IMAGE_TAG" docker compose -f /claude-dev-runtime/docker-compose.yml up -d --pull never - name: Post-deploy runtime checks run: | set -euo pipefail docker exec claude-dev bash -lc 'claude --version' docker exec claude-dev bash -lc 'gh --version' docker exec claude-dev bash -lc 'gh auth status || true'