chore: sync deploy-dev.yml from Template-Go [skip ci]

This commit is contained in:
2026-07-14 21:12:43 +00:00
parent fb758f7227
commit 7fc04c8fb7
+136
View File
@@ -0,0 +1,136 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# BRIEF: Build and deploy to the Dev environment on push to the dev branch.
# Portable across Go server repos: ALL deployment config comes from repo
# Actions variables (vars.*) and secrets (secrets.*), nothing hardcoded.
# The dev branch is the ongoing integration branch.
# OWNER: Template-Go (canonical source; syncs to the root workflows dir). See Template-Go#3.
#
# Required repo VARIABLES (all tier-scoped so each environment is independent —
# a repo may host its rc/dev/prod tiers on different machines):
# DEV_SSH_HOST, DEV_SSH_PORT, DEV_SSH_USERNAME - SSH deploy target for the dev tier
# DEV_REGISTRY, DEV_REGISTRY_USER, DEV_IMAGE - container registry + login user + image
# DEV_CONTAINER - compose service/container to recreate
# DEV_COMPOSE_PROJECT - docker compose -p project name
# DEV_COMPOSE_DIR - dir containing docker-compose.yml on host
# DEV_SOURCE_DIR - build source checkout on host
# DEV_TAG_ENV - compose env-var name that pins the image tag
# DEV_HEALTH_URL - external URL to verify after deploy
# Required SECRETS (already configured org-wide; reused, not re-set):
# DEPLOY_SSH_KEY - deploy private key (repo/org secret)
# MOKOGIT_TOKEN - registry/API token (org secret)
name: Deploy (Dev)
on:
push:
branches:
- dev
# Manual trigger for isolated end-to-end tests.
# Runs on the ref it is dispatched from.
workflow_dispatch:
concurrency:
group: deploy-dev
cancel-in-progress: true
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
deploy-dev:
name: "Build & Deploy to Dev"
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine version
id: config
run: |
VERSION=$(git describe --tags --always 2>/dev/null || echo "dev-$(git rev-parse --short HEAD)")
echo "tag=${VERSION}-dev" >> $GITHUB_OUTPUT
echo "Version: ${VERSION}-dev"
- name: Write deploy key
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
run: |
mkdir -p ~/.ssh
echo "$DEPLOY_KEY" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
- name: Build and deploy to RC via SSH
env:
REGISTRY_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
TAG: ${{ steps.config.outputs.tag }}
run: |
# Runner-side values (TAG, REGISTRY_TOKEN) are injected into the remote shell
# via an env prefix; a *quoted* heredoc keeps every $var expanding once, on the
# remote. Repo variables (vars.*) are substituted inline by Actions before ssh.
ssh -i ~/.ssh/deploy_key -p ${{ vars.DEV_SSH_PORT }} \
-o ConnectTimeout=30 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
-o ServerAliveInterval=30 -o ServerAliveCountMax=10 \
${{ vars.DEV_SSH_USERNAME }}@${{ vars.DEV_SSH_HOST }} \
"TAG='$TAG' REGISTRY_TOKEN='$REGISTRY_TOKEN' bash -s" <<'DEPLOY_EOF'
set -e
echo 'SSH connected to Dev environment'
if [ -z "$TAG" ]; then
echo 'ERROR: TAG is empty; refusing to build an untagged image' >&2
exit 1
fi
HEALTH_FMT='{{.State.Health.Status}}'
echo 'Cleaning Docker build cache...'
docker builder prune -af 2>/dev/null || true
docker image prune -af 2>/dev/null || true
echo 'Pulling source...'
SOURCE_DIR='${{ vars.DEV_SOURCE_DIR }}'
if [ ! -d "$SOURCE_DIR/.git" ]; then
git clone -b dev https://x-access-token:${REGISTRY_TOKEN}@git.mokoconsulting.tech/${{ github.repository }}.git "$SOURCE_DIR"
fi
cd "$SOURCE_DIR"
git remote set-url origin https://x-access-token:${REGISTRY_TOKEN}@git.mokoconsulting.tech/${{ github.repository }}.git 2>/dev/null || true
git fetch origin dev
git reset --hard origin/dev
echo "Building image: ${{ vars.DEV_REGISTRY }}/${{ vars.DEV_IMAGE }}:$TAG"
docker build --no-cache --build-arg GOFLAGS='-p 1' \
--tag "${{ vars.DEV_REGISTRY }}/${{ vars.DEV_IMAGE }}:$TAG" \
-f Dockerfile .
echo 'Pushing to registry...'
echo "$REGISTRY_TOKEN" | docker login ${{ vars.DEV_REGISTRY }} -u ${{ vars.DEV_REGISTRY_USER }} --password-stdin
docker push "${{ vars.DEV_REGISTRY }}/${{ vars.DEV_IMAGE }}:$TAG"
echo 'Restarting Dev container...'
cd '${{ vars.DEV_COMPOSE_DIR }}'
# Drive the rc service image tag via its compose env-var (no sed on the shared
# file); remove any lingering fixed-name container first, then force-recreate.
docker rm -f '${{ vars.DEV_CONTAINER }}' 2>/dev/null || true
${{ vars.DEV_TAG_ENV }}="$TAG" docker compose -p '${{ vars.DEV_COMPOSE_PROJECT }}' up -d --force-recreate '${{ vars.DEV_CONTAINER }}'
echo 'Health check...'
for i in 1 2 3 4 5 6 7 8; do
sleep 15
if docker inspect --format="$HEALTH_FMT" '${{ vars.DEV_CONTAINER }}' 2>/dev/null | grep -q healthy; then
echo 'Dev container healthy!'
exit 0
fi
echo "Waiting... (attempt $i/8)"
done
echo 'Health check failed'
docker logs '${{ vars.DEV_CONTAINER }}' --tail 20
exit 1
DEPLOY_EOF
- name: Verify Dev instance
continue-on-error: true
run: |
sleep 5
ssh -i ~/.ssh/deploy_key -p ${{ vars.DEV_SSH_PORT }} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${{ vars.DEV_SSH_USERNAME }}@${{ vars.DEV_SSH_HOST }} "curl -sf '${{ vars.DEV_HEALTH_URL }}'" && echo " Dev API healthy"