diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30d9cb0..d6c5e4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,6 +20,7 @@ on: pull_request: types: [opened, synchronize, reopened] branches: [main, master, develop] + merge_group: workflow_dispatch: permissions: diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml index 2c5b801..5abc0eb 100644 --- a/.github/workflows/pr-validation.yml +++ b/.github/workflows/pr-validation.yml @@ -8,17 +8,28 @@ on: branches: - main - master + merge_group: permissions: {} concurrency: - group: pr-validation-${{ github.event.pull_request.number }} + # #ASSUME github.event.pull_request.number is null under merge_group; + # fall back to github.ref (unique per merge-group ref) so a merge-group + # build never collides with, or is cancelled by, a PR build's group. + # #VERIFY confirm no cross-cancellation between a PR run and its + # corresponding merge-group run after the first live merge-queue pass. + group: pr-validation-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: title-check: name: PR Title Format runs-on: ubuntu-latest + # #CRITICAL github.event.pull_request.title is null under merge_group, + # so this check has nothing to validate there; restrict to pull_request. + # #VERIFY validate-dependencies below still reports success when this + # job is skipped under merge_group. + if: github.event_name == 'pull_request' permissions: pull-requests: read steps: @@ -45,6 +56,11 @@ jobs: body-check: name: PR Body Non-Empty runs-on: ubuntu-latest + # #CRITICAL github.event.pull_request.body is null under merge_group, + # so this check has nothing to validate there; restrict to pull_request. + # #VERIFY validate-dependencies below still reports success when this + # job is skipped under merge_group. + if: github.event_name == 'pull_request' permissions: pull-requests: read steps: @@ -82,18 +98,27 @@ jobs: TITLE_RESULT: ${{ needs.title-check.result }} BODY_RESULT: ${{ needs.body-check.result }} run: | - echo "## PR Validation Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "| Check | Result |" >> $GITHUB_STEP_SUMMARY - echo "|---|---|" >> $GITHUB_STEP_SUMMARY - echo "| PR Title Format | $TITLE_RESULT |" >> $GITHUB_STEP_SUMMARY - echo "| PR Body Non-Empty | $BODY_RESULT |" >> $GITHUB_STEP_SUMMARY - if [ "$TITLE_RESULT" != "success" ] || [ "$BODY_RESULT" != "success" ]; then + echo "## PR Validation Summary" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "| Check | Result |" >> "$GITHUB_STEP_SUMMARY" + echo "|---|---|" >> "$GITHUB_STEP_SUMMARY" + echo "| PR Title Format | $TITLE_RESULT |" >> "$GITHUB_STEP_SUMMARY" + echo "| PR Body Non-Empty | $BODY_RESULT |" >> "$GITHUB_STEP_SUMMARY" + # #CRITICAL a required status check for the merge queue; a + # merge_group build skips title-check/body-check by design + # (no PR title/body to read there), so "skipped" is accepted + # here on top of "success". A real "failure" still fails this + # gate under either event, so the gate is not weakened, only + # made compatible with the merge_group event. + # #VERIFY watch the first live merge-group run to confirm this + # context reports success instead of stalling the queue. + ok() { [ "$1" = "success" ] || [ "$1" = "skipped" ]; } + if ! ok "$TITLE_RESULT" || ! ok "$BODY_RESULT"; then echo "::error::One or more PR validation checks failed." exit 1 fi - echo "" >> $GITHUB_STEP_SUMMARY - echo "All PR validation checks passed." >> $GITHUB_STEP_SUMMARY + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "All PR validation checks passed." >> "$GITHUB_STEP_SUMMARY" validate-dependencies: # Aggregator named to satisfy the org ruleset @@ -115,19 +140,33 @@ jobs: TITLE_RESULT: ${{ needs.title-check.result }} BODY_RESULT: ${{ needs.body-check.result }} run: | - echo "## Dependency & Standards Validation" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - if [ "$TITLE_RESULT" = "success" ]; then - echo "Conventional Commits standard: Passed" >> $GITHUB_STEP_SUMMARY + echo "## Dependency & Standards Validation" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + # #CRITICAL required status check for the merge queue; a + # merge_group build skips title-check/body-check by design + # (no PR title/body to read there), so "skipped" is accepted + # here on top of "success" for each upstream job individually. + # A real "failure" still fails this gate under either event, so + # the gate is not weakened, only made compatible with the + # merge_group event. This aggregator currently only wraps + # title-check/body-check (no separate dependency-scan job feeds + # it on main); if a real scan job is added to this aggregator + # later, apply the same per-job success-or-skipped rule to it, + # never a blanket event-name bypass. + # #VERIFY watch the first live merge-group run to confirm this + # context reports success instead of stalling the queue. + ok() { [ "$1" = "success" ] || [ "$1" = "skipped" ]; } + if ok "$TITLE_RESULT"; then + echo "Conventional Commits standard: Passed" >> "$GITHUB_STEP_SUMMARY" else - echo "Conventional Commits standard: $TITLE_RESULT" >> $GITHUB_STEP_SUMMARY + echo "Conventional Commits standard: $TITLE_RESULT" >> "$GITHUB_STEP_SUMMARY" fi - if [ "$BODY_RESULT" = "success" ]; then - echo "PR Body standard: Passed" >> $GITHUB_STEP_SUMMARY + if ok "$BODY_RESULT"; then + echo "PR Body standard: Passed" >> "$GITHUB_STEP_SUMMARY" else - echo "PR Body standard: $BODY_RESULT" >> $GITHUB_STEP_SUMMARY + echo "PR Body standard: $BODY_RESULT" >> "$GITHUB_STEP_SUMMARY" fi - if [ "$TITLE_RESULT" != "success" ] || [ "$BODY_RESULT" != "success" ]; then + if ! ok "$TITLE_RESULT" || ! ok "$BODY_RESULT"; then echo "::error::Dependency and standards validation failed." exit 1 fi diff --git a/.github/workflows/reuse.yml b/.github/workflows/reuse.yml index 849a86b..e9d3bee 100644 --- a/.github/workflows/reuse.yml +++ b/.github/workflows/reuse.yml @@ -12,6 +12,7 @@ on: - "REUSE.toml" - "LICENSES/**" - ".github/workflows/reuse.yml" + merge_group: push: branches: - main diff --git a/.github/workflows/security-analysis.yml b/.github/workflows/security-analysis.yml index 91e5ca3..3c7e017 100644 --- a/.github/workflows/security-analysis.yml +++ b/.github/workflows/security-analysis.yml @@ -7,6 +7,7 @@ on: branches: [main, master] pull_request: branches: [main, master] + merge_group: schedule: # Weekly scan on Mondays at 09:00 UTC - cron: '0 9 * * 1'