Skip to content

Commit b8283cb

Browse files
committed
Added release workflow
1 parent 2d5fc9d commit b8283cb

1 file changed

Lines changed: 254 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
# =============================================================================
2+
# mqBase Release Workflow
3+
# =============================================================================
4+
# Triggers:
5+
# - Tag push: v* (e.g., v0.13.0) on any branch
6+
# - Manual: workflow_dispatch with version input
7+
#
8+
# Jobs:
9+
# 1. build: Build and push Docker images to Docker Hub and GHCR
10+
# 2. deploy: Deploy to production (requires environment approval)
11+
#
12+
# Setup:
13+
# - Create "production" environment in repo settings with required reviewers
14+
# - Install self-hosted runner on production server (see docs)
15+
# - Configure runner with labels: [self-hosted, linux, production]
16+
# =============================================================================
17+
18+
name: Release mqBase
19+
20+
on:
21+
push:
22+
tags:
23+
- 'v*'
24+
workflow_dispatch:
25+
inputs:
26+
version:
27+
description: 'Version to release (e.g., 0.13.0)'
28+
required: true
29+
deploy:
30+
description: 'Deploy to production after build'
31+
type: boolean
32+
default: false
33+
34+
env:
35+
DOCKERHUB_IMAGE: dotstartech/mqbase
36+
GHCR_IMAGE: ghcr.io/dotstartech/mqbase
37+
38+
jobs:
39+
# ===========================================================================
40+
# Build Job - Runs on GitHub-hosted runner
41+
# ===========================================================================
42+
build:
43+
name: Build Docker Images
44+
runs-on: ubuntu-latest
45+
permissions:
46+
contents: read
47+
packages: write
48+
outputs:
49+
version: ${{ steps.version.outputs.VERSION }}
50+
51+
steps:
52+
- name: Extract version
53+
id: version
54+
run: |
55+
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
56+
VERSION="${GITHUB_REF#refs/tags/v}"
57+
else
58+
VERSION="${{ inputs.version }}"
59+
fi
60+
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
61+
echo "Building version: $VERSION"
62+
63+
- name: Checkout repository
64+
uses: actions/checkout@v4
65+
66+
- name: Set up QEMU for multi-arch builds
67+
uses: docker/setup-qemu-action@v3
68+
69+
- name: Set up Docker Buildx
70+
uses: docker/setup-buildx-action@v3
71+
72+
- name: Minify app.js for production
73+
run: |
74+
npm install -g terser
75+
ORIGINAL_SIZE=$(wc -c < admin/app.js)
76+
terser admin/app.js --compress --mangle -o admin/app.js
77+
MINIFIED_SIZE=$(wc -c < admin/app.js)
78+
REDUCTION=$((100 - (MINIFIED_SIZE * 100 / ORIGINAL_SIZE)))
79+
echo "app.js: ${ORIGINAL_SIZE} bytes -> ${MINIFIED_SIZE} bytes (${REDUCTION}% reduction)"
80+
81+
- name: Log in to Docker Hub
82+
uses: docker/login-action@v3
83+
with:
84+
registry: docker.io
85+
username: ${{ secrets.DOCKERHUB_USERNAME }}
86+
password: ${{ secrets.DOCKERHUB_TOKEN }}
87+
88+
- name: Log in to GitHub Container Registry
89+
uses: docker/login-action@v3
90+
with:
91+
registry: ghcr.io
92+
username: ${{ github.actor }}
93+
password: ${{ secrets.GITHUB_TOKEN }}
94+
95+
# =========================================================================
96+
# Standard image - AMD64
97+
# =========================================================================
98+
- name: Build and push standard AMD64 image
99+
uses: docker/build-push-action@v5
100+
with:
101+
context: .
102+
file: ./docker/Dockerfile
103+
platforms: linux/amd64
104+
push: true
105+
tags: |
106+
${{ env.DOCKERHUB_IMAGE }}:${{ steps.version.outputs.VERSION }}-amd64
107+
${{ env.DOCKERHUB_IMAGE }}:${{ steps.version.outputs.VERSION }}
108+
${{ env.DOCKERHUB_IMAGE }}:latest
109+
${{ env.GHCR_IMAGE }}:${{ steps.version.outputs.VERSION }}-amd64
110+
${{ env.GHCR_IMAGE }}:${{ steps.version.outputs.VERSION }}
111+
${{ env.GHCR_IMAGE }}:latest
112+
build-args: |
113+
UID=1000
114+
GID=1000
115+
cache-from: type=gha,scope=standard-amd64
116+
cache-to: type=gha,mode=max,scope=standard-amd64
117+
118+
# =========================================================================
119+
# Standard image - ARM64
120+
# =========================================================================
121+
- name: Build and push standard ARM64 image
122+
uses: docker/build-push-action@v5
123+
with:
124+
context: .
125+
file: ./docker/Dockerfile
126+
platforms: linux/arm64
127+
push: true
128+
tags: |
129+
${{ env.DOCKERHUB_IMAGE }}:${{ steps.version.outputs.VERSION }}-arm64
130+
${{ env.GHCR_IMAGE }}:${{ steps.version.outputs.VERSION }}-arm64
131+
build-args: |
132+
UID=1000
133+
GID=1000
134+
cache-from: type=gha,scope=standard-arm64
135+
cache-to: type=gha,mode=max,scope=standard-arm64
136+
137+
# =========================================================================
138+
# Distroless image - AMD64
139+
# =========================================================================
140+
- name: Build and push distroless AMD64 image
141+
uses: docker/build-push-action@v5
142+
with:
143+
context: .
144+
file: ./docker/Dockerfile.distroless
145+
platforms: linux/amd64
146+
push: true
147+
tags: |
148+
${{ env.DOCKERHUB_IMAGE }}:${{ steps.version.outputs.VERSION }}-amd64-distroless
149+
${{ env.GHCR_IMAGE }}:${{ steps.version.outputs.VERSION }}-amd64-distroless
150+
cache-from: type=gha,scope=distroless-amd64
151+
cache-to: type=gha,mode=max,scope=distroless-amd64
152+
153+
# =========================================================================
154+
# Distroless image - ARM64
155+
# =========================================================================
156+
- name: Build and push distroless ARM64 image
157+
uses: docker/build-push-action@v5
158+
with:
159+
context: .
160+
file: ./docker/Dockerfile.distroless
161+
platforms: linux/arm64
162+
push: true
163+
tags: |
164+
${{ env.DOCKERHUB_IMAGE }}:${{ steps.version.outputs.VERSION }}-arm64-distroless
165+
${{ env.GHCR_IMAGE }}:${{ steps.version.outputs.VERSION }}-arm64-distroless
166+
cache-from: type=gha,scope=distroless-arm64
167+
cache-to: type=gha,mode=max,scope=distroless-arm64
168+
169+
- name: Build Summary
170+
run: |
171+
echo "## Images pushed successfully! :rocket:" >> $GITHUB_STEP_SUMMARY
172+
echo "" >> $GITHUB_STEP_SUMMARY
173+
echo "### Version: ${{ steps.version.outputs.VERSION }}" >> $GITHUB_STEP_SUMMARY
174+
echo "" >> $GITHUB_STEP_SUMMARY
175+
echo "### Standard Images (debian:trixie-slim)" >> $GITHUB_STEP_SUMMARY
176+
echo "| Architecture | Docker Hub | GitHub Container Registry |" >> $GITHUB_STEP_SUMMARY
177+
echo "|--------------|------------|---------------------------|" >> $GITHUB_STEP_SUMMARY
178+
echo "| AMD64 | \`${{ env.DOCKERHUB_IMAGE }}:${{ steps.version.outputs.VERSION }}-amd64\` | \`${{ env.GHCR_IMAGE }}:${{ steps.version.outputs.VERSION }}-amd64\` |" >> $GITHUB_STEP_SUMMARY
179+
echo "| ARM64 | \`${{ env.DOCKERHUB_IMAGE }}:${{ steps.version.outputs.VERSION }}-arm64\` | \`${{ env.GHCR_IMAGE }}:${{ steps.version.outputs.VERSION }}-arm64\` |" >> $GITHUB_STEP_SUMMARY
180+
echo "" >> $GITHUB_STEP_SUMMARY
181+
echo "### Distroless Images (gcr.io/distroless/base-debian13)" >> $GITHUB_STEP_SUMMARY
182+
echo "| Architecture | Docker Hub | GitHub Container Registry |" >> $GITHUB_STEP_SUMMARY
183+
echo "|--------------|------------|---------------------------|" >> $GITHUB_STEP_SUMMARY
184+
echo "| AMD64 | \`${{ env.DOCKERHUB_IMAGE }}:${{ steps.version.outputs.VERSION }}-amd64-distroless\` | \`${{ env.GHCR_IMAGE }}:${{ steps.version.outputs.VERSION }}-amd64-distroless\` |" >> $GITHUB_STEP_SUMMARY
185+
echo "| ARM64 | \`${{ env.DOCKERHUB_IMAGE }}:${{ steps.version.outputs.VERSION }}-arm64-distroless\` | \`${{ env.GHCR_IMAGE }}:${{ steps.version.outputs.VERSION }}-arm64-distroless\` |" >> $GITHUB_STEP_SUMMARY
186+
echo "" >> $GITHUB_STEP_SUMMARY
187+
echo "### Latest Tag" >> $GITHUB_STEP_SUMMARY
188+
echo "- \`${{ env.DOCKERHUB_IMAGE }}:latest\` → AMD64 standard image" >> $GITHUB_STEP_SUMMARY
189+
echo "- \`${{ env.GHCR_IMAGE }}:latest\` → AMD64 standard image" >> $GITHUB_STEP_SUMMARY
190+
191+
# ===========================================================================
192+
# Deploy Job - Runs on self-hosted runner on production server
193+
# ===========================================================================
194+
deploy:
195+
name: Deploy to Production
196+
needs: build
197+
# Only deploy on tag push OR when manually triggered with deploy=true
198+
if: startsWith(github.ref, 'refs/tags/v') || inputs.deploy == true
199+
runs-on: [self-hosted, linux, production]
200+
environment: production # Requires approval from reviewers
201+
202+
steps:
203+
- name: Deploy mqBase v${{ needs.build.outputs.version }}
204+
run: |
205+
echo "=== Deploying mqBase v${{ needs.build.outputs.version }} ==="
206+
cd /opt/mqbase
207+
208+
# Pull the new image
209+
echo "Pulling new image..."
210+
sudo docker compose -f compose.prod.yml pull
211+
212+
# Restart with new image
213+
echo "Restarting container..."
214+
sudo docker compose -f compose.prod.yml up -d
215+
216+
# Wait for container to be healthy
217+
echo "Waiting for health check..."
218+
sleep 5
219+
220+
# Verify deployment
221+
HEALTH=$(curl -sf --max-time 10 https://mqbase.io/health || echo "FAILED")
222+
if [ "$HEALTH" = "OK" ]; then
223+
echo "✅ Deployment successful!"
224+
else
225+
echo "❌ Health check failed: $HEALTH"
226+
exit 1
227+
fi
228+
229+
- name: Deployment Summary
230+
run: |
231+
echo "## Deployment Complete :white_check_mark:" >> $GITHUB_STEP_SUMMARY
232+
echo "" >> $GITHUB_STEP_SUMMARY
233+
echo "- **Version**: ${{ needs.build.outputs.version }}" >> $GITHUB_STEP_SUMMARY
234+
echo "- **Server**: mqbase.io (78.46.17.48)" >> $GITHUB_STEP_SUMMARY
235+
echo "- **Status**: Healthy" >> $GITHUB_STEP_SUMMARY
236+
echo "" >> $GITHUB_STEP_SUMMARY
237+
echo "### Verification" >> $GITHUB_STEP_SUMMARY
238+
echo "- Health endpoint: https://mqbase.io/health → OK" >> $GITHUB_STEP_SUMMARY
239+
240+
- name: Notify on failure
241+
if: failure()
242+
run: |
243+
echo "## ❌ Deployment Failed" >> $GITHUB_STEP_SUMMARY
244+
echo "" >> $GITHUB_STEP_SUMMARY
245+
echo "Check the logs above for details." >> $GITHUB_STEP_SUMMARY
246+
echo "" >> $GITHUB_STEP_SUMMARY
247+
echo "### Rollback" >> $GITHUB_STEP_SUMMARY
248+
echo "To rollback, SSH to the server and run:" >> $GITHUB_STEP_SUMMARY
249+
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
250+
echo "cd /opt/mqbase" >> $GITHUB_STEP_SUMMARY
251+
echo "sudo docker compose -f compose.prod.yml down" >> $GITHUB_STEP_SUMMARY
252+
echo "sudo docker pull dotstartech/mqbase:<previous-version>" >> $GITHUB_STEP_SUMMARY
253+
echo "sudo docker compose -f compose.prod.yml up -d" >> $GITHUB_STEP_SUMMARY
254+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY

0 commit comments

Comments
 (0)