feat: add in copy of updated shared deployment workflows for now until they are
published
This commit is contained in:
parent
bcb7f86b7f
commit
e245bcbe96
12 changed files with 1113 additions and 0 deletions
45
.github/actions/determine-build-metadata/action.yml
vendored
Normal file
45
.github/actions/determine-build-metadata/action.yml
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
name: "Determine Build Metadata"
|
||||
description: "Extract repository metadata and build configuration from GitHub context"
|
||||
author: "Portfolio CI/CD"
|
||||
|
||||
inputs:
|
||||
repository:
|
||||
description: "Repository name in format owner/repo"
|
||||
required: true
|
||||
github-ref:
|
||||
description: "GitHub ref (e.g., refs/heads/main, refs/tags/v1.0.0)"
|
||||
required: true
|
||||
|
||||
outputs:
|
||||
repo-name:
|
||||
description: "Repository name only (without owner)"
|
||||
value: ${{ steps.meta.outputs.repo-name }}
|
||||
repo-path:
|
||||
description: "Server deployment path"
|
||||
value: ${{ steps.meta.outputs.repo-path }}
|
||||
prod:
|
||||
description: "Whether this is a production build (true/false)"
|
||||
value: ${{ steps.meta.outputs.prod }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu -o pipefail
|
||||
|
||||
REPO="${{ inputs.repository }}"
|
||||
REPO_NAME_ONLY="$(echo "${REPO}" | cut -d'/' -f2)"
|
||||
REPO_PROJECT_PATH="/srv/${REPO_NAME_ONLY}"
|
||||
PROD="${{ startsWith(inputs.github-ref, 'refs/heads/main') }}"
|
||||
|
||||
|
||||
echo "🖊️ Writing determined values:"
|
||||
echo "repo-name=$REPO_NAME_ONLY" >> $GITHUB_OUTPUT
|
||||
echo "repo-name -> $REPO_NAME_ONLY"
|
||||
echo "repo-path=$REPO_PROJECT_PATH" >> $GITHUB_OUTPUT
|
||||
echo "repo-path -> $REPO_PROJECT_PATH"
|
||||
echo "prod=$PROD" >> $GITHUB_OUTPUT
|
||||
echo "prod -> $PROD"
|
||||
57
.github/actions/push-to-origin/action.yml
vendored
Normal file
57
.github/actions/push-to-origin/action.yml
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
name: "Push to Git Origin"
|
||||
description: "Push branches and tags to Git origin repository"
|
||||
author: "Portfolio CI/CD"
|
||||
|
||||
inputs:
|
||||
git-origin-url:
|
||||
description: "Git origin repository URL (e.g., git@example.com:user/repo.git)"
|
||||
required: true
|
||||
branches:
|
||||
description: 'Space-separated list of branches to push (e.g., "main staging dev" or "staging")'
|
||||
required: true
|
||||
push-tags:
|
||||
description: "Whether to push tags along with branches"
|
||||
required: false
|
||||
default: "false"
|
||||
force:
|
||||
description: "Whether to force push"
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Setup Git Remotes
|
||||
shell: bash
|
||||
run: |
|
||||
echo "🔧 Setting up git remotes..."
|
||||
|
||||
git remote remove git-origin 2>/dev/null || true
|
||||
git remote add git-origin ${{ inputs.git-origin-url }}
|
||||
|
||||
echo "✅ git-origin remote configured"
|
||||
|
||||
- name: Push to Git Origin
|
||||
shell: bash
|
||||
run: |
|
||||
echo "📤 Pushing to Git Origin..."
|
||||
|
||||
PUSH_ARGS="${{ inputs.branches }}"
|
||||
|
||||
if [[ "${{ inputs.push-tags }}" == "true" ]]; then
|
||||
PUSH_ARGS="$PUSH_ARGS --tags"
|
||||
echo "🏷️ Including tags in Git origin push"
|
||||
fi
|
||||
|
||||
if [[ "${{ inputs.force }}" == "true" ]]; then
|
||||
PUSH_ARGS="$PUSH_ARGS --force"
|
||||
echo "🔥 Forcing push to Git origin"
|
||||
fi
|
||||
|
||||
if git push git-origin $PUSH_ARGS; then
|
||||
echo "✅ Successfully pushed to Git origin"
|
||||
else
|
||||
echo "❌ Failed to push to Git origin"
|
||||
echo "::warning::Push to Git origin failed, but GitHub push succeeded"
|
||||
exit 1
|
||||
fi
|
||||
78
.github/actions/setup-environment/action.yml
vendored
Normal file
78
.github/actions/setup-environment/action.yml
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
name: 'Setup Environment'
|
||||
description: 'Create environment files and variables for deployment'
|
||||
author: 'Portfolio CI/CD'
|
||||
|
||||
inputs:
|
||||
release-type:
|
||||
description: 'Release type (staging or prod)'
|
||||
required: true
|
||||
domain:
|
||||
description: 'Domain name'
|
||||
required: true
|
||||
android-sms-gateway-url:
|
||||
description: 'Android SMS Gateway URL'
|
||||
required: true
|
||||
android-sms-gateway-login:
|
||||
description: 'Android SMS Gateway login'
|
||||
required: true
|
||||
android-sms-gateway-password:
|
||||
description: 'Android SMS Gateway password'
|
||||
required: true
|
||||
my-phone-number:
|
||||
description: 'Phone number for SMS delivery'
|
||||
required: true
|
||||
super-secret-salt:
|
||||
description: 'Secret salt for TOTP generation'
|
||||
required: true
|
||||
wireguard-allowed-ips:
|
||||
description: 'WireGuard allowed IPs'
|
||||
required: true
|
||||
wireguard-private-key:
|
||||
description: 'WireGuard private key'
|
||||
required: true
|
||||
wireguard-addresses:
|
||||
description: 'WireGuard addresses'
|
||||
required: true
|
||||
wireguard-public-key:
|
||||
description: 'WireGuard public key'
|
||||
required: true
|
||||
wireguard-endpoint-host:
|
||||
description: 'WireGuard endpoint host'
|
||||
required: true
|
||||
wireguard-endpoint-port:
|
||||
description: 'WireGuard endpoint port'
|
||||
required: true
|
||||
prod:
|
||||
description: 'Whether this is a production deployment (true/false)'
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
outputs:
|
||||
env-file:
|
||||
description: 'Path to the created .env file'
|
||||
value: '.env'
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Create .env from secrets and environment variables
|
||||
shell: bash
|
||||
run: |
|
||||
echo "🔧 Creating environment configuration..."
|
||||
|
||||
echo "DOMAIN=\"${{ inputs.domain }}\"" > .env
|
||||
echo "NUXT_ANDROID_SMS_GATEWAY_URL=\"${{ inputs.android-sms-gateway-url }}\"" >> .env
|
||||
echo "NUXT_ANDROID_SMS_GATEWAY_LOGIN=\"${{ inputs.android-sms-gateway-login }}\"" >> .env
|
||||
echo "NUXT_ANDROID_SMS_GATEWAY_PASSWORD=\"${{ inputs.android-sms-gateway-password }}\"" >> .env
|
||||
echo "NUXT_MY_PHONE_NUMBER=\"${{ inputs.my-phone-number }}\"" >> .env
|
||||
echo "NUXT_SUPER_SECRET_SALT=\"${{ inputs.super-secret-salt }}\"" >> .env
|
||||
echo "WIREGUARD_ALLOWED_IPS=\"${{ inputs.wireguard-allowed-ips }}\"" >> .env
|
||||
echo "WIREGUARD_PRIVATE_KEY=\"${{ inputs.wireguard-private-key }}\"" >> .env
|
||||
echo "WIREGUARD_ADDRESSES=\"${{ inputs.wireguard-addresses }}\"" >> .env
|
||||
echo "WIREGUARD_PUBLIC_KEY=\"${{ inputs.wireguard-public-key }}\"" >> .env
|
||||
echo "WIREGUARD_ENDPOINT_HOST=\"${{ inputs.wireguard-endpoint-host }}\"" >> .env
|
||||
echo "WIREGUARD_ENDPOINT_PORT=\"${{ inputs.wireguard-endpoint-port }}\"" >> .env
|
||||
echo "RELEASE_TYPE=\"${{ inputs.release-type }}\"" >> .env
|
||||
echo "PROD=\"${{ inputs.prod }}\"" >> .env
|
||||
|
||||
echo "✅ Environment file created with $(wc -l < .env) variables"
|
||||
52
.github/actions/setup-git-ssh/action.yml
vendored
Normal file
52
.github/actions/setup-git-ssh/action.yml
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
name: "Setup Git SSH"
|
||||
description: "Configure SSH key and Git signing for commits and pushes"
|
||||
author: "Portfolio CI/CD"
|
||||
|
||||
inputs:
|
||||
commit-ssh-private-key:
|
||||
description: "SSH private key for commit signing"
|
||||
required: false
|
||||
push-ssh-private-key:
|
||||
description: "SSH private key for git-origin operations"
|
||||
required: false
|
||||
actor:
|
||||
description: "GitHub actor name for git user configuration"
|
||||
default: ""
|
||||
required: false
|
||||
actor-id:
|
||||
description: "GitHub actor ID for git email configuration"
|
||||
default: ""
|
||||
required: false
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Setup git user.name and user.email
|
||||
shell: bash
|
||||
run: |
|
||||
git config user.name "${{ inputs.actor != '' && inputs.actor || github.actor }}"
|
||||
git config user.email "${{ inputs.actor-id != '' && inputs.actor-id || github.actor_id }}+${{ inputs.actor != '' && inputs.actor || github.actor }}@users.noreply.github.com"
|
||||
- name: Setup SSH for key-based push
|
||||
shell: bash
|
||||
if: ${{ inputs.push-ssh-private-key != '' }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ inputs.push-ssh-private-key }}" > ~/.ssh/id-push
|
||||
chmod 600 ~/.ssh/id-push
|
||||
cat > ~/.ssh/config <<EOF
|
||||
Host *
|
||||
UserKnownHostsFile /dev/null
|
||||
StrictHostKeyChecking no
|
||||
IdentityFile $HOME/.ssh/id-push
|
||||
LogLevel QUIET
|
||||
EOF
|
||||
- name: Setup git for commit signing
|
||||
shell: bash
|
||||
if: ${{ inputs.commit-ssh-private-key != '' }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ inputs.commit-ssh-private-key }}" > ~/.ssh/id-commit
|
||||
chmod 600 ~/.ssh/id-commit
|
||||
git config gpg.format ssh
|
||||
git config user.signingkey ~/.ssh/id-commit
|
||||
git config commit.gpgsign true
|
||||
140
.github/actions/validate-build-status/action.yml
vendored
Normal file
140
.github/actions/validate-build-status/action.yml
vendored
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
name: "Validate Build Status"
|
||||
description: "Validate that a build workflow has completed successfully for a specific branch and commit"
|
||||
author: "Portfolio CI/CD"
|
||||
|
||||
inputs:
|
||||
from-branch:
|
||||
description: "Name of the branch to check (e.g., dev, staging)"
|
||||
required: true
|
||||
to-branch:
|
||||
description: "Base branch to compare against (e.g., staging, main)"
|
||||
required: true
|
||||
job-name:
|
||||
description: "Name of the build job to check"
|
||||
required: true
|
||||
workflow-name:
|
||||
description: "Name of the workflow to check"
|
||||
required: false
|
||||
default: "Build/Deploy"
|
||||
force:
|
||||
description: "Force validation even if other conditions fail"
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
outputs:
|
||||
should-proceed:
|
||||
description: "Whether the validation passed and should proceed"
|
||||
value: ${{ steps.validation.outputs.should_proceed }}
|
||||
commits-ahead:
|
||||
description: "Number of commits ahead of comparison branch"
|
||||
value: ${{ steps.validation.outputs.commits_ahead }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Run validation checks
|
||||
id: validation
|
||||
shell: bash
|
||||
run: |
|
||||
echo "🔍 Running build validation checks for ${{ inputs.from-branch }}..."
|
||||
|
||||
# Check if there are new commits in branch since last comparison
|
||||
git checkout ${{ inputs.from-branch }}
|
||||
# git fetch --tags
|
||||
# git pull --tags
|
||||
COMMITS_AHEAD=$(git rev-list --count origin/${{ inputs.to-branch }}..${{ inputs.from-branch }})
|
||||
echo "📊 Commits ahead of ${{ inputs.to-branch }}: $COMMITS_AHEAD"
|
||||
echo "commits_ahead=$COMMITS_AHEAD" >> $GITHUB_OUTPUT
|
||||
|
||||
if [[ "${{ inputs.force }}" == "true" ]]; then
|
||||
echo "⚡ Force flag enabled - skipping all validation checks"
|
||||
echo "should_proceed=true" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$COMMITS_AHEAD" -eq 0 ]; then
|
||||
echo "ℹ️ No new commits to process"
|
||||
echo "should_proceed=false" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check for any [skip ci] in recent commit messages
|
||||
SKIP_CI=$(git log --oneline origin/${{ inputs.to-branch }}..${{ inputs.from-branch }} | grep -i "\[skip ci\]" || true)
|
||||
if [ -n "$SKIP_CI" ]; then
|
||||
echo "⏭️ Skipping processing due to [skip ci] flag in commits"
|
||||
echo "should_proceed=false" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get the actual branch HEAD commit
|
||||
COMMIT_SHA=$(git rev-parse ${{ inputs.from-branch }})
|
||||
echo "🔍 Checking build job status for ${{ inputs.from-branch }} commit: $COMMIT_SHA"
|
||||
|
||||
# Get workflow runs for the specific commit
|
||||
echo "🔍 Querying GitHub API for workflow runs..."
|
||||
RUNS_RESPONSE=$(curl -s -H "Authorization: Bearer ${{ github.token }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/actions/runs?head_sha=${COMMIT_SHA}")
|
||||
|
||||
# Check if API call was successful
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ Failed to call GitHub API"
|
||||
echo "::error::GitHub API call failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if response contains total_count
|
||||
WORKFLOW_RUNS_COUNT=$(echo "$RUNS_RESPONSE" | jq -r '.total_count' 2>/dev/null || echo "error")
|
||||
|
||||
if [ "$WORKFLOW_RUNS_COUNT" = "error" ] || [ "$WORKFLOW_RUNS_COUNT" = "null" ]; then
|
||||
echo "❌ Invalid API response format"
|
||||
echo "API Response: $RUNS_RESPONSE"
|
||||
echo "::error::Invalid response from GitHub API"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📊 Found $WORKFLOW_RUNS_COUNT workflow run(s) for commit $COMMIT_SHA"
|
||||
|
||||
# Extract run ID for build_deploy.yml workflow (safely handle empty results)
|
||||
BUILD_RUN_ID=$(echo "$RUNS_RESPONSE" | jq -r '.workflow_runs[] | select(.name == "${{ inputs.workflow-name }}") | .id' 2>/dev/null | head -1)
|
||||
|
||||
# Remove any whitespace/newlines
|
||||
BUILD_RUN_ID=$(echo "$BUILD_RUN_ID" | tr -d '\n\r ')
|
||||
|
||||
if [ -z "$BUILD_RUN_ID" ] || [ "$BUILD_RUN_ID" = "null" ]; then
|
||||
echo "❌ No build workflow run found for commit ${COMMIT_SHA}"
|
||||
echo "::error::Expected build workflow run not found - this indicates a problem with the CI/CD pipeline"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Found build workflow run: $BUILD_RUN_ID"
|
||||
|
||||
# Get jobs for the workflow run
|
||||
JOBS_RESPONSE=$(curl -s -H "Authorization: Bearer ${{ github.token }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/actions/runs/${BUILD_RUN_ID}/jobs")
|
||||
|
||||
# Find the build job status
|
||||
BUILD_JOB_STATUS=$(echo "$JOBS_RESPONSE" | jq -r '.jobs[] | select(.name == "${{ inputs.job-name }}") | .status')
|
||||
BUILD_JOB_CONCLUSION=$(echo "$JOBS_RESPONSE" | jq -r '.jobs[] | select(.name == "${{ inputs.job-name }}") | .conclusion')
|
||||
|
||||
echo "📊 Build job status: $BUILD_JOB_STATUS, conclusion: $BUILD_JOB_CONCLUSION"
|
||||
|
||||
if [ "$BUILD_JOB_STATUS" = "completed" ] && ([ "$BUILD_JOB_CONCLUSION" = "success" ] || [ "$BUILD_JOB_CONCLUSION" = "skipped" ]); then
|
||||
if [ "$BUILD_JOB_CONCLUSION" = "skipped" ]; then
|
||||
echo "✅ Build job skipped (artifact already exists)!"
|
||||
else
|
||||
echo "✅ Build job completed successfully!"
|
||||
fi
|
||||
else
|
||||
echo "❌ Build job not successful (status: $BUILD_JOB_STATUS, conclusion: $BUILD_JOB_CONCLUSION)"
|
||||
echo "🔗 View job details: https://github.com/${{ github.repository }}/actions/runs/${BUILD_RUN_ID}"
|
||||
echo "If job is in_progress, wait for it to complete, then re-run this workflow"
|
||||
echo "should_proceed=false" >> $GITHUB_OUTPUT
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ No blockers, ready to proceed"
|
||||
echo "should_proceed=true" >> $GITHUB_OUTPUT
|
||||
Loading…
Add table
Add a link
Reference in a new issue