Pulse/.github/workflows/update-demo-server.yml
2026-04-14 19:22:12 +01:00

164 lines
6.6 KiB
YAML

name: Update Demo Server
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: 'Release tag to deploy (e.g., v5.1.28)'
required: true
type: string
permissions:
contents: read
jobs:
update-demo:
# Only run for stable releases (not pre-releases) or manual dispatch
if: github.event_name == 'workflow_dispatch' || github.event.release.prerelease == false
runs-on: ubuntu-latest
steps:
- name: Resolve target tag
id: target
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
TAG="${{ inputs.tag }}"
else
TAG="${{ github.event.release.tag_name }}"
fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
- name: Skip if not latest published release
id: gate
if: github.event_name == 'release'
env:
GH_TOKEN: ${{ github.token }}
run: |
TARGET="${{ steps.target.outputs.tag }}"
LATEST=$(gh api "repos/${{ github.repository }}/releases?per_page=100" --jq 'map(select(.draft == false and .prerelease == false and (.tag_name | test("^v5\\.1\\.[0-9]+$"))))[0].tag_name')
echo "Target tag: $TARGET"
echo "Latest published v5.1 tag: $LATEST"
if [ "$TARGET" != "$LATEST" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "Release is not the latest v5.1 stable release; skipping demo update."
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Check release type
if: steps.gate.outputs.skip != 'true'
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "Manual deployment triggered for: ${{ inputs.tag }}"
else
echo "Release: ${{ github.event.release.tag_name }}"
echo "Prerelease: ${{ github.event.release.prerelease }}"
echo "Updating demo server to latest stable v5.1 release..."
fi
- name: Wait for release assets
if: steps.gate.outputs.skip != 'true'
run: |
TAG="${{ steps.target.outputs.tag }}"
echo "Waiting for release assets to be available..."
MAX_ATTEMPTS=30
ATTEMPT=0
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
echo "Checking for assets (attempt $((ATTEMPT + 1))/$MAX_ATTEMPTS)..."
# Check if checksums.txt and linux-amd64 tarball exist
CHECKSUMS_STATUS=$(curl -sL -o /dev/null -w "%{http_code}" \
"https://github.com/rcourtman/Pulse/releases/download/${TAG}/checksums.txt")
TARBALL_STATUS=$(curl -sL -o /dev/null -w "%{http_code}" \
"https://github.com/rcourtman/Pulse/releases/download/${TAG}/pulse-${TAG}-linux-amd64.tar.gz")
echo "checksums.txt: $CHECKSUMS_STATUS, tarball: $TARBALL_STATUS"
if [ "$CHECKSUMS_STATUS" = "200" ] && [ "$TARBALL_STATUS" = "200" ]; then
echo "✅ Release assets are available!"
exit 0
fi
ATTEMPT=$((ATTEMPT + 1))
if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then
echo "Assets not ready yet, waiting 10 seconds..."
sleep 10
fi
done
echo "❌ Timeout waiting for release assets"
exit 1
- name: Setup SSH
if: steps.gate.outputs.skip != 'true'
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEMO_SERVER_SSH_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H ${{ secrets.DEMO_SERVER_HOST }} >> ~/.ssh/known_hosts
- name: Check current demo version
if: steps.gate.outputs.skip != 'true'
id: current
run: |
TARGET="${{ steps.target.outputs.tag }}"
TARGET_STRIPPED="${TARGET#v}"
CURRENT=$(ssh -i ~/.ssh/id_ed25519 ${{ secrets.DEMO_SERVER_USER }}@${{ secrets.DEMO_SERVER_HOST }} \
"curl -s http://localhost:7655/api/version | jq -r .version")
echo "Current demo version: ${CURRENT}"
if [ "$CURRENT" = "$TARGET" ] || [ "$CURRENT" = "$TARGET_STRIPPED" ] || [ "v${CURRENT}" = "$TARGET" ]; then
echo "skip_current=true" >> "$GITHUB_OUTPUT"
echo "Demo server already on target version; skipping update."
else
echo "skip_current=false" >> "$GITHUB_OUTPUT"
fi
- name: Update demo server
if: steps.gate.outputs.skip != 'true' && steps.current.outputs.skip_current != 'true'
run: |
TAG="${{ steps.target.outputs.tag }}"
# Use set -o pipefail to ensure curl errors aren't masked by bash
ssh -i ~/.ssh/id_ed25519 ${{ secrets.DEMO_SERVER_USER }}@${{ secrets.DEMO_SERVER_HOST }} \
"set -o pipefail && curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/release/5.1/install.sh | sudo bash -s -- --version $TAG"
- name: Verify update
if: steps.gate.outputs.skip != 'true' && steps.current.outputs.skip_current != 'true'
run: |
# Wait a moment for service to restart
sleep 5
# Check version endpoint
VERSION=$(ssh -i ~/.ssh/id_ed25519 ${{ secrets.DEMO_SERVER_USER }}@${{ secrets.DEMO_SERVER_HOST }} \
"curl -s http://localhost:7655/api/version | jq -r .version")
echo "Demo server is now running version: $VERSION"
# Verify version matches target
TAG="${{ steps.target.outputs.tag }}"
TAG_STRIPPED="${TAG#v}"
if [ "$VERSION" != "$TAG" ] && [ "$VERSION" != "$TAG_STRIPPED" ]; then
echo "::error::Version mismatch! Expected $TAG but got $VERSION"
exit 1
fi
# Verify mock mode is active by authenticating and checking node count
# Uses $HOME for cookie file since /tmp may not be writable by all users
NODES=$(ssh -i ~/.ssh/id_ed25519 ${{ secrets.DEMO_SERVER_USER }}@${{ secrets.DEMO_SERVER_HOST }} \
'curl -s -c $HOME/.demo-cookies.txt http://localhost:7655/api/login -X POST -H "Content-Type: application/json" -d "{\"username\":\"demo\",\"password\":\"demo\"}" > /dev/null && curl -s -b $HOME/.demo-cookies.txt http://localhost:7655/api/state | jq -r ".nodes | length" && rm -f $HOME/.demo-cookies.txt')
echo "Mock nodes detected: $NODES"
if [ "$NODES" -ge 1 ]; then
echo "✅ Demo server successfully updated and verified!"
else
echo "⚠️ Demo server updated but mock mode may not be active"
exit 1
fi
- name: Cleanup SSH key
if: always() && steps.gate.outputs.skip != 'true'
run: rm -f ~/.ssh/id_ed25519