Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions .github/actions/deployment-notification/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
name: "Deployment Notification"
description: "Sends deployment status notifications"

inputs:
deployment_status:
description: "Status of deployment (success, failure, cancelled)"
required: true
environment:
description: "Environment being deployed to (develop, staging, production)"
required: true
version:
description: "Version being deployed"
required: true
branch:
description: "Branch being deployed from"
required: true
commit_sha:
description: "Commit SHA being deployed"
required: false
default: "${{ github.sha }}"
commit_message:
description: "Commit message"
required: false
default: "${{ github.event.head_commit.message || 'No commit message' }}"
author:
description: "Author of the commit"
required: false
default: "${{ github.actor }}"
pr_number:
description: "Pull request number"
required: false
default: "${{ github.event.pull_request.number || '' }}"
pr_title:
description: "Pull request title"
required: false
default: "${{ github.event.pull_request.title || '' }}"
webhook_url:
description: "Webhook URL for notifications (Slack, Discord, etc.)"
required: false
email_recipients:
description: "Comma-separated list of email recipients"
required: false

runs:
using: "composite"
steps:
- name: Generate Notification Message
id: generate_message
shell: bash
run: |
status="${{ inputs.deployment_status }}"
environment="${{ inputs.environment }}"
version="${{ inputs.version }}"
branch="${{ inputs.branch }}"
commit_sha="${{ inputs.commit_sha }}"
commit_message="${{ inputs.commit_message }}"
author="${{ inputs.author }}"
pr_number="${{ inputs.pr_number }}"
pr_title="${{ inputs.pr_title }}"

# Set emoji based on status
case "$status" in
"success") status_emoji="✅" ;;
"failure") status_emoji="❌" ;;
"cancelled") status_emoji="⚠️" ;;
*) status_emoji="ℹ️" ;;
esac

# Set environment emoji
case "$environment" in
"develop") env_emoji="🔧" ;;
"staging") env_emoji="🚀" ;;
"production") env_emoji="🎯" ;;
*) env_emoji="🌍" ;;
esac

# Build message
message=""
message+="$status_emoji **Deployment $status**\n"
message+="$env_emoji **Environment:** $environment\n"
message+="📦 **Version:** $version\n"
message+="🌿 **Branch:** $branch\n"
message+="👤 **Author:** $author\n"

if [[ -n "$pr_number" ]]; then
message+="🔗 **PR:** #$pr_number - $pr_title\n"
fi

message+="📝 **Commit:** \`${commit_sha:0:8}\`\n"
message+="💬 **Message:** $commit_message\n"
message+="⏰ **Time:** $(date -u +'%Y-%m-%d %H:%M:%S UTC')\n"

# Add repository link
message+="🔗 **Repository:** https://github.com/${{ github.repository }}\n"

if [[ -n "$pr_number" ]]; then
message+="🔗 **PR Link:** https://github.com/${{ github.repository }}/pull/$pr_number\n"
fi

echo "message<<EOF" >> $GITHUB_OUTPUT
echo "$message" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

echo "Generated notification message"

- name: Send Webhook Notification
if: inputs.webhook_url != ''
shell: bash
run: |
webhook_url="${{ inputs.webhook_url }}"
message="${{ steps.generate_message.outputs.message }}"

# Prepare payload
payload=$(cat <<EOF
{
"text": "$message",
"username": "Deployment Bot",
"icon_emoji": ":rocket:"
}
EOF
)

# Send webhook
curl -X POST -H "Content-Type: application/json" \
-d "$payload" \
"$webhook_url" || {
echo "::warning::Failed to send webhook notification"
}

echo "✅ Webhook notification sent"

- name: Send Email Notification
if: inputs.email_recipients != ''
shell: bash
run: |
recipients="${{ inputs.email_recipients }}"
status="${{ inputs.deployment_status }}"
environment="${{ inputs.environment }}"
version="${{ inputs.version }}"

# This would typically use a service like SendGrid, Mailgun, etc.
# For now, we'll just log the intent
echo "📧 Email notification would be sent to: $recipients"
echo "Subject: Deployment $status - $environment v$version"
echo "Body: ${{ steps.generate_message.outputs.message }}"

# Example with curl to a hypothetical email service
# curl -X POST "https://api.emailservice.com/send" \
# -H "Authorization: Bearer ${{ secrets.EMAIL_API_KEY }}" \
# -H "Content-Type: application/json" \
# -d "{\"to\":\"$recipients\",\"subject\":\"Deployment $status\",\"body\":\"$message\"}"

- name: Create GitHub Issue for Failed Deployments
if: inputs.deployment_status == 'failure'
shell: bash
run: |
title="🚨 Deployment Failed - ${{ inputs.environment }} v${{ inputs.version }}"
body="${{ steps.generate_message.outputs.message }}"

# Create issue using GitHub CLI
gh issue create \
--title "$title" \
--body "$body" \
--label "deployment-failed" \
--label "${{ inputs.environment }}" || {
echo "::warning::Failed to create GitHub issue"
}

echo "✅ GitHub issue created for failed deployment"

- name: Log Notification Summary
shell: bash
run: |
echo "📊 Notification Summary:"
echo "Status: ${{ inputs.deployment_status }}"
echo "Environment: ${{ inputs.environment }}"
echo "Version: ${{ inputs.version }}"
echo "Webhook: ${{ inputs.webhook_url != '' && 'Sent' || 'Not configured' }}"
echo "Email: ${{ inputs.email_recipients != '' && 'Sent' || 'Not configured' }}"
echo "GitHub Issue: ${{ inputs.deployment_status == 'failure' && 'Created' || 'Not needed' }}"
81 changes: 81 additions & 0 deletions .github/actions/rollback-version/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: "Rollback Version"
description: "Rolls back version changes if deployment fails"

inputs:
github_token:
description: "GitHub token for authentication"
required: true
repository:
description: "Repository name in the format 'owner/repo'"
required: true
default: "${{ github.repository }}"
branch_name:
description: "Branch name to rollback changes on"
required: true
previous_version:
description: "Previous version to rollback to"
required: true
pubspec_path:
description: "Path to the pubspec.yaml file"
required: true
default: "apps/multichoice/pubspec.yaml"
rollback_reason:
description: "Reason for rollback"
required: false
default: "Deployment failed"

runs:
using: "composite"
steps:
- name: Checkout Branch
uses: actions/checkout@v4
with:
ref: ${{ inputs.branch_name }}
fetch-depth: 0
token: ${{ inputs.github_token }}

- name: Rollback Version
shell: bash
env:
GH_TOKEN: ${{ inputs.github_token }}
REPO: ${{ inputs.repository }}
run: |
previous_version="${{ inputs.previous_version }}"
rollback_reason="${{ inputs.rollback_reason }}"

# Validate previous version format
if ! echo "$previous_version" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-RC)?\+[0-9]+$'; then
echo "::error::Invalid previous version format: $previous_version"
exit 1
fi

# Check if file exists
if [[ ! -f "${{ inputs.pubspec_path }}" ]]; then
echo "::error::File not found: ${{ inputs.pubspec_path }}"
exit 1
fi

# Get current version
current_version=$(grep 'version:' ${{ inputs.pubspec_path }} | sed 's/version:[[:space:]]*//')
echo "Current version: $current_version"
echo "Rolling back to: $previous_version"

# Update pubspec.yaml with previous version
sed -i "s/version: .*/version: $previous_version/" ${{ inputs.pubspec_path }}

# Verify the change was made
if ! grep -q "version: $previous_version" "${{ inputs.pubspec_path }}"; then
echo "::error::Failed to rollback version in ${{ inputs.pubspec_path }}"
exit 1
fi

git config --global user.name 'VersionBumpingBot'
git config --global user.email '[email protected]'

git add ${{ inputs.pubspec_path }}
git commit -m "Rollback version to $previous_version - $rollback_reason [skip ci]"

git remote set-url origin https://x-access-token:${GH_TOKEN}@github.com/${REPO}.git
git push origin HEAD:${{ inputs.branch_name }}

echo "✅ Successfully rolled back version to $previous_version"
64 changes: 55 additions & 9 deletions .github/actions/version-management/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,22 +105,57 @@ runs:
version_suffix="${{ inputs.version_suffix }}"

echo "Comparing current_version ($current_version) with latest_tag ($latest_tag)"

# Extract version parts for comparison
current_version_part=$(echo "$current_version" | cut -d'+' -f1)
current_build_number=$(echo "$current_version" | cut -d'+' -f2)

# Validate current version format
if ! echo "$current_version_part" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-RC)?$'; then
echo "::error::Invalid version format: $current_version_part"
exit 1
fi

if ! echo "$current_build_number" | grep -qE '^[0-9]+$'; then
echo "::error::Invalid build number: $current_build_number"
exit 1
fi


# Function to handle version conflicts
handle_version_conflict() {
local max_retries=3
local retry_count=0

while [[ $retry_count -lt $max_retries ]]; do
echo "Attempt $((retry_count + 1)) of $max_retries to resolve version conflict"

# Fetch latest changes
git fetch origin ${{ inputs.branch_name }}
git reset --hard origin/${{ inputs.branch_name }}

# Get updated version
updated_version=$(grep 'version:' ${{ inputs.pubspec_path }} | sed 's/version:[[:space:]]*//')
if [[ "$updated_version" != "$current_version" ]]; then
echo "Version was updated by another process: $updated_version"
current_version="$updated_version"
current_version_part=$(echo "$current_version" | cut -d'+' -f1)
current_build_number=$(echo "$current_version" | cut -d'+' -f2)
break
fi

retry_count=$((retry_count + 1))
if [[ $retry_count -lt $max_retries ]]; then
echo "Waiting 5 seconds before retry..."
sleep 5
fi
done

if [[ $retry_count -eq $max_retries ]]; then
echo "::error::Failed to resolve version conflict after $max_retries attempts"
exit 1
fi
}

# Compare versions (handle case where latest_tag might be 0.0.0)
if [[ "$latest_tag" == "0.0.0" ]] || [[ "$current_version" > "$latest_tag" ]]; then
echo "Version in pubspec.yaml ($current_version) is ahead of latest tag ($latest_tag). Proceeding."
Expand All @@ -133,7 +168,13 @@ runs:
sed -i "s/version: .*/version: $new_version/" ${{ inputs.pubspec_path }}
git add ${{ inputs.pubspec_path }}
git commit -m "Add $version_suffix suffix to version $new_version [skip ci]"
git push origin HEAD:${{ inputs.branch_name }}

# Try to push, handle conflicts
if ! git push origin HEAD:${{ inputs.branch_name }}; then
echo "Push failed, attempting to resolve version conflict..."
handle_version_conflict
fi

current_version="$new_version"
current_version_part="$new_version_part"
fi
Expand Down Expand Up @@ -222,10 +263,15 @@ runs:
exit 1
}
git remote set-url origin https://x-access-token:${GH_TOKEN}@github.com/${REPO}.git
git push origin HEAD:${{ inputs.branch_name }} || {
echo "::error::Failed to push version bump to ${{ inputs.branch_name }}"
exit 1
}

# Try to push, handle conflicts
if ! git push origin HEAD:${{ inputs.branch_name }}; then
echo "Push failed, attempting to resolve version conflict..."
handle_version_conflict
# Re-run version bumping logic with updated version
echo "Re-running version bumping with updated version: $current_version"
exit 1 # This will trigger a retry of the action
fi

echo "version_part=$new_version" >> $GITHUB_OUTPUT
echo "build_number=$new_build_number" >> $GITHUB_OUTPUT
Expand Down
Loading
Loading