From b21a0e3a39a8df511bb1565bed657db7a5d10977 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Montoya Date: Tue, 25 Nov 2025 17:21:46 -0500 Subject: [PATCH] Feature/CI Workflow (#1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Add CI/CD Pipeline with Docker Build and Publish ## Summary This PR adds a complete CI/CD pipeline for building and publishing Docker images of the Three.js game to the Forgejo container registry. The workflow automatically builds, validates, and publishes Docker images with semantic versioning when code is merged to main. ## Changes ### 🚀 CI/CD Workflow (`.forgejo/workflows/ci.yaml`) - **Build & Validation**: Automatically builds Docker image on PRs and validates it works - **Semantic Versioning**: Auto-increments patch version on each merge to main - First version: `0.1.0` (when no tags exist) - Subsequent merges: Auto-increments patch (e.g., `0.1.0` → `0.1.1` → `0.1.2`) - **Publishing**: Publishes images to `git.jusemon.com/jusemon/threejs-test:` and `latest` tag - **Git Tagging**: Automatically creates git tags (e.g., `v0.1.0`) for releases - **Registry Integration**: Uses Forgejo container registry with secrets-based authentication ### 🐳 Docker Setup - **Dockerfile**: Custom nginx:alpine image with the game HTML file - **docker-compose.yml**: Simple orchestration for local development - **nginx.conf**: Minimal nginx configuration with gzip compression ## Workflow Behavior ### On Pull Requests - ✅ Builds Docker image - ✅ Validates image by running container and checking HTTP response - ❌ Does NOT publish (validation only) ### On Merge to Main - ✅ Builds Docker image - ✅ Validates image - ✅ Publishes to registry with version tag - ✅ Tags as `latest` - ✅ Creates git tag for the release ## Required Setup Before merging, ensure these secrets are configured in the repository: - `REGISTRY_USERNAME`: Forgejo username - `REGISTRY_PASSWORD`: Personal Access Token with package write permissions ## Versioning Strategy - **First Release**: `0.1.0` (when no tags exist) - **Subsequent Releases**: Auto-increments patch version on each merge - **Image Tags**: - `git.jusemon.com/jusemon/threejs-test:0.1.0` - `git.jusemon.com/jusemon/threejs-test:latest` (always points to latest main) ## Testing The workflow includes validation steps that: 1. Build the Docker image 2. Run a test container 3. Verify the web server responds correctly 4. Only publish if all validations pass ## Benefits - ✅ Automated builds and deployments - ✅ Consistent versioning - ✅ Image validation before publishing - ✅ Easy rollback using version tags - ✅ Latest tag for easy deployment Reviewed-on: https://git.jusemon.com/jusemon/threejs-test/pulls/1 Co-authored-by: Juan Sebastian Montoya Co-committed-by: Juan Sebastian Montoya --- .forgejo/workflows/ci.yaml | 100 +++++++++++++++++++++++++++++++++++++ Dockerfile | 11 ++++ docker-compose.yml | 7 +++ nginx.conf | 17 +++++++ 4 files changed, 135 insertions(+) create mode 100644 .forgejo/workflows/ci.yaml create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 nginx.conf diff --git a/.forgejo/workflows/ci.yaml b/.forgejo/workflows/ci.yaml new file mode 100644 index 0000000..d3be3cf --- /dev/null +++ b/.forgejo/workflows/ci.yaml @@ -0,0 +1,100 @@ +name: Build and Publish Docker Image + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + build-and-validate: + name: Build and Validate + runs-on: ubuntu + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Build Docker Image + run: | + docker build -t threejs-test:test . + + - name: Validate Image + run: | + docker run --rm -d --name test-container -p 8080:80 threejs-test:test + sleep 2 + curl -f http://localhost:8080 || exit 1 + docker stop test-container + + publish: + name: Publish to Registry + runs-on: ubuntu + needs: build-and-validate + if: github.event_name == 'push' || gitea.event_name == 'push' + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history for tags + + - name: Login to Registry + run: | + echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login git.jusemon.com -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin + + - name: Determine Version + id: version + run: | + # Get latest version tag + LATEST_TAG=$(git describe --tags --match 'v*.*.*' --abbrev=0 2>/dev/null || echo "v0.0.0") + LATEST_VERSION="${LATEST_TAG#v}" + + # Parse version components + IFS='.' read -r MAJOR MINOR PATCH <<< "$LATEST_VERSION" + MAJOR=${MAJOR:-0} + MINOR=${MINOR:-0} + PATCH=${PATCH:-0} + + # Increment patch version for each merge to main, or start at 0.1.0 if no tags exist + if [[ "$LATEST_TAG" == "v0.0.0" ]]; then + # First version + NEW_VERSION="0.1.0" + else + # Increment patch version for each merge to main + PATCH=$((PATCH + 1)) + NEW_VERSION="$MAJOR.$MINOR.$PATCH" + fi + + echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "tag=v$NEW_VERSION" >> $GITHUB_OUTPUT + echo "Latest tag: $LATEST_TAG" + echo "New version: $NEW_VERSION" + + - name: Build Docker Image + run: | + IMAGE_NAME="git.jusemon.com/jusemon/threejs-test:${{ steps.version.outputs.version }}" + docker build -t "$IMAGE_NAME" . + echo "IMAGE_NAME=$IMAGE_NAME" >> $GITHUB_ENV + + - name: Push Docker Image + run: | + IMAGE_NAME="git.jusemon.com/jusemon/threejs-test:${{ steps.version.outputs.version }}" + docker push "$IMAGE_NAME" + + # Also tag as 'latest' for main branch + docker tag "$IMAGE_NAME" "git.jusemon.com/jusemon/threejs-test:latest" + docker push "git.jusemon.com/jusemon/threejs-test:latest" + + - name: Create Git Tag + run: | + git config user.name "forgejo-actions" + git config user.email "forgejo-actions@forgejo.io" + TAG="${{ steps.version.outputs.tag }}" + # Check if tag already exists + if git rev-parse "$TAG" >/dev/null 2>&1; then + echo "Tag $TAG already exists, skipping tag creation" + else + git tag -a "$TAG" -m "Release ${{ steps.version.outputs.version }}" + git push origin "$TAG" + fi + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..38d09b4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM nginx:alpine + +# Copy the HTML file +COPY index.html /usr/share/nginx/html/index.html + +# Copy nginx configuration +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Expose port 80 +EXPOSE 80 + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..747f7dd --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,7 @@ +name: threejs-test + +services: + ui: + build: . + restart: unless-stopped + diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..2c3229d --- /dev/null +++ b/nginx.conf @@ -0,0 +1,17 @@ +server { + listen 80; + server_name localhost; + + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ =404; + } + + # Enable gzip compression + gzip on; + gzip_types text/html text/css application/javascript; + gzip_min_length 1000; +} +