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