feat: convert workflows to tag-based deployment with semantic versioning

- Replace branch triggers with tag triggers for all services
- Backend: backend-dev-v1.0.0
- Learner: learner-dev-v1.0.0
- Management: management-dev-v1.0.0
- Extract version from tags and use for Docker image tagging
- Update compose.yaml to use GITEA_INSTANCE variable
- Add comprehensive deployment guide (DEPLOYMENT.md)
- Support pre-release tags (beta, rc, alpha)

BREAKING CHANGE: Pushing to dev branch no longer triggers deployment.
Must create and push version tags to deploy.
This commit is contained in:
JakkrapartXD 2026-02-11 10:20:35 +07:00
parent 025084b2bf
commit e7a2ac8b5a
5 changed files with 489 additions and 46 deletions

View file

@ -2,11 +2,9 @@ name: Build and Deploy Backend
on: on:
push: push:
branches: tags:
- dev - "backend-dev-v[0-9]+.[0-9]+.[0-9]+"
paths: - "backend-dev-v[0-9]+.[0-9]+.[0-9]+-*"
- "Backend/**"
- ".forgejo/workflows/deploy-backend.yaml"
workflow_dispatch: workflow_dispatch:
env: env:
@ -16,7 +14,6 @@ env:
# Docker Image # Docker Image
BACKEND_IMAGE_NAME: chamomind/elearning-backend BACKEND_IMAGE_NAME: chamomind/elearning-backend
IMAGE_TAG: ${{ github.event.pull_request.head.sha || github.sha }}
# Notifications # Notifications
DISCORD_WEBHOOK_URL: ${{ vars.DISCORD_WEBHOOK_URL }} DISCORD_WEBHOOK_URL: ${{ vars.DISCORD_WEBHOOK_URL }}
@ -26,14 +23,22 @@ jobs:
name: Build Backend Docker Image name: Build Backend Docker Image
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
short_sha: ${{ steps.vars.outputs.short_sha }} version: ${{ steps.version.outputs.version }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Generate short SHA - name: Extract version from tag
id: vars id: version
run: echo "short_sha=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
# Tag: backend-dev-v1.2.3 → Version: 1.2.3
VERSION=$(echo "${{ github.ref_name }}" | sed 's/backend-dev-v//g')
echo "version=${VERSION}" >> $GITHUB_OUTPUT
else
# Manual run: use latest-{run_number}
echo "version=latest-${{ github.run_number }}" >> $GITHUB_OUTPUT
fi
- name: Log in to Container Registry - name: Log in to Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v3
@ -56,9 +61,8 @@ jobs:
with: with:
images: ${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }} images: ${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}
tags: | tags: |
type=ref,event=branch type=raw,value=${{ steps.version.outputs.version }}
type=sha,prefix= type=raw,value=latest,enable=${{ github.event_name == 'push' }}
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/dev' }}
- name: Build and Push Docker image - name: Build and Push Docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
@ -86,7 +90,7 @@ jobs:
script: | script: |
cd ~/repo cd ~/repo
chmod +x ./replace-env.sh ./deploy.sh chmod +x ./replace-env.sh ./deploy.sh
./replace-env.sh BACKEND_TAG "${{ needs.build.outputs.short_sha }}" ./replace-env.sh BACKEND_TAG "${{ needs.build.outputs.version }}"
./deploy.sh backend ./deploy.sh backend
notify: notify:

View file

@ -2,11 +2,9 @@ name: Build and Deploy Frontend Learner
on: on:
push: push:
branches: tags:
- dev - "learner-dev-v[0-9]+.[0-9]+.[0-9]+"
paths: - "learner-dev-v[0-9]+.[0-9]+.[0-9]+-*"
- "Frontend-Learner/**"
- ".forgejo/workflows/deploy-frontend-learner.yaml"
workflow_dispatch: workflow_dispatch:
env: env:
@ -25,14 +23,22 @@ jobs:
name: Build Frontend Learner Docker Image name: Build Frontend Learner Docker Image
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
short_sha: ${{ steps.short_sha.outputs.sha }} version: ${{ steps.version.outputs.version }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Generate short SHA - name: Extract version from tag
id: short_sha id: version
run: echo "sha=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
# Tag: learner-dev-v1.2.3 → Version: 1.2.3
VERSION=$(echo "${{ github.ref_name }}" | sed 's/learner-dev-v//g')
echo "version=${VERSION}" >> $GITHUB_OUTPUT
else
# Manual run: use latest-{run_number}
echo "version=latest-${{ github.run_number }}" >> $GITHUB_OUTPUT
fi
- name: Log in to Container Registry - name: Log in to Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v3
@ -55,9 +61,8 @@ jobs:
with: with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: | tags: |
type=ref,event=branch type=raw,value=${{ steps.version.outputs.version }}
type=sha,prefix= type=raw,value=latest,enable=${{ github.event_name == 'push' }}
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/dev' }}
- name: Build and Push Docker image - name: Build and Push Docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
@ -85,7 +90,7 @@ jobs:
script: | script: |
cd ~/repo cd ~/repo
chmod +x ./replace-env.sh ./deploy.sh chmod +x ./replace-env.sh ./deploy.sh
./replace-env.sh FRONTEND_TAG "${{ needs.build.outputs.short_sha }}" ./replace-env.sh FRONTEND_TAG "${{ needs.build.outputs.version }}"
./deploy.sh learner ./deploy.sh learner
notify: notify:

View file

@ -2,11 +2,9 @@ name: Build and Deploy Frontend Management to Dev Server
on: on:
push: push:
branches: tags:
- dev - "management-dev-v[0-9]+.[0-9]+.[0-9]+"
paths: - "management-dev-v[0-9]+.[0-9]+.[0-9]+-*"
- "frontend_management/**"
- ".forgejo/workflows/deploy-frontend-management.yaml"
workflow_dispatch: workflow_dispatch:
env: env:
@ -25,14 +23,22 @@ jobs:
name: Build Frontend Management Docker Image name: Build Frontend Management Docker Image
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
short_sha: ${{ steps.short_sha.outputs.sha }} version: ${{ steps.version.outputs.version }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Generate short SHA - name: Extract version from tag
id: short_sha id: version
run: echo "sha=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
# Tag: management-dev-v1.2.3 → Version: 1.2.3
VERSION=$(echo "${{ github.ref_name }}" | sed 's/management-dev-v//g')
echo "version=${VERSION}" >> $GITHUB_OUTPUT
else
# Manual run: use latest-{run_number}
echo "version=latest-${{ github.run_number }}" >> $GITHUB_OUTPUT
fi
- name: Log in to Container Registry - name: Log in to Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v3
@ -55,9 +61,8 @@ jobs:
with: with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: | tags: |
type=ref,event=branch type=raw,value=${{ steps.version.outputs.version }}
type=sha,prefix= type=raw,value=latest,enable=${{ github.event_name == 'push' }}
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/dev' }}
- name: Build and Push Docker image - name: Build and Push Docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
@ -85,7 +90,7 @@ jobs:
script: | script: |
cd ~/repo cd ~/repo
chmod +x ./replace-env.sh ./deploy.sh chmod +x ./replace-env.sh ./deploy.sh
./replace-env.sh MANAGEMENT_TAG "${{ needs.build.outputs.short_sha }}" ./replace-env.sh MANAGEMENT_TAG "${{ needs.build.outputs.version }}"
./deploy.sh management ./deploy.sh management
notify: notify:

423
DEPLOYMENT.md Normal file
View file

@ -0,0 +1,423 @@
# 🚀 E-Learning Platform Deployment Guide
## Overview
This project uses **tag-based deployment** with semantic versioning. Deployments are triggered by pushing Git tags, not by pushing to branches.
---
## 📋 Prerequisites
- Git installed and configured
- Access to push tags to the repository
- Understanding of semantic versioning
---
## 🏷️ Tag Naming Convention
### Format
```
<service>-<environment>-v<version>
```
### Services
- `backend` - Backend API
- `learner` - Frontend Learner
- `management` - Frontend Management
### Environments
- `dev` - Development server
- `staging` - Staging server (future)
- `prod` - Production server (future)
### Version Format (Semantic Versioning)
- **Major.Minor.Patch** (e.g., `1.0.0`)
- **Major.Minor.Patch-PreRelease** (e.g., `1.0.0-beta`, `1.0.0-rc1`)
### Examples
```
backend-dev-v1.0.0
learner-dev-v1.2.3
management-dev-v2.0.0-beta
```
---
## 🚀 Deployment Commands
### 1. Deploy All Services (Same Version)
Use this when deploying a complete release with all services updated.
```bash
# Set version
VERSION="1.0.0"
# Create tags for all services
git tag backend-dev-v${VERSION}
git tag learner-dev-v${VERSION}
git tag management-dev-v${VERSION}
# Push all tags at once
git push origin --tags
# Or push individually
git push origin backend-dev-v${VERSION}
git push origin learner-dev-v${VERSION}
git push origin management-dev-v${VERSION}
```
---
### 2. Deploy Single Service
Use this when only one service needs to be updated (e.g., hotfix).
#### Backend Only
```bash
git tag backend-dev-v1.0.1
git push origin backend-dev-v1.0.1
```
#### Frontend Learner Only
```bash
git tag learner-dev-v1.0.1
git push origin learner-dev-v1.0.1
```
#### Frontend Management Only
```bash
git tag management-dev-v1.0.1
git push origin management-dev-v1.0.1
```
---
### 3. Deploy Pre-Release Version
Use this for testing before official release.
```bash
# Beta release
git tag backend-dev-v1.0.0-beta
git push origin backend-dev-v1.0.0-beta
# Release candidate
git tag backend-dev-v1.0.0-rc1
git push origin backend-dev-v1.0.0-rc1
# Alpha release
git tag backend-dev-v1.0.0-alpha
git push origin backend-dev-v1.0.0-alpha
```
---
### 4. View Existing Tags
```bash
# List all tags
git tag
# List tags for specific service
git tag | grep backend-dev
git tag | grep learner-dev
git tag | grep management-dev
# Show tag details
git show backend-dev-v1.0.0
```
---
### 5. Delete Tag (If Mistake)
```bash
# Delete local tag
git tag -d backend-dev-v1.0.0
# Delete remote tag
git push origin --delete backend-dev-v1.0.0
```
---
## 📝 Complete Deployment Workflow
### Scenario: Release v1.0.0
```bash
# 1. Ensure you're on dev branch and up to date
git checkout dev
git pull origin dev
# 2. Make your changes
git add .
git commit -m "feat: implement user authentication"
git push origin dev
# 3. Test locally (optional but recommended)
cd Backend
docker compose up
# 4. Create version tags
git tag backend-dev-v1.0.0
git tag learner-dev-v1.0.0
git tag management-dev-v1.0.0
# 5. Push tags to trigger CI/CD
git push origin --tags
# 6. Monitor CI/CD pipeline
# - Check Forgejo Actions
# - Check Discord notifications
# - Verify deployment on server
# 7. Verify deployment
curl http://192.168.1.69:20901/health
curl http://192.168.1.69:20902
curl http://192.168.1.69:20903
```
---
### Scenario: Hotfix v1.0.1 (Backend Only)
```bash
# 1. Fix the bug
git checkout dev
git pull origin dev
git add .
git commit -m "fix: resolve authentication bug"
git push origin dev
# 2. Create patch version tag (only backend)
git tag backend-dev-v1.0.1
# 3. Push tag
git push origin backend-dev-v1.0.1
# 4. Only backend will be rebuilt and deployed
# Frontend services remain on v1.0.0
```
---
### Scenario: Feature Release v1.1.0
```bash
# 1. Develop feature
git checkout dev
git add .
git commit -m "feat: add course filtering"
git push origin dev
# 2. Create minor version tags
git tag backend-dev-v1.1.0
git tag learner-dev-v1.1.0
git tag management-dev-v1.1.0
# 3. Push tags
git push origin --tags
```
---
### Scenario: Breaking Change v2.0.0
```bash
# 1. Implement breaking changes
git checkout dev
git add .
git commit -m "feat!: redesign API endpoints (BREAKING CHANGE)"
git push origin dev
# 2. Create major version tags
git tag backend-dev-v2.0.0
git tag learner-dev-v2.0.0
git tag management-dev-v2.0.0
# 3. Push tags
git push origin --tags
```
---
## 🔄 Rollback to Previous Version
If a deployment fails or has issues, rollback to a previous version:
### On Server (SSH)
```bash
# SSH to server
ssh dev@192.168.1.69
# Navigate to repo
cd ~/repo
# Update environment variables to previous version
./replace-env.sh BACKEND_TAG "1.0.0"
./replace-env.sh FRONTEND_TAG "1.0.0"
./replace-env.sh MANAGEMENT_TAG "1.0.0"
# Redeploy with old version
./deploy.sh backend
./deploy.sh learner
./deploy.sh management
```
---
## 📊 Version History
### View Deployment History
```bash
# List all tags sorted by version
git tag -l "backend-dev-v*" --sort=-v:refname
# Show commits for a specific tag
git log backend-dev-v1.0.0 -1
# Compare versions
git diff backend-dev-v1.0.0 backend-dev-v1.1.0
```
---
## 🛠️ Helper Scripts
### Create Multi-Service Tag Script
Create `scripts/tag-release.sh`:
```bash
#!/bin/bash
if [ -z "$1" ]; then
echo "Usage: ./tag-release.sh <version>"
echo "Example: ./tag-release.sh 1.0.0"
exit 1
fi
VERSION=$1
echo "Creating tags for version ${VERSION}..."
git tag backend-dev-v${VERSION}
git tag learner-dev-v${VERSION}
git tag management-dev-v${VERSION}
echo "Tags created:"
git tag | grep "v${VERSION}"
echo ""
echo "Push tags with: git push origin --tags"
```
Usage:
```bash
chmod +x scripts/tag-release.sh
./scripts/tag-release.sh 1.0.0
git push origin --tags
```
---
## ⚠️ Important Notes
> [!IMPORTANT]
> **Pushing to `dev` branch does NOT trigger deployment.** You must create and push a tag to deploy.
> [!WARNING]
> **Tags are immutable.** Once pushed, a tag should not be changed. If you need to fix a release, create a new patch version.
> [!TIP]
> **Use pre-release tags for testing.** Tag with `-beta` or `-rc1` suffix to test before official release.
---
## 🔍 Troubleshooting
### Tag Already Exists
```bash
# Error: tag 'backend-dev-v1.0.0' already exists
# Solution: Use next version number
git tag backend-dev-v1.0.1
```
### CI/CD Not Triggering
```bash
# Check if tag matches pattern
git tag | grep backend-dev-v1.0.0
# Verify tag was pushed to remote
git ls-remote --tags origin | grep backend-dev-v1.0.0
```
### Wrong Tag Pushed
```bash
# Delete from remote
git push origin --delete backend-dev-v1.0.0
# Delete from local
git tag -d backend-dev-v1.0.0
# Create correct tag
git tag backend-dev-v1.0.1
git push origin backend-dev-v1.0.1
```
---
## 📚 Semantic Versioning Guide
### When to Increment
| Change Type | Version | Example |
|-------------|---------|---------|
| Bug fix | Patch (x.x.1) | `1.0.0``1.0.1` |
| New feature (backward compatible) | Minor (x.1.x) | `1.0.0``1.1.0` |
| Breaking change | Major (1.x.x) | `1.0.0``2.0.0` |
| Pre-release | Add suffix | `1.0.0-beta` |
### Examples
```bash
# Bug fixes
1.0.0 → 1.0.1 → 1.0.2
# New features
1.0.0 → 1.1.0 → 1.2.0
# Breaking changes
1.0.0 → 2.0.0 → 3.0.0
# Pre-releases
1.0.0-alpha → 1.0.0-beta → 1.0.0-rc1 → 1.0.0
```
---
## 🎯 Quick Reference
```bash
# Deploy all services v1.0.0
git tag backend-dev-v1.0.0 learner-dev-v1.0.0 management-dev-v1.0.0
git push origin --tags
# Deploy backend only v1.0.1
git tag backend-dev-v1.0.1 && git push origin backend-dev-v1.0.1
# View tags
git tag | grep dev
# Delete tag
git tag -d backend-dev-v1.0.0
git push origin --delete backend-dev-v1.0.0
```
---
**Last Updated:** 2026-02-11

View file

@ -5,23 +5,27 @@ services:
# Backend API # Backend API
backend: backend:
image: 192.168.1.60/chamomind/elearning-backend:${BACKEND_TAG:-latest} image: ${GITEA_INSTANCE}/chamomind/elearning-backend:${BACKEND_TAG}
container_name: elearning-backend container_name: elearning-backend
restart: unless-stopped restart: unless-stopped
ports: ports:
- "4000:4000" - "20901:4000"
env_file: env_file:
- .env - .env
environment:
- NODE_ENV=production
networks: networks:
- elearning-shared - elearning-shared
# Frontend Learner # Frontend Learner
frontend-learner: learner:
image: 192.168.1.60/chamomind/elearning-learner:${FRONTEND_TAG:-latest} image: ${GITEA_INSTANCE}/chamomind/elearning-learner:${FRONTEND_TAG}
container_name: elearning-learner container_name: elearning-learner
restart: unless-stopped restart: unless-stopped
ports: ports:
- "20902:3000" - "20902:3000"
environment:
- PORT=${PORT_MANG:-3000}
env_file: env_file:
- .env - .env
depends_on: depends_on:
@ -30,12 +34,14 @@ services:
- elearning-shared - elearning-shared
# Frontend Management # Frontend Management
frontend-management: management:
image: 192.168.1.60/chamomind/elearning-management:${MANAGEMENT_TAG:-latest} image: ${GITEA_INSTANCE}/chamomind/elearning-management:${MANAGEMENT_TAG}
container_name: elearning-management container_name: elearning-management
restart: unless-stopped restart: unless-stopped
ports: ports:
- "20903:3001" - "20903:3001"
environment:
- PORT=${PORT_MANG:-3001}
env_file: env_file:
- .env - .env
depends_on: depends_on: