From b987a917d32f1aa586877f75247b2b0805b842de Mon Sep 17 00:00:00 2001 From: Kevin Brown Date: Mon, 15 Dec 2025 15:21:26 +0300 Subject: [PATCH 1/3] Add 'dependabot' as valid branch in workflows --- .github/workflows/branch-protection.yml | 3 ++- .husky/scripts/check-branch-name.sh | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/branch-protection.yml b/.github/workflows/branch-protection.yml index 8dbb1b010..637da8bee 100644 --- a/.github/workflows/branch-protection.yml +++ b/.github/workflows/branch-protection.yml @@ -19,7 +19,7 @@ jobs: : "${BRANCH_NAME:?github.head_ref is required}" # Valid patterns: bugfix/, hotfix/, feature/, infrastructure/, maintenance/, content/ - if [[ ! $BRANCH_NAME =~ ^(bugfix|hotfix|feature|infrastructure|maintenance|content)/[a-z0-9-]+$ ]]; then + if [[ ! $BRANCH_NAME =~ ^(bugfix|hotfix|feature|infrastructure|maintenance|content|dependabot)/[a-z0-9-]+$ ]]; then echo "❌ Invalid branch name: $BRANCH_NAME" echo "" echo "Branch names must follow one of these patterns:" @@ -29,6 +29,7 @@ jobs: echo " - infrastructure/ (e.g., infrastructure/setup-ci)" echo " - maintenance/ (e.g., maintenance/update-dependencies)" echo " - content/ (e.g., content/update-about-page)" + echo " - dependabot/ (machine generated)" echo "" echo "Use lowercase letters, numbers, and hyphens only." exit 1 diff --git a/.husky/scripts/check-branch-name.sh b/.husky/scripts/check-branch-name.sh index 0cb9d9f8e..a624f1f95 100755 --- a/.husky/scripts/check-branch-name.sh +++ b/.husky/scripts/check-branch-name.sh @@ -4,7 +4,7 @@ branch=$(git symbolic-ref --short HEAD) # Define valid branch name patterns -valid_patterns="^(bugfix|hotfix|feature|infrastructure|content|maintenance)\/[a-z0-9-]+$" +valid_patterns="^(bugfix|hotfix|feature|infrastructure|content|maintenance|dependabot)\/[a-z0-9-]+$" # Allow main and develop branches (for merges) if [ "$branch" = "main" ] || [ "$branch" = "develop" ]; then @@ -22,6 +22,7 @@ if ! echo "$branch" | grep -Eq "$valid_patterns"; then echo " - infrastructure/ (e.g., infrastructure/setup-ci)" echo " - maintenance/ (e.g., maintenance/update-dependencies)" echo " - content/ (e.g., content/update-about-page)" + echo " - dependabot/ (machine generated)" echo "" echo "Use lowercase letters, numbers, and hyphens only." echo "" From 94a5107f79ace5b6cfa83fa313c9390238a25abf Mon Sep 17 00:00:00 2001 From: Kevin Brown Date: Mon, 15 Dec 2025 15:30:23 +0300 Subject: [PATCH 2/3] Skip CodeQL checks on hotfix branches --- .github/workflows/codeql.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8f7d74ed8..81c2d7e0a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -12,6 +12,7 @@ on: jobs: analyze: name: Analyze Code + if: github.event_name != 'pull_request' || !startsWith(github.head_ref, 'hotfix/') runs-on: ubuntu-latest permissions: actions: read From b4a16efa724f77b86f9c98d0a4789204d1b4f803 Mon Sep 17 00:00:00 2001 From: Kevin Brown Date: Mon, 15 Dec 2025 15:52:43 +0300 Subject: [PATCH 3/3] Skip deploy to preview gating on hotfix branches --- .github/workflows/deployment.yml | 109 +++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 41807fe5b..cdb2cfdc6 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -12,6 +12,7 @@ permissions: pull-requests: write issues: write deployments: write + checks: write jobs: verify-ci: @@ -24,14 +25,15 @@ jobs: uses: actions/github-script@v8 with: script: | + const runId = context.payload.workflow_run.id; const workflowRun = context.payload.workflow_run; - const headBranch = workflowRun?.head_branch; - if (typeof headBranch === 'string' && headBranch.startsWith('hotfix/')) { - core.info('hotfix/* branch detected; skipping CI job verification.'); + const branch = workflowRun?.head_branch ?? ''; + const isHotfix = branch.startsWith('hotfix/'); + if (workflowRun?.event === 'pull_request' && isHotfix) { + core.notice('Hotfix branch: skipping CI verification requirements.'); return; } - const runId = workflowRun.id; const requiredJobs = ['Lint', 'Unit Tests']; const { data } = await github.rest.actions.listJobsForWorkflowRun({ owner: context.repo.owner, @@ -57,7 +59,11 @@ jobs: if: >- needs.verify-ci.result == 'success' && github.event.workflow_run.conclusion == 'success' && - github.event.workflow_run.event == 'pull_request' + github.event.workflow_run.event == 'pull_request' && + !startsWith(github.event.workflow_run.head_branch, 'hotfix/') + + outputs: + previewUrl: ${{ steps.vercel-preview.outputs.preview-url }} steps: - name: Hotfix branch — skip preview deploy @@ -373,6 +379,99 @@ jobs: body: `❌ Preview deployment failed.${linkLine}\n\nPlease review the Vercel build logs for details.` }); + publish-preview-status: + name: Publish Preview Status + runs-on: ubuntu-latest + needs: + - verify-ci + - deploy-preview + if: always() && github.event.workflow_run.event == 'pull_request' + steps: + - name: Publish required check run + uses: actions/github-script@v8 + env: + VERIFY_RESULT: ${{ needs.verify-ci.result }} + DEPLOY_RESULT: ${{ needs.deploy-preview.result }} + PREVIEW_URL: ${{ needs.deploy-preview.outputs.previewUrl }} + with: + script: | + const workflowRun = context.payload.workflow_run; + const sha = workflowRun?.head_sha; + if (!sha) { + core.warning('Missing workflow_run.head_sha; cannot publish check run.'); + return; + } + + const branch = workflowRun?.head_branch ?? ''; + const isHotfix = branch.startsWith('hotfix/'); + const verifyResult = process.env.VERIFY_RESULT || 'unknown'; + const deployResult = process.env.DEPLOY_RESULT || 'unknown'; + const previewUrl = (process.env.PREVIEW_URL || '').trim(); + + const checkName = 'Deploy Preview to Vercel'; + const detailsUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + + let conclusion = 'success'; + let summary = ''; + + if (isHotfix) { + conclusion = 'success'; + summary = 'Hotfix branch: preview deploy intentionally skipped.'; + } else if (verifyResult !== 'success') { + conclusion = 'failure'; + summary = `CI verification failed (${verifyResult}).`; + } else if (deployResult === 'success') { + conclusion = 'success'; + summary = previewUrl ? `Preview deployed: ${previewUrl}` : 'Preview deployed.'; + } else { + conclusion = 'failure'; + summary = `Preview deployment failed (${deployResult}).`; + } + + const output = { + title: checkName, + summary: `${summary}\n\nDetails: ${detailsUrl}` + }; + + const owner = context.repo.owner; + const repo = context.repo.repo; + const completed_at = new Date().toISOString(); + + const { data } = await github.rest.checks.listForRef({ + owner, + repo, + ref: sha, + filter: 'latest', + per_page: 100 + }); + + const existing = (data.check_runs || []).find((run) => run.name === checkName); + if (existing) { + await github.rest.checks.update({ + owner, + repo, + check_run_id: existing.id, + status: 'completed', + conclusion, + completed_at, + output, + details_url: detailsUrl + }); + return; + } + + await github.rest.checks.create({ + owner, + repo, + name: checkName, + head_sha: sha, + status: 'completed', + conclusion, + completed_at, + output, + details_url: detailsUrl + }); + deploy-production: name: Deploy to Production (Vercel) runs-on: ubuntu-latest