diff --git a/.github/workflows/prod-server-deploy.yml b/.github/workflows/prod-server-deploy.yml index dfcaa56b..2ac77182 100644 --- a/.github/workflows/prod-server-deploy.yml +++ b/.github/workflows/prod-server-deploy.yml @@ -33,24 +33,62 @@ jobs: steps: - uses: actions/checkout@v4 + + - name: Parse deployment target from release + id: deployment_target + run: | + # Extract deployment target from release body or use current commit + RELEASE_BODY="${{ github.event.release.body }}" + TARGET_COMMIT="${{ github.sha }}" + TARGET_TAG="" + + # Look for deployment target in release body + # Format: deploy-target: + if echo "$RELEASE_BODY" | grep -i "deploy-target:"; then + TARGET_REF=$(echo "$RELEASE_BODY" | grep -i "deploy-target:" | head -1 | sed -E 's/.*[Dd][Ee][Pp][Ll][Oo][Yy]-[Tt][Aa][Rr][Gg][Ee][Tt]:[[:space:]]*//' | awk '{print $1}') + echo "Found deployment target: $TARGET_REF" + + # Check if it's a valid commit/tag/branch + if git cat-file -e "$TARGET_REF" 2>/dev/null; then + TARGET_COMMIT=$(git rev-parse "$TARGET_REF") + if git tag --list | grep -q "^${TARGET_REF}$"; then + TARGET_TAG="$TARGET_REF" + fi + echo "Resolved target to commit: $TARGET_COMMIT" + else + echo "Invalid deployment target '$TARGET_REF', using current commit" + fi + else + echo "No deployment target specified, using current commit" + fi + + echo "deploy_commit=$TARGET_COMMIT" >> $GITHUB_OUTPUT + echo "deploy_tag=$TARGET_TAG" >> $GITHUB_OUTPUT + echo "Using deployment commit: $TARGET_COMMIT" + + - name: Checkout deployment target + if: steps.deployment_target.outputs.deploy_commit != github.sha + uses: actions/checkout@v4 + with: + ref: ${{ steps.deployment_target.outputs.deploy_commit }} - name: Build action runner - run: docker build -t "wgd-action-runner:prod" --build-arg "GIT_SHA=${GITHUB_SHA}" apps/wgd-action-runner + run: docker build -t "wgd-action-runner:prod" --build-arg "GIT_SHA=${{ steps.deployment_target.outputs.deploy_commit }}" apps/wgd-action-runner - uses: docker/build-push-action@v6 with: - tags: "wikigdrive-prod:${{ github.sha }},wikigdrive-prod:latest" + tags: "wikigdrive-prod:${{ steps.deployment_target.outputs.deploy_commit }},wikigdrive-prod:latest" push: false build-args: | - GIT_SHA=${{ github.sha }} + GIT_SHA=${{ steps.deployment_target.outputs.deploy_commit }} BUILD_UI=yes - name: Build docs run: | docker run \ -v "/var/www/wikigdrive.com:/usr/src/app/website/.vitepress/dist" \ - -e "GIT_SHA=${{ github.sha }}" \ - "wikigdrive-prod:${{ github.sha }}" deno task -f wikigdrive-website build + -e "GIT_SHA=${{ steps.deployment_target.outputs.deploy_commit }}" \ + "wikigdrive-prod:${{ steps.deployment_target.outputs.deploy_commit }}" deno task -f wikigdrive-website build - name: Stop and remove run: docker stop wikigdrive-prod ; docker rm wikigdrive-prod @@ -69,10 +107,10 @@ jobs: -v "/var/www/preview-prod:/var/www/preview-prod" \ -v "/srv/overlay_mounts:/srv/overlay_mounts" \ -e "DOMAIN=https://wikigdrive.com" \ - -e "GIT_SHA=${GITHUB_SHA}" \ + -e "GIT_SHA=${{ steps.deployment_target.outputs.deploy_commit }}" \ --publish 127.0.0.1:3000:3000 \ --restart unless-stopped \ - "wikigdrive-prod:${GITHUB_SHA}" wikigdrive \ + "wikigdrive-prod:${{ steps.deployment_target.outputs.deploy_commit }}" wikigdrive \ --service_account /service_account.json \ --share_email mie-docs-wikigdrive@wikigdrive.iam.gserviceaccount.com \ --workdir /data \ diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..c7fc4a08 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,8 @@ +# Documentation + +This directory contains additional documentation for WikiGDrive development and operations. + +## Files + +- [deployment-control.md](deployment-control.md) - Guide for release-based deployment control +- [deployment-examples.md](deployment-examples.md) - Example release descriptions for deployment control \ No newline at end of file diff --git a/docs/deployment-control.md b/docs/deployment-control.md new file mode 100644 index 00000000..ea81ccca --- /dev/null +++ b/docs/deployment-control.md @@ -0,0 +1,117 @@ +# Release-based Deployment Control + +This document describes how to control which version of the code is deployed to production using the GitHub release system. + +## Overview + +The production deployment system now supports deploying specific versions of the code without needing to reset the master branch. This is accomplished by specifying a deployment target in the release description. + +## How it Works + +When you create a GitHub release, the production deployment workflow will: + +1. Check the release description for a deployment target specification +2. If found, checkout and deploy that specific commit/tag/branch +3. If not found, deploy the current commit (default behavior) + +## Specifying a Deployment Target + +To deploy a specific version, include the following line in your release description: + +``` +deploy-target: +``` + +### Examples + +**Deploy a specific commit:** +``` +deploy-target: a1b2c3d4e5f6 +``` + +**Deploy a specific tag:** +``` +deploy-target: v2.15.14 +``` + +**Deploy a specific branch:** +``` +deploy-target: hotfix/security-patch +``` + +## Use Cases + +### Rollback to Previous Version + +To rollback to a previous release: + +1. Create a new release with the title "Rollback to v2.15.14" +2. In the release description, add: + ``` + deploy-target: v2.15.14 + + Rolling back production to stable version due to issues with latest release. + ``` +3. Publish the release + +### Deploy a Hotfix + +To deploy a hotfix branch without merging to master: + +1. Create a hotfix branch: `git checkout -b hotfix/critical-fix` +2. Make your changes and push the branch +3. Create a new release with the title "Hotfix: Critical Security Patch" +4. In the release description, add: + ``` + deploy-target: hotfix/critical-fix + + Emergency deployment of security patch. + ``` +5. Publish the release + +### Deploy for Testing + +To deploy a specific commit for testing: + +1. Find the commit hash you want to deploy +2. Create a new release with the title "Testing Deploy" +3. In the release description, add: + ``` + deploy-target: abc123def456 + + Deploying specific commit for testing purposes. + ``` +4. Publish the release + +## Benefits + +- **Safe Rollbacks**: Easily rollback to any previous version without touching master +- **Hotfix Deployment**: Deploy critical fixes without waiting for full merge cycle +- **Testing Flexibility**: Deploy specific versions for testing without disrupting development +- **Audit Trail**: All deployments are tracked through GitHub releases +- **No Master Branch Risk**: Never need to reset or force-push master branch + +## Validation + +The deployment workflow validates that the specified target exists before attempting deployment. If an invalid target is specified, the deployment will fall back to using the current commit and log a warning. + +## Monitoring + +You can verify which version is currently deployed by: + +1. Checking the Docker container tags in production +2. Looking at the `GIT_SHA` environment variable in the running container +3. Reviewing the deployment logs in GitHub Actions + +## Migration from Manual Process + +Previously, deploying specific versions required: + +1. Resetting master to the target commit +2. Creating a release from that reset +3. Resetting master back to its original state + +With this new system, you simply: + +1. Create a release with the deployment target specified +2. The system handles checkout and deployment automatically \ No newline at end of file diff --git a/docs/deployment-examples.md b/docs/deployment-examples.md new file mode 100644 index 00000000..da0bc5dd --- /dev/null +++ b/docs/deployment-examples.md @@ -0,0 +1,104 @@ +# Example Release Descriptions + +This file provides examples of how to use the deployment control feature in GitHub releases. + +## Example 1: Deploy Specific Tag (Rollback) + +**Release Title:** Rollback to v2.15.14 + +**Release Description:** +``` +deploy-target: v2.15.14 + +Rolling back production to stable version v2.15.14 due to critical issues discovered in v2.15.15. + +This deployment will: +- Restore the stable codebase +- Fix the authentication issues reported in production +- Maintain data integrity + +Once deployed, we will investigate the issues in v2.15.15 before the next release. +``` + +## Example 2: Deploy Hotfix Branch + +**Release Title:** Emergency Security Patch + +**Release Description:** +``` +deploy-target: hotfix/security-cve-2024-001 + +Emergency deployment of security patch for CVE-2024-001. + +This hotfix addresses: +- SQL injection vulnerability in user authentication +- Cross-site scripting vulnerability in file upload +- Privilege escalation in admin dashboard + +The fix has been tested in staging and is ready for immediate production deployment. +``` + +## Example 3: Deploy Specific Commit + +**Release Title:** Deploy Tested Build + +**Release Description:** +``` +deploy-target: a1b2c3d4e5f6789012345678901234567890abcd + +Deploying specific commit that has been thoroughly tested in staging environment. + +This commit includes: +- Performance improvements for large file processing +- Bug fixes for Google Drive synchronization +- UI improvements for mobile devices + +Testing completed: +- ✅ Unit tests: 100% pass +- ✅ Integration tests: 100% pass +- ✅ Performance tests: Within acceptable limits +- ✅ Security scan: No vulnerabilities found +``` + +## Example 4: Regular Release (No Deploy Target) + +**Release Title:** WikiGDrive v2.16.0 + +**Release Description:** +``` +New features and improvements in this release: + +- Added support for collaborative editing +- Improved markdown rendering performance +- Enhanced file synchronization reliability +- New authentication options + +Full changelog: https://github.com/mieweb/wikiGDrive/compare/v2.15.14...v2.16.0 + +This release will deploy the current codebase automatically. +``` + +## Example 5: Deploy Feature Branch for Testing + +**Release Title:** Testing New File Processor + +**Release Description:** +``` +deploy-target: feature/new-file-processor + +Deploying feature branch for production testing of the new file processing engine. + +⚠️ This is a testing deployment and may be unstable. + +Changes in this branch: +- Rewritten file processing pipeline +- Improved error handling and recovery +- Better memory management for large files + +Monitoring required: +- Watch for memory usage spikes +- Monitor file processing times +- Check error logs for any issues + +Plan to rollback if issues are detected within 2 hours. +``` \ No newline at end of file diff --git a/test/test_deployment_parsing.sh b/test/test_deployment_parsing.sh new file mode 100755 index 00000000..5fdd52c3 --- /dev/null +++ b/test/test_deployment_parsing.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# Test script for deployment target parsing +# This simulates the logic used in the GitHub Actions workflow + +test_deployment_target_parsing() { + local release_body="$1" + local expected_target="$2" + local test_name="$3" + + echo "Testing: $test_name" + echo "Release body: $release_body" + + # Simulate the parsing logic + if echo "$release_body" | grep -i "deploy-target:"; then + target_ref=$(echo "$release_body" | grep -i "deploy-target:" | head -1 | sed -E 's/.*[Dd][Ee][Pp][Ll][Oo][Yy]-[Tt][Aa][Rr][Gg][Ee][Tt]:[[:space:]]*//' | awk '{print $1}') + echo "Found deployment target: $target_ref" + if [ "$target_ref" = "$expected_target" ]; then + echo "✅ PASS: Correctly parsed target '$target_ref'" + else + echo "❌ FAIL: Expected '$expected_target', got '$target_ref'" + fi + else + if [ "$expected_target" = "" ]; then + echo "✅ PASS: No deployment target found (as expected)" + else + echo "❌ FAIL: Expected target '$expected_target' but found none" + fi + fi + echo "" +} + +# Test cases +test_deployment_target_parsing "deploy-target: v2.15.14" "v2.15.14" "Simple tag deployment" + +test_deployment_target_parsing "Emergency fix + +deploy-target: hotfix/security-patch + +This deploys a critical security fix." "hotfix/security-patch" "Deployment target in multiline description" + +test_deployment_target_parsing "Deploy-Target: a1b2c3d4e5f6" "a1b2c3d4e5f6" "Case insensitive matching" + +test_deployment_target_parsing "Regular release without deployment target" "" "No deployment target specified" + +test_deployment_target_parsing "deploy-target: main +Additional text here" "main" "Target with additional content" + +echo "All deployment target parsing tests completed." \ No newline at end of file diff --git a/website/docs/developer-guide.md b/website/docs/developer-guide.md index d20b22ba..40478cce 100644 --- a/website/docs/developer-guide.md +++ b/website/docs/developer-guide.md @@ -17,6 +17,12 @@ curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh ## Version Strategy * We use labels to set the version number based on https://github.com/marketplace/actions/create-tag-release * See background info: https://github.com/mieweb/wikiGDrive/issues/297 + +## Deployment Control +* Production deployments support release-based version control +* You can deploy specific commits, tags, or branches without resetting master +* See [deployment-control.md](../../docs/deployment-control.md) for detailed instructions +* Specify deployment targets in release descriptions using: `deploy-target: ` ## Install locally