.canopy/deploy-hub.ymlblame
View source
80fafdf1name: Deploy Hub
409bc792concurrency: 1
80fafdf3on:
80fafdf4 push:
80fafdf5 branches:
80fafdf6 - main
80fafdf7 paths:
36387cc8 - "web/**"
36387cc9 - "hub-api/**"
36387cc10 - "api/**"
6dd74de11 - "collab/mermaid/**"
e4f07b812 - "hub/Caddyfile"
c35d0b613 - "hub/docker-compose.yml"
36387cc14 - "docker/Dockerfile.grove-web"
36387cc15 - "docker/Dockerfile.grove-hub-api"
36387cc16 - "docker/Dockerfile.grove-api"
80fafdf17
80fafdf18steps:
6dd74de19 - name: Build mermaid
6dd74de20 image: node:22-alpine
6dd74de21 run: |
6dd74de22 cd collab/mermaid
6dd74de23 npm install -g pnpm
04a7f4324 pnpm install --frozen-lockfile --ignore-scripts
6dd74de25 pnpm build:mermaid
6dd74de26 cp -R packages/mermaid/dist ../../web/mermaid/dist
6dd74de27
80fafdf28 - name: Build web image
80fafdf29 image: docker:27-dind
80fafdf30 run: |
80fafdf31 docker build \
36387cc32 -f docker/Dockerfile.grove-web \
80fafdf33 --build-arg GROVE_HUB_API_URL=http://hub-api:4000 \
f0bb19234 --build-arg GROVE_API_URL=http://grove-api:4000 \
5f0fbcf35 -t $GROVE_REGISTRY/grove-web:latest \
36387cc36 .
5f0fbcf37 docker push $GROVE_REGISTRY/grove-web:latest
80fafdf38
80fafdf39 - name: Build hub-api image
80fafdf40 image: docker:27-dind
80fafdf41 run: |
80fafdf42 docker build \
36387cc43 -f docker/Dockerfile.grove-hub-api \
5f0fbcf44 -t $GROVE_REGISTRY/grove-hub-api:latest \
36387cc45 .
5f0fbcf46 docker push $GROVE_REGISTRY/grove-hub-api:latest
80fafdf47
5f0fbcf48 - name: Build api image
5f0fbcf49 image: docker:27-dind
5f0fbcf50 run: |
5f0fbcf51 docker build \
36387cc52 -f docker/Dockerfile.grove-api \
5f0fbcf53 -t $GROVE_REGISTRY/grove-api:latest \
36387cc54 .
5f0fbcf55 docker push $GROVE_REGISTRY/grove-api:latest
5f0fbcf56
5f0fbcf57 - name: Deploy
5f0fbcf58 image: docker:27-dind
80fafdf59 run: |
e69316360 REGISTRY=localhost:5000
e69316361 # Save current API image as :previous BEFORE pulling the new one
e69316362 docker tag $REGISTRY/grove-api:latest $REGISTRY/grove-api:previous 2>/dev/null || true
e69316363 docker push $REGISTRY/grove-api:previous 2>/dev/null || true
e69316364
c35d0b665 # Update docker-compose.yml and Caddyfile on host
c35d0b666 cat hub/docker-compose.yml | docker run --rm -i -v /opt/grove:/opt/grove alpine sh -c 'cat > /opt/grove/docker-compose.yml'
c35d0b667 cat hub/Caddyfile | docker run --rm -i -v /opt/grove:/opt/grove alpine sh -c 'cat > /opt/grove/Caddyfile'
c35d0b668
0b4b58269 docker compose -f /opt/grove/docker-compose.yml pull hub-api grove-web grove-api
0b4b58270 docker compose -f /opt/grove/docker-compose.yml up -d --no-deps hub-api grove-web
2e1766971 docker compose -f /opt/grove/docker-compose.yml exec -T caddy caddy reload --config /etc/caddy/Caddyfile
5f0fbcf72 docker image prune -f
7422c6573
7422c6574 - name: Restart API
7422c6575 image: docker:27-dind
7422c6576 run: |
fb964da77 # grove-api IS the Canopy runner — restarting it kills this pipeline.
fb964da78 # We fire-and-forget a detached container that does a health-checked
fb964da79 # restart with automatic rollback on failure.
7422c6580 docker run -d --rm \
7422c6581 -v /var/run/docker.sock:/var/run/docker.sock \
7422c6582 -v /opt/grove:/opt/grove:ro \
7422c6583 --network host \
7422c6584 docker:27-dind \
fb964da85 sh -c '
fb964da86 COMPOSE="docker compose -f /opt/grove/docker-compose.yml"
fb964da87 REGISTRY=localhost:5000
fb964da88 IMAGE=$REGISTRY/grove-api
e69316389 CONTAINER=grove-grove-api-1
fb964da90
e69316391 # 1. Restart with new image
fb964da92 sleep 5
fb964da93 $COMPOSE up -d grove-api
fb964da94
e69316395 # 2. Health check — poll for 30s using docker exec
fb964da96 ok=false
fb964da97 for i in $(seq 1 15); do
fb964da98 sleep 2
e69316399 if docker exec $CONTAINER wget -qO- http://127.0.0.1:4000/health 2>/dev/null; then
fb964da100 ok=true
fb964da101 break
fb964da102 fi
fb964da103 done
fb964da104
fb964da105 if $ok; then
fb964da106 echo "API healthy after restart"
fb964da107 else
fb964da108 echo "API unhealthy — rolling back to previous image"
fb964da109 docker tag $IMAGE:previous $IMAGE:latest
fb964da110 docker push $IMAGE:latest
e693163111 $COMPOSE pull grove-api
fb964da112 $COMPOSE up -d grove-api
fb964da113
fb964da114 # Wait for rollback to come up
fb964da115 for i in $(seq 1 10); do
fb964da116 sleep 2
e693163117 if docker exec $CONTAINER wget -qO- http://127.0.0.1:4000/health 2>/dev/null; then
fb964da118 echo "Rollback successful"
fb964da119 break
fb964da120 fi
fb964da121 done
fb964da122 fi
fb964da123 '