ci: adopt standard go deploy workflows (deploy-dev/prod) #783
@@ -1,25 +1,40 @@
|
||||
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# BRIEF: Build and deploy MokoGitea to dev environment on push to dev branch.
|
||||
# Production deploy (deploy-mokogitea.yml) only succeeds if dev is healthy.
|
||||
# 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)
|
||||
# MOKOGITEA_TOKEN - registry/API token (org secret)
|
||||
|
||||
name: Deploy MokoGitea (Dev)
|
||||
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-mokogitea-dev
|
||||
group: deploy-dev
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REGISTRY: git.mokoconsulting.tech
|
||||
IMAGE: mokoconsulting/mokogitea
|
||||
DEPLOY_HOST: git.mokoconsulting.tech
|
||||
DEPLOY_PORT: 2918
|
||||
DEPLOY_USER: mokoconsulting
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||
|
||||
jobs:
|
||||
@@ -47,22 +62,21 @@ jobs:
|
||||
echo "$DEPLOY_KEY" > ~/.ssh/deploy_key
|
||||
chmod 600 ~/.ssh/deploy_key
|
||||
|
||||
- name: Build and deploy to dev via SSH
|
||||
- name: Build and deploy to RC via SSH
|
||||
env:
|
||||
REGISTRY_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||
TAG: ${{ steps.config.outputs.tag }}
|
||||
run: |
|
||||
# Inject runner-side values (TAG, REGISTRY_TOKEN) into the remote shell's
|
||||
# environment via a command prefix, then use a *quoted* heredoc so every
|
||||
# $var below expands in exactly one place: the remote dev host. This avoids
|
||||
# the local-vs-remote expansion trap that previously left TAG empty.
|
||||
ssh -i ~/.ssh/deploy_key -p ${{ env.DEPLOY_PORT }} \
|
||||
# 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 \
|
||||
${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} \
|
||||
${{ 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'
|
||||
echo 'SSH connected to Dev environment'
|
||||
|
||||
if [ -z "$TAG" ]; then
|
||||
echo 'ERROR: TAG is empty; refusing to build an untagged image' >&2
|
||||
@@ -76,52 +90,46 @@ jobs:
|
||||
docker image prune -af 2>/dev/null || true
|
||||
|
||||
echo 'Pulling source...'
|
||||
SOURCE_DIR=/opt/gitea-dev/source
|
||||
SOURCE_DIR='${{ vars.DEV_SOURCE_DIR }}'
|
||||
if [ ! -d "$SOURCE_DIR/.git" ]; then
|
||||
git clone -b dev https://git.mokoconsulting.tech/MokoConsulting/MokoGitea-Fork.git "$SOURCE_DIR"
|
||||
git clone -b dev ${{ github.server_url }}/${{ github.repository }}.git "$SOURCE_DIR"
|
||||
fi
|
||||
cd "$SOURCE_DIR"
|
||||
git remote set-url origin https://git.mokoconsulting.tech/MokoConsulting/MokoGitea-Fork.git 2>/dev/null || true
|
||||
git remote set-url origin ${{ github.server_url }}/${{ github.repository }}.git 2>/dev/null || true
|
||||
git fetch origin dev
|
||||
git reset --hard origin/dev
|
||||
|
||||
echo "Building Docker image: ${{ env.REGISTRY }}/${{ env.IMAGE }}:$TAG"
|
||||
echo "Building image: ${{ vars.DEV_REGISTRY }}/${{ vars.DEV_IMAGE }}:$TAG"
|
||||
docker build --no-cache --build-arg GOFLAGS='-p 1' \
|
||||
--tag "${{ env.REGISTRY }}/${{ env.IMAGE }}:$TAG" \
|
||||
--tag "${{ vars.DEV_REGISTRY }}/${{ vars.DEV_IMAGE }}:$TAG" \
|
||||
-f Dockerfile .
|
||||
|
||||
echo 'Pushing to registry...'
|
||||
echo "$REGISTRY_TOKEN" | docker login ${{ env.REGISTRY }} -u ${{ env.DEPLOY_USER }} --password-stdin
|
||||
docker push "${{ env.REGISTRY }}/${{ env.IMAGE }}:$TAG"
|
||||
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 /opt/gitea-dev
|
||||
# The dev service in the SHARED compose file reads its image tag from
|
||||
# ${MOKOGITEA_DEV_TAG}. Drive it from the freshly built tag instead of
|
||||
# rewriting the file with sed: the old sed pattern matched the *prod*
|
||||
# service line (container_name: mokogitea) and left the dev service pinned
|
||||
# to a stale image, so every dev deploy recreated old code while silently
|
||||
# corrupting the prod image pin. The env-var only affects the dev service.
|
||||
# Remove any lingering fixed-name container first so the recreate can't hit
|
||||
# a name conflict, pin the project name for determinism, then force-recreate.
|
||||
docker rm -f mokogitea-dev 2>/dev/null || true
|
||||
MOKOGITEA_DEV_TAG="$TAG" docker compose -p gitea-dev up -d --force-recreate mokogitea-dev
|
||||
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" mokogitea-dev 2>/dev/null | grep -q healthy; then
|
||||
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 mokogitea-dev --tail 20
|
||||
docker logs '${{ vars.DEV_CONTAINER }}' --tail 20
|
||||
exit 1
|
||||
DEPLOY_EOF
|
||||
|
||||
- name: Verify dev instance
|
||||
- name: Verify Dev instance
|
||||
run: |
|
||||
sleep 5
|
||||
curl -sf https://git.dev.mokoconsulting.tech/api/healthz && echo " Dev API healthy"
|
||||
curl -sf "${{ vars.DEV_HEALTH_URL }}" && echo " Dev API healthy"
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# BRIEF: Build MokoGitea Docker image, push to registry, and deploy
|
||||
|
||||
name: Deploy MokoGitea
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version tag'
|
||||
required: true
|
||||
default: 'latest'
|
||||
environment:
|
||||
description: 'Target environment'
|
||||
required: true
|
||||
default: 'dev'
|
||||
type: choice
|
||||
options:
|
||||
- dev
|
||||
- production
|
||||
|
||||
concurrency:
|
||||
group: deploy-mokogitea
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
REGISTRY: git.mokoconsulting.tech
|
||||
IMAGE: mokoconsulting/mokogitea
|
||||
DEPLOY_HOST: git.mokoconsulting.tech
|
||||
DEPLOY_PORT: 2918
|
||||
DEPLOY_USER: mokoconsulting
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# NOTE: removed a "Verify dev environment is healthy" gate that curled
|
||||
# git.dev and `exit 1` on failure — gating a PROD deploy on a live DEV
|
||||
# health check is a cross-tier false-negative (a transient dev blip blocked
|
||||
# prod). Pre-prod validation is the dev -> rc -> main pipeline + RC env.
|
||||
- name: Checkout source (for version detection)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Determine settings
|
||||
id: config
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "push" ]; then
|
||||
VERSION=$(git describe --tags --always 2>/dev/null || echo "dev-$(git rev-parse --short HEAD)")
|
||||
ENV="production"
|
||||
else
|
||||
VERSION="${{ github.event.inputs.version }}"
|
||||
ENV="${{ github.event.inputs.environment }}"
|
||||
fi
|
||||
if [ "$ENV" = "production" ]; then
|
||||
echo "compose_dir=/opt/gitea-dev" >> $GITHUB_OUTPUT
|
||||
echo "container=mokogitea" >> $GITHUB_OUTPUT
|
||||
echo "source_dir=/opt/gitea/source" >> $GITHUB_OUTPUT
|
||||
echo "branch=main" >> $GITHUB_OUTPUT
|
||||
echo "tag=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "tag_env=MOKOGITEA_TAG" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "compose_dir=/opt/gitea-dev" >> $GITHUB_OUTPUT
|
||||
echo "container=mokogitea-dev" >> $GITHUB_OUTPUT
|
||||
echo "source_dir=/opt/gitea-dev/source" >> $GITHUB_OUTPUT
|
||||
echo "branch=dev" >> $GITHUB_OUTPUT
|
||||
echo "tag=$VERSION-dev" >> $GITHUB_OUTPUT
|
||||
echo "tag_env=MOKOGITEA_DEV_TAG" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- 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 via SSH
|
||||
env:
|
||||
REGISTRY_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||
TAG: ${{ steps.config.outputs.tag }}
|
||||
BRANCH: ${{ steps.config.outputs.branch }}
|
||||
SOURCE_DIR: ${{ steps.config.outputs.source_dir }}
|
||||
COMPOSE_DIR: ${{ steps.config.outputs.compose_dir }}
|
||||
CONTAINER: ${{ steps.config.outputs.container }}
|
||||
TAG_ENV: ${{ steps.config.outputs.tag_env }}
|
||||
run: |
|
||||
HEALTH_FMT='${{ '{{' }}.State.Health.Status${{ '}}' }}'
|
||||
IMAGE_FMT='Image: ${{ '{{' }}.Config.Image${{ '}}' }}'
|
||||
|
||||
ssh -i ~/.ssh/deploy_key -p ${{ env.DEPLOY_PORT }} \
|
||||
-o ConnectTimeout=30 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
||||
-o ServerAliveInterval=30 -o ServerAliveCountMax=10 \
|
||||
${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} bash -s <<DEPLOY_EOF
|
||||
set -e
|
||||
echo 'SSH connected'
|
||||
|
||||
echo 'Cleaning Docker build cache...'
|
||||
docker builder prune -af 2>/dev/null || true
|
||||
docker image prune -af 2>/dev/null || true
|
||||
free -m | head -3
|
||||
|
||||
echo 'Pulling source...'
|
||||
if [ ! -d $SOURCE_DIR/.git ]; then
|
||||
git clone -b $BRANCH https://git.mokoconsulting.tech/MokoConsulting/MokoGitea-Fork.git $SOURCE_DIR
|
||||
fi
|
||||
cd $SOURCE_DIR
|
||||
# Ensure remote points to MokoGitea-Fork (not the upstream fork)
|
||||
git remote set-url origin https://git.mokoconsulting.tech/MokoConsulting/MokoGitea-Fork.git 2>/dev/null || true
|
||||
git fetch origin $BRANCH
|
||||
git reset --hard origin/$BRANCH
|
||||
|
||||
echo 'Building Docker image...'
|
||||
docker build --no-cache --build-arg GOFLAGS='-p 1' \
|
||||
--tag ${{ env.REGISTRY }}/${{ env.IMAGE }}:$TAG \
|
||||
--tag ${{ env.REGISTRY }}/${{ env.IMAGE }}:latest \
|
||||
-f Dockerfile .
|
||||
|
||||
echo 'Pushing to registry...'
|
||||
echo '$REGISTRY_TOKEN' | docker login ${{ env.REGISTRY }} -u ${{ env.DEPLOY_USER }} --password-stdin
|
||||
docker push ${{ env.REGISTRY }}/${{ env.IMAGE }}:$TAG
|
||||
docker push ${{ env.REGISTRY }}/${{ env.IMAGE }}:latest
|
||||
|
||||
echo 'Restarting container...'
|
||||
cd $COMPOSE_DIR
|
||||
# Drive ONLY the target service's tag via its compose env-var (no sed —
|
||||
# a blanket 'sed s|mokogitea:...|' clobbered the dev + rc service tags too).
|
||||
# Remove any lingering fixed-name container first (avoids the "name already
|
||||
# in use" conflict), then force-recreate under the shared compose project.
|
||||
docker rm -f $CONTAINER 2>/dev/null || true
|
||||
env $TAG_ENV="$TAG" docker compose -p gitea-dev up -d --force-recreate $CONTAINER
|
||||
|
||||
echo 'Health check...'
|
||||
for i in 1 2 3 4 5 6 7 8; do
|
||||
sleep 15
|
||||
if docker inspect --format='$HEALTH_FMT' $CONTAINER 2>/dev/null | grep -q healthy; then
|
||||
echo 'Container healthy!'
|
||||
docker inspect --format='$IMAGE_FMT' $CONTAINER
|
||||
exit 0
|
||||
fi
|
||||
echo "Waiting... (attempt \$i/8)"
|
||||
done
|
||||
echo 'Health check failed'
|
||||
docker logs $CONTAINER --tail 20
|
||||
exit 1
|
||||
DEPLOY_EOF
|
||||
|
||||
- name: Verify
|
||||
run: |
|
||||
sleep 5
|
||||
curl -sf https://${{ env.DEPLOY_HOST }}/api/healthz && echo " API healthy"
|
||||
|
||||
- name: Notify on failure
|
||||
if: failure()
|
||||
run: echo "::error::Deploy failed for ${{ steps.config.outputs.tag }}"
|
||||
@@ -0,0 +1,135 @@
|
||||
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# BRIEF: Build and deploy to the Prod environment on push to the main branch.
|
||||
# Portable across Go server repos: ALL deployment config comes from repo
|
||||
# Actions variables (vars.*) and secrets (secrets.*), nothing hardcoded.
|
||||
# Prod deploys on merge to main (dev -> rc -> main pipeline).
|
||||
# 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):
|
||||
# PROD_SSH_HOST, PROD_SSH_PORT, PROD_SSH_USERNAME - SSH deploy target for the prod tier
|
||||
# PROD_REGISTRY, PROD_REGISTRY_USER, PROD_IMAGE - container registry + login user + image
|
||||
# PROD_CONTAINER - compose service/container to recreate
|
||||
# PROD_COMPOSE_PROJECT - docker compose -p project name
|
||||
# PROD_COMPOSE_DIR - dir containing docker-compose.yml on host
|
||||
# PROD_SOURCE_DIR - build source checkout on host
|
||||
# PROD_TAG_ENV - compose env-var name that pins the image tag
|
||||
# PROD_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)
|
||||
# MOKOGITEA_TOKEN - registry/API token (org secret)
|
||||
|
||||
name: Deploy (Prod)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
# Manual trigger for a prod re-deploy.
|
||||
# Runs on the ref it is dispatched from (use main).
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: deploy-prod
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||
|
||||
jobs:
|
||||
deploy-prod:
|
||||
name: "Build & Deploy to Prod"
|
||||
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 "$(git rev-parse --short HEAD)")
|
||||
echo "tag=${VERSION}" >> $GITHUB_OUTPUT
|
||||
echo "Version: ${VERSION}"
|
||||
|
||||
- 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.MOKOGITEA_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.PROD_SSH_PORT }} \
|
||||
-o ConnectTimeout=30 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
||||
-o ServerAliveInterval=30 -o ServerAliveCountMax=10 \
|
||||
${{ vars.PROD_SSH_USERNAME }}@${{ vars.PROD_SSH_HOST }} \
|
||||
"TAG='$TAG' REGISTRY_TOKEN='$REGISTRY_TOKEN' bash -s" <<'DEPLOY_EOF'
|
||||
set -e
|
||||
echo 'SSH connected to Prod 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.PROD_SOURCE_DIR }}'
|
||||
if [ ! -d "$SOURCE_DIR/.git" ]; then
|
||||
git clone -b main ${{ github.server_url }}/${{ github.repository }}.git "$SOURCE_DIR"
|
||||
fi
|
||||
cd "$SOURCE_DIR"
|
||||
git remote set-url origin ${{ github.server_url }}/${{ github.repository }}.git 2>/dev/null || true
|
||||
git fetch origin main
|
||||
git reset --hard origin/main
|
||||
|
||||
echo "Building image: ${{ vars.PROD_REGISTRY }}/${{ vars.PROD_IMAGE }}:$TAG"
|
||||
docker build --no-cache --build-arg GOFLAGS='-p 1' \
|
||||
--tag "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_IMAGE }}:$TAG" \
|
||||
-f Dockerfile .
|
||||
|
||||
echo 'Pushing to registry...'
|
||||
echo "$REGISTRY_TOKEN" | docker login ${{ vars.PROD_REGISTRY }} -u ${{ vars.PROD_REGISTRY_USER }} --password-stdin
|
||||
docker push "${{ vars.PROD_REGISTRY }}/${{ vars.PROD_IMAGE }}:$TAG"
|
||||
|
||||
echo 'Restarting Prod container...'
|
||||
cd '${{ vars.PROD_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.PROD_CONTAINER }}' 2>/dev/null || true
|
||||
${{ vars.PROD_TAG_ENV }}="$TAG" docker compose -p '${{ vars.PROD_COMPOSE_PROJECT }}' up -d --force-recreate '${{ vars.PROD_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.PROD_CONTAINER }}' 2>/dev/null | grep -q healthy; then
|
||||
echo 'Prod container healthy!'
|
||||
exit 0
|
||||
fi
|
||||
echo "Waiting... (attempt $i/8)"
|
||||
done
|
||||
echo 'Health check failed'
|
||||
docker logs '${{ vars.PROD_CONTAINER }}' --tail 20
|
||||
exit 1
|
||||
DEPLOY_EOF
|
||||
|
||||
- name: Verify Prod instance
|
||||
run: |
|
||||
sleep 5
|
||||
curl -sf "${{ vars.PROD_HEALTH_URL }}" && echo " Prod API healthy"
|
||||
Reference in New Issue
Block a user