|
1 | 1 | name: PR Intake Checks |
2 | 2 |
|
3 | 3 | on: |
4 | | - pull_request_target: |
5 | | - branches: [dev, main] |
6 | | - types: [opened, reopened, synchronize, edited, ready_for_review] |
7 | | - |
8 | | -concurrency: |
9 | | - group: pr-intake-checks-${{ github.event.pull_request.number || github.run_id }} |
10 | | - cancel-in-progress: true |
| 4 | + pull_request_target: |
| 5 | + types: [opened, synchronize, reopened] |
11 | 6 |
|
12 | 7 | permissions: |
13 | | - contents: read |
14 | | - pull-requests: write |
15 | | - issues: write |
| 8 | + contents: read |
| 9 | + pull-requests: write |
| 10 | + |
| 11 | +jobs: |
| 12 | + pr-intake: |
| 13 | + runs-on: ubuntu-latest |
| 14 | + steps: |
| 15 | + - uses: actions/checkout@v4 |
| 16 | + with: |
| 17 | + sparse-checkout: | |
| 18 | + .github |
| 19 | + sparse-checkout-cone-mode: false |
16 | 20 |
|
17 | | -env: |
18 | | - GIT_CONFIG_COUNT: "1" |
19 | | - GIT_CONFIG_KEY_0: core.hooksPath |
20 | | - GIT_CONFIG_VALUE_0: /dev/null |
| 21 | + - name: Check PR and post feedback |
| 22 | + uses: actions/github-script@v7 |
| 23 | + with: |
| 24 | + github-token: ${{ secrets.GITHUB_TOKEN }} |
| 25 | + script: | |
| 26 | + const { data: pr } = await github.rest.pulls.get({ |
| 27 | + owner: context.repo.owner, |
| 28 | + repo: context.repo.repo, |
| 29 | + pull_number: context.issue.number |
| 30 | + }); |
21 | 31 |
|
| 32 | + const body = pr.body || ''; |
| 33 | + const title = pr.title || ''; |
| 34 | + const warnings = []; |
| 35 | + const blocking = []; |
22 | 36 |
|
23 | | -jobs: |
24 | | - intake: |
25 | | - name: Intake Checks |
26 | | - runs-on: [self-hosted, Linux, X64, aws-india, blacksmith-2vcpu-ubuntu-2404, hetzner] |
27 | | - timeout-minutes: 10 |
28 | | - steps: |
29 | | - - name: Checkout repository |
30 | | - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 |
31 | | - |
32 | | - - name: Run safe PR intake checks |
33 | | - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 |
34 | | - with: |
35 | | - script: | |
36 | | - const script = require('./.github/workflows/scripts/pr_intake_checks.js'); |
37 | | - await script({ github, context, core }); |
| 37 | + // Check PR template sections |
| 38 | + const requiredSections = [ |
| 39 | + 'Summary', |
| 40 | + 'Problem statement', |
| 41 | + 'Proposed solution', |
| 42 | + 'Acceptance criteria' |
| 43 | + ]; |
| 44 | +
|
| 45 | + const missingSections = requiredSections.filter(section => |
| 46 | + !body.includes(section) |
| 47 | + ); |
| 48 | +
|
| 49 | + if (missingSections.length > 0) { |
| 50 | + warnings.push(`Missing sections: ${missingSections.join(', ')}`); |
| 51 | + } |
| 52 | +
|
| 53 | + // Check for issue reference |
| 54 | + if (!/#\d+/.test(body) && !/#\d+/.test(title)) { |
| 55 | + warnings.push('No issue reference found (recommended for traceability)'); |
| 56 | + } |
| 57 | +
|
| 58 | + // Check for large PR |
| 59 | + const { data: files } = await github.rest.pulls.listFiles({ |
| 60 | + owner: context.repo.owner, |
| 61 | + repo: context.repo.repo, |
| 62 | + pull_number: context.issue.number |
| 63 | + }); |
| 64 | +
|
| 65 | + const totalChanges = files.reduce((sum, f) => sum + f.additions + f.deletions, 0); |
| 66 | + if (totalChanges > 500) { |
| 67 | + warnings.push(`Large PR: ${totalChanges} lines changed`); |
| 68 | + } |
| 69 | +
|
| 70 | + // Check for merge conflicts |
| 71 | + for (const file of files) { |
| 72 | + if (file.patch && (file.patch.includes('<<<<<<<') || file.patch.includes('=======') || file.patch.includes('>>>>>>>'))) { |
| 73 | + blocking.push(`Merge conflicts in ${file.filename}`); |
| 74 | + } |
| 75 | + } |
| 76 | +
|
| 77 | + // Build comment |
| 78 | + let commentBody = ''; |
| 79 | + |
| 80 | + if (blocking.length > 0) { |
| 81 | + commentBody += '## PR Intake Checks - Blocking Issues\n\n'; |
| 82 | + commentBody += '❌ These issues must be resolved before merging:\n\n'; |
| 83 | + blocking.forEach(e => commentBody += `- ${e}\n`); |
| 84 | + commentBody += '\n---\n\n'; |
| 85 | + } |
| 86 | +
|
| 87 | + if (warnings.length > 0) { |
| 88 | + commentBody += '## PR Intake Checks - Warnings (non-blocking)\n\n'; |
| 89 | + commentBody += 'The following are recommendations:\n\n'; |
| 90 | + warnings.forEach(w => commentBody += `- ${w}\n`); |
| 91 | + } |
| 92 | +
|
| 93 | + if (commentBody) { |
| 94 | + await github.rest.issues.createComment({ |
| 95 | + owner: context.repo.owner, |
| 96 | + repo: context.repo.repo, |
| 97 | + issue_number: context.issue.number, |
| 98 | + body: commentBody |
| 99 | + }); |
| 100 | + } |
| 101 | +
|
| 102 | + if (blocking.length > 0) { |
| 103 | + core.setFailed('Blocking issues found in PR'); |
| 104 | + } |
0 commit comments