From 840378e0874d21db81657839c0c430f288851f82 Mon Sep 17 00:00:00 2001 From: Dmytro Sydorov Date: Mon, 30 Mar 2026 13:28:18 +0200 Subject: [PATCH] ci: add conflict-check reusable workflow Extracts the conflict-check workflow (detects unresolved merge conflict markers in PRs targeting release branches) as a reusable workflow_call. Source: identical workflow in loft-enterprise and vcluster. Changes from source: - SHA-pinned actions/checkout - Added persist-credentials: false on checkout - Parameterized GH_ACCESS_TOKEN as a workflow_call secret - Branch filters moved to callers (enterprise: release-** + v**, vcluster: v** only) --- .github/workflows/conflict-check.yaml | 77 +++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 .github/workflows/conflict-check.yaml diff --git a/.github/workflows/conflict-check.yaml b/.github/workflows/conflict-check.yaml new file mode 100644 index 0000000..2fbe10d --- /dev/null +++ b/.github/workflows/conflict-check.yaml @@ -0,0 +1,77 @@ +name: Check for unresolved conflicts + +on: + workflow_call: + secrets: + gh-access-token: + description: 'GitHub PAT for commenting on PRs' + required: true + +concurrency: + group: conflict-check-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + conflict-check: + runs-on: ubuntu-latest + timeout-minutes: 5 + name: Check for conflict markers + permissions: + pull-requests: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Find conflict markers + id: conflicts + run: | + # Look for git conflict markers: <<<<<<< followed by branch name + # Exclude vendor, node_modules, and common non-source directories + CONFLICTS=$(grep -rn "^<<<<<<< " \ + --include="*.go" --include="*.yaml" --include="*.yml" --include="*.json" \ + --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" \ + --include="*.py" --include="*.rb" --include="*.rs" --include="*.sh" \ + --include="*.md" --include="*.txt" \ + --exclude-dir=vendor --exclude-dir=node_modules --exclude-dir=.git \ + . 2>/dev/null || true) + + if [ -n "$CONFLICTS" ]; then + echo "found=true" >> "$GITHUB_OUTPUT" + echo "### Conflict markers found:" + echo "$CONFLICTS" + + # Save to file for PR comment + { + echo "## Unresolved Merge Conflicts Detected" + echo "" + echo "This PR contains unresolved merge conflict markers. Please resolve them before merging." + echo "" + echo "### Conflicted Files" + echo "" + echo '```' + echo "$CONFLICTS" + echo '```' + } > /tmp/conflict-report.md + else + echo "found=false" >> "$GITHUB_OUTPUT" + echo "No conflict markers found" + fi + + - name: Comment on PR + if: steps.conflicts.outputs.found == 'true' && github.event.pull_request.number + env: + GH_TOKEN: ${{ secrets.gh-access-token }} # zizmor: ignore[secrets-outside-env] -- PAT passed via workflow_call, not a repo secret + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + # Update existing comment or create new one + gh pr comment "$PR_NUMBER" --body-file /tmp/conflict-report.md --edit-last --create-if-none 2>/dev/null || \ + gh pr comment "$PR_NUMBER" --body-file /tmp/conflict-report.md + + - name: Fail if conflicts found + if: steps.conflicts.outputs.found == 'true' + run: | + echo "::error::Unresolved merge conflict markers found" + exit 1