Skip to content

chore: align MVP docs and FeatureServer updates (#252) #230

chore: align MVP docs and FeatureServer updates (#252)

chore: align MVP docs and FeatureServer updates (#252) #230

Workflow file for this run

name: PR Validation
on:
pull_request:
types: [opened, edited, synchronize, reopened]
jobs:
validate-pr:
name: Validate PR Template Compliance
if: ${{ github.event.pull_request.user.login != 'dependabot[bot]' }}
runs-on: ubuntu-latest
permissions:
pull-requests: write
issues: read
steps:
- name: Check PR Template Compliance
uses: actions/github-script@v8
with:
script: |
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
const body = pr.body || '';
const title = pr.title || '';
console.log('Validating PR:', title);
console.log('PR body length:', body.length);
const issues = [];
const warnings = [];
// Check 1: Issue link requirement
const hasIssueLink = /(?:Fixes|Closes|Resolves|Related to)\s+#\d+/i.test(body);
if (!hasIssueLink) {
issues.push('❌ **Missing issue link** - Please include "Fixes #123" or similar');
}
// Check 2: Summary section
const summaryMatch = body.match(/## Summary\s*(?:\s*<!--.*?-->\s*)?\n\s*(.*?)\n/s);
if (!summaryMatch || !summaryMatch[1].trim()) {
issues.push('❌ **Empty summary** - Please describe what this PR does');
}
// Check 3: Changes Made section
const changesMatch = body.match(/## Changes Made\s*(?:\s*<!--.*?-->\s*)?\n(.*?)(?=\n##|\n---|\n$)/s);
if (!changesMatch || !changesMatch[1].includes('-') || changesMatch[1].trim().length < 10) {
issues.push('❌ **Changes Made incomplete** - Please list key changes with bullet points');
}
// Check 4: Testing checklist
const testingChecked = body.match(/- \[x\]/i);
if (!testingChecked) {
warnings.push('⚠️ **No testing boxes checked** - Please indicate testing completed');
}
// Check 5: Pre-PR checklist
const preChecklistComplete = body.match(/## Pre-PR Checklist[\s\S]*?- \[x\].*scripts\/pre-pr-check\.sh/i);
if (!preChecklistComplete) {
issues.push('❌ **Pre-PR validation not confirmed** - Please run `scripts/pre-pr-check.sh` and check the box');
}
// Check 6: Breaking changes addressed
const hasBreakingSection = body.includes('## Breaking Changes');
if (!hasBreakingSection) {
warnings.push('⚠️ **Missing Breaking Changes section** - Template may be outdated');
}
// Check 7: Commit message format (check title)
const titleFormat = /^(feat|fix|docs|style|refactor|test|chore|ci|perf)(\([^)]+\))?: .+( \(#\d+\))?$/i;
if (!titleFormat.test(title)) {
issues.push('❌ **PR title format** - Should be "type: description (#issue)" (e.g., "feat: add login endpoint (#123)")');
}
// Generate comment
let comment = '## 🤖 PR Template Validation\n\n';
if (issues.length === 0 && warnings.length === 0) {
comment += '✅ **All checks passed!** Your PR follows the template correctly.\n\n';
comment += '**Next steps:**\n';
comment += '- Wait for CI to complete\n';
comment += '- Address any feedback from LLM architecture review\n';
comment += '- Request review from team members\n';
} else {
if (issues.length > 0) {
comment += '### ❌ Issues (must fix)\n\n';
issues.forEach(issue => comment += `${issue}\n\n`);
}
if (warnings.length > 0) {
comment += '### ⚠️ Warnings (recommended fixes)\n\n';
warnings.forEach(warning => comment += `${warning}\n\n`);
}
comment += '### 📚 Helpful Links\n';
comment += '- [PR Template Guide](../blob/trunk/.github/pull_request_template.md)\n';
comment += '- [Pre-PR Validation](../blob/trunk/scripts/pre-pr-check.sh)\n';
comment += '- [Commit Message Format](../blob/trunk/CLAUDE.md#commit-guidelines)\n\n';
comment += '💡 **Tip:** Edit your PR description to address these issues and this check will re-run automatically.\n';
}
comment += '\n---\n*Automated validation powered by GitHub Actions*';
// Check if we already have a validation comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number
});
const existingComment = comments.find(comment =>
comment.body.includes('🤖 PR Template Validation')
);
if (existingComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.id,
body: comment
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: comment
});
}
// Set status
if (issues.length > 0) {
core.setFailed(`PR template validation failed: ${issues.length} issues found`);
} else {
console.log(`✅ PR template validation passed (${warnings.length} warnings)`);
}