diff --git a/.github/actions/cloudrun-rollback b/.github/actions/cloudrun-rollback new file mode 100644 index 00000000..4fa2bee0 --- /dev/null +++ b/.github/actions/cloudrun-rollback @@ -0,0 +1,68 @@ +######################################################################################## +# Rollback Workflow (Cloud Run) +#--------------------------------------------------------------------------------------- +# Purpose: +# This job is automatically triggered when the `deploy-backend` job fails. +# It safely rolls back the specified Google Cloud Run service to the +# previously deployed revision by shifting 100% traffic back to it. +# +# Use case: +# - Prevents broken deployments from impacting production +# - Ensures high availability by restoring last known good revision +# +# Trigger condition: +# - Runs only when a dependent job fails (`if: failure()`) +######################################################################################## + +rollback-all: + needs: + - deploy-backend + if: ${{ failure() }} + runs-on: ubuntu-latest + + steps: + - name: Authenticate to GCP + uses: google-github-actions/auth@v2 + with: + credentials_json: # GCP Service Account key (JSON) + + - name: Setup gcloud + uses: google-github-actions/setup-gcloud@v2 + with: + project_id: # GCP Project ID + + - name: Rollback Cloud Run services (if needed) + run: | + echo "🚨 Rollback triggered because a deployment failed" + + REGION= # GCP region + PROJECT= # GCP Project ID + + rollback_if_needed () { + SERVICE_NAME=$1 + PREV_REV=$2 + + if [ -z "$PREV_REV" ]; then + echo "â„šī¸ $SERVICE_NAME was not deployed, skipping rollback" + return + fi + + CURRENT_REV=$(gcloud run services describe "$SERVICE_NAME" \ + --region "$REGION" \ + --project "$PROJECT" \ + --format="value(status.traffic[0].revisionName)") + + if [ "$CURRENT_REV" = "$PREV_REV" ]; then + echo "✅ $SERVICE_NAME rollback not required — traffic already on previous revision ($PREV_REV)" + else + echo "🔄 Rolling back $SERVICE_NAME to revision: $PREV_REV" + gcloud run services update-traffic "$SERVICE_NAME" \ + --to-revisions="$PREV_REV=100" \ + --region "$REGION" \ + --project "$PROJECT" \ + && echo "✅ $SERVICE_NAME rollback successful" \ + || echo "âš ī¸ $SERVICE_NAME rollback failed — traffic may already be correct" + fi + } + + rollback_if_needed "# Cloud Run service name" "${{ needs.deploy-backend.outputs.revision }}" \ No newline at end of file diff --git a/.github/workflows/cloudrun-rollback.yml b/.github/workflows/cloudrun-rollback.yml new file mode 100644 index 00000000..4029fa8d --- /dev/null +++ b/.github/workflows/cloudrun-rollback.yml @@ -0,0 +1,76 @@ +--- +name: Cloud Run Deploy with Auto Rollback + +on: + workflow_call: + inputs: + gcp_registry_host: + required: true + type: string + IMAGE_NAME: + required: true + type: string + IMAGE_TAG: + required: true + type: string + GCP_REPOSITORY: + required: true + type: string + SERVICE_NAME: + required: true + type: string + REGION: + required: true + type: string + + secrets: + GCP_PROJECT_ID: + required: true + GCP_SA_KEY: + required: true + + outputs: + revision: + description: "Previous revision" + value: ${{ jobs.deploy.outputs.revision }} + service_name: + description: "Service name" + value: ${{ inputs.SERVICE_NAME }} + +jobs: + deploy: + runs-on: ubuntu-latest + outputs: + revision: ${{ steps.prev.outputs.revision }} + + steps: + - name: Authenticate to GCP + uses: google-github-actions/auth@v2 + with: + credentials_json: ${{ secrets.GCP_SA_KEY }} + + - name: Setup gcloud + uses: google-github-actions/setup-gcloud@v2 + + - name: Get current revision + id: prev + run: | + REVISION=$(gcloud run services describe ${{ inputs.SERVICE_NAME }} \ + --region ${{ inputs.REGION }} \ + --format="value(status.traffic[0].revisionName)") + echo "Current revision: $REVISION" + # Set for parent workflow (Environment file) + echo "revision=$REVISION" >> $GITHUB_OUTPUT + + # 2ī¸âƒŖ Deploy new image + - name: Deploy new image + id: deploy + run: | + IMAGE_URI="${{ inputs.gcp_registry_host }}/${{ secrets.GCP_PROJECT_ID }}/${{ inputs.GCP_REPOSITORY }}/${{ inputs.IMAGE_NAME }}:${{ inputs.IMAGE_TAG }}" + echo "🚀 Deploying $IMAGE_URI" + gcloud run deploy ${{ inputs.SERVICE_NAME }} \ + --image "$IMAGE_URI" \ + --region ${{ inputs.REGION }} \ + --platform managed \ + --quiet +... diff --git a/docs/cloudrun-rollback.md b/docs/cloudrun-rollback.md new file mode 100644 index 00000000..d704d948 --- /dev/null +++ b/docs/cloudrun-rollback.md @@ -0,0 +1,60 @@ +## [Cloud Run Deploy with Auto Rollback reusable workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/shared-cloudrun-rollback.yml) + + + +### Overview + +The Cloud Run Deploy with Auto Rollback reusable workflow is designed to make Cloud Run deployments safer and more reliable. + +It deploys a new Docker image to a Cloud Run service while preserving the currently active revision. +If the deployment fails, parent workflows can automatically roll back traffic to the last stable revision. + +This approach helps reduce production risk and ensures quick recovery from failed deployments. + +### Features + +* Deploys a Docker image to Google Cloud Run + +* Captures the currently active revision before deployment + +* Exposes the previous revision as a workflow output + +* Enables automatic rollback on deployment failure + +* Uses secure GCP authentication via Service Account + +* Designed as a reusable workflow for multiple services + +### Usage + +### Workflow Location +``` +.github/workflows/cloudrun-rollback.yml +``` +#### Example +```yaml +name: Deploy to Cloud Run + +on: + workflow_dispatch: + +jobs: + deploy-backend: + uses: clouddrove/github-shared-workflows/.github/workflows/cloudrun-rollback.yml@master + with: + gcp_registry_host: # GCP Artifact Registry host + IMAGE_NAME: # Docker image name + IMAGE_TAG: # Image tag to deploy + SERVICE_NAME: # Cloud Run service name + REGION: # GCP region + GCP_REPOSITORY: # Artifact Registry repository + secrets: + GCP_PROJECT_ID: # GCP Project ID + GCP_SA_KEY: # GCP Service Account key (JSON) +``` + +#### Reference workflow: +The rollback logic used by this workflow is implemented in +``` +actions/cloudrun-rollback +``` \ No newline at end of file diff --git a/docs/tfdrift.md b/docs/tfdrift.md new file mode 100644 index 00000000..4f249487 --- /dev/null +++ b/docs/tfdrift.md @@ -0,0 +1,28 @@ +## [terraform drifts Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/tfdrifts.yml) + +This workflow automates Terraform configuration drift detection by running terraform init/plan against your live infrastructure and signaling when resources have changed outside of code. The reusable workflow is stored at `.github/workflows/tfdrifts.yml` in the shared repo. + +**Key capabilities**: +- Detect drift via terraform plan. +- Works with AWS, Azure, or GCP (select with provider). + +#### Example +```yaml +name: TF-Drift +on: + push: + branches: [ master ] + pull_request: + workflow_dispatch: +jobs: + tf-lint: + uses: clouddrove/github-shared-workflows/.github/workflows/tfdrift.yml@master + with: + working_directory: #'./_example/complete/' + provider: #aws + aws_region: # AWS region + secrets: + AWS_ACCESS_KEY_ID: # Specify AWS Access key ID + AWS_SECRET_ACCESS_KEY: # Specify AWS Secret Access key ID + AWS_SESSION_TOKEN: # Specify Session ID +``` \ No newline at end of file