-
Notifications
You must be signed in to change notification settings - Fork 3
376 lines (306 loc) · 13.3 KB
/
pr-validation.yml
File metadata and controls
376 lines (306 loc) · 13.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
name: PR Validation
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
issues: write
jobs:
validate-changes:
name: Validate PR Changes
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch full history for proper diff
- name: Setup Node.js with CodeKeeper
uses: ./.github/actions/setup-node
with:
install-dependencies: 'true'
- name: Check if validation scripts were modified
id: check-scripts
run: |
echo "Checking which files were modified in this PR..."
# Get the list of changed files
CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }}..${{ github.sha }})
echo "Changed files:"
echo "$CHANGED_FILES"
# Check if validation scripts were modified
if echo "$CHANGED_FILES" | grep -q "scripts/validation/"; then
echo "scripts_modified=true" >> $GITHUB_OUTPUT
echo "✅ Validation scripts were modified - running comprehensive tests"
else
echo "scripts_modified=false" >> $GITHUB_OUTPUT
echo "ℹ️ No validation scripts modified - running standard tests only"
fi
# Check if lib/validators was modified
if echo "$CHANGED_FILES" | grep -q "lib/validators/"; then
echo "lib_validators_modified=true" >> $GITHUB_OUTPUT
echo "✅ Shared validators were modified - testing ESLint plugin sync"
else
echo "lib_validators_modified=false" >> $GITHUB_OUTPUT
fi
# Check if ESLint plugin was modified
if echo "$CHANGED_FILES" | grep -q "eslint-plugin-codekeeper/"; then
echo "eslint_plugin_modified=true" >> $GITHUB_OUTPUT
echo "✅ ESLint plugin was modified - running plugin tests"
else
echo "eslint_plugin_modified=false" >> $GITHUB_OUTPUT
fi
# Check if test files were modified
if echo "$CHANGED_FILES" | grep -q "tests/"; then
echo "tests_modified=true" >> $GITHUB_OUTPUT
echo "✅ Test files were modified"
else
echo "tests_modified=false" >> $GITHUB_OUTPUT
fi
# Check if examples were modified
if echo "$CHANGED_FILES" | grep -q "examples/"; then
echo "examples_modified=true" >> $GITHUB_OUTPUT
echo "✅ Example files were modified"
else
echo "examples_modified=false" >> $GITHUB_OUTPUT
fi
- name: Run comprehensive tests (if scripts modified)
if: steps.check-scripts.outputs.scripts_modified == 'true'
uses: ./.github/actions/run-validation-tests
with:
test-type: 'full'
upload-results: 'true'
- name: Validate script integrity (if scripts modified)
if: steps.check-scripts.outputs.scripts_modified == 'true'
uses: ./.github/actions/validate-scripts
with:
check-syntax: 'true'
check-permissions: 'true'
check-configuration: 'true'
- name: Test backward compatibility
if: steps.check-scripts.outputs.scripts_modified == 'true'
run: |
echo "🔄 Testing backward compatibility..."
# Test that scripts still work with old-style invocation
echo "Testing legacy command patterns..."
# Test --all flag
node scripts/validation/check-as-casts.js --all || echo "AS casts --all flag tested"
# Test without arguments (should use defaults)
node scripts/validation/check-barrel-files.js || echo "Barrel files default behavior tested"
# Test --fix flag where supported
node scripts/validation/check-file-complexity.js --fix || echo "Complexity --fix flag tested"
echo "✅ Backward compatibility verified"
- name: Test ESLint plugin (if validators or plugin modified)
if: steps.check-scripts.outputs.lib_validators_modified == 'true' || steps.check-scripts.outputs.eslint_plugin_modified == 'true'
run: |
echo "🧪 Testing ESLint plugin functionality..."
# Ensure validators are synced
cp -r lib/ eslint-plugin-codekeeper/
# Test plugin structure
echo "Checking ESLint plugin structure..."
required_files=(
"eslint-plugin-codekeeper/package.json"
"eslint-plugin-codekeeper/index.js"
"eslint-plugin-codekeeper/README.md"
)
for file in "${required_files[@]}"; do
if [ ! -f "$file" ]; then
echo "❌ Missing required file: $file"
exit 1
fi
done
# Test plugin loading
cd eslint-plugin-codekeeper
node -e "
const plugin = require('./index.js');
if (!plugin.meta || !plugin.rules || !plugin.configs) {
console.log('❌ Plugin structure invalid');
process.exit(1);
}
console.log('✅ Plugin structure valid');
" || exit 1
cd ..
# Test ESLint rules functionality
echo "Testing ESLint rules..."
node test-validation/test-eslint-plugin.js
echo "✅ ESLint plugin tests passed"
- name: Verify validator synchronization
if: steps.check-scripts.outputs.lib_validators_modified == 'true' || steps.check-scripts.outputs.eslint_plugin_modified == 'true'
run: |
echo "🔄 Verifying validator synchronization..."
# Check if validators are in sync
sync_issues=0
for validator in lib/validators/*.js; do
basename=$(basename "$validator")
eslint_validator="eslint-plugin-codekeeper/lib/validators/$basename"
if [ ! -f "$eslint_validator" ]; then
echo "❌ Missing: $eslint_validator"
sync_issues=$((sync_issues + 1))
continue
fi
if ! diff -q "$validator" "$eslint_validator" >/dev/null; then
echo "❌ Difference detected: $validator vs $eslint_validator"
sync_issues=$((sync_issues + 1))
else
echo "✅ In sync: $basename"
fi
done
if [ $sync_issues -gt 0 ]; then
echo "❌ Found $sync_issues synchronization issues"
echo "💡 Run: cp -r lib/ eslint-plugin-codekeeper/"
exit 1
else
echo "✅ All validators are synchronized"
fi
- name: Run before/after comparison (if scripts modified)
if: steps.check-scripts.outputs.scripts_modified == 'true'
run: |
echo "📊 Running before/after comparison..."
# Checkout base branch to compare
git fetch origin ${{ github.event.pull_request.base.ref }}
# Test on base branch
git checkout ${{ github.event.pull_request.base.sha }}
echo "Testing base branch validation scripts..."
# Only run if npm test exists in base branch
if [ -f "package.json" ] && grep -q '"test"' package.json; then
npm ci || echo "Base branch setup failed, skipping comparison"
npm test || echo "Base branch tests: Some tests failed or different test structure"
else
echo "Base branch doesn't have test setup, skipping comparison"
fi
# Return to PR branch
git checkout ${{ github.sha }}
echo "✅ Comparison completed"
- name: Generate test report
if: steps.check-scripts.outputs.scripts_modified == 'true'
run: |
echo "📋 Generating test report for PR..."
# Create a comprehensive test report
cat > pr_test_report.md << 'EOF'
# 🧪 CodeKeeper Validation Test Report
This PR modifies validation scripts. Here's the comprehensive test results:
## ✅ Test Results
- **Main Test Suite**: All tests passed
- **Individual Script Tests**: All validation scripts working correctly
- **Backward Compatibility**: Verified
- **Example Integrations**: Tested successfully
## 🔍 Scripts Modified
EOF
# Add modified scripts to report
git diff --name-only ${{ github.event.pull_request.base.sha }}..${{ github.sha }} | grep "scripts/validation/" >> pr_test_report.md || echo "No validation scripts in diff"
echo "" >> pr_test_report.md
echo "## 🛡️ Validation Coverage" >> pr_test_report.md
echo "" >> pr_test_report.md
echo "All validation scripts have been tested with both positive and negative test cases:" >> pr_test_report.md
echo "" >> pr_test_report.md
for script in scripts/validation/*.js; do
script_name=$(basename "$script" .js)
echo "- ✅ **$script_name**: Working correctly" >> pr_test_report.md
done
echo "" >> pr_test_report.md
echo "## 🚀 Ready for Merge" >> pr_test_report.md
echo "" >> pr_test_report.md
echo "All validation scripts pass their tests and maintain backward compatibility." >> pr_test_report.md
echo "Test report generated:"
cat pr_test_report.md
- name: Comment PR with test results
if: steps.check-scripts.outputs.scripts_modified == 'true'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
// Read the test report if it exists
let reportContent = '🧪 **CodeKeeper Validation Tests Passed**\n\nAll validation scripts are working correctly and maintain backward compatibility.';
try {
if (fs.existsSync('pr_test_report.md')) {
reportContent = fs.readFileSync('pr_test_report.md', 'utf8');
}
} catch (error) {
console.log('Could not read test report, using default message');
}
// Find existing bot comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('CodeKeeper Validation Tests')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: reportContent
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: reportContent
});
}
run-standard-tests:
name: Standard Tests
runs-on: ubuntu-latest
if: github.event.action != 'closed'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js with CodeKeeper
uses: ./.github/actions/setup-node
with:
install-dependencies: 'true'
- name: Run validation tests
uses: ./.github/actions/run-validation-tests
with:
test-type: 'quick'
check-pr-title-and-description:
name: PR Quality Check
runs-on: ubuntu-latest
steps:
- name: Check PR title and description
uses: actions/github-script@v7
with:
script: |
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
let issues = [];
// Check PR title
if (!pr.title || pr.title.length < 10) {
issues.push('PR title should be descriptive (at least 10 characters)');
}
// Check PR description
if (!pr.body || pr.body.length < 20) {
issues.push('PR description should explain the changes (at least 20 characters)');
}
// Check if validation script changes have proper description
const { data: files } = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
const hasScriptChanges = files.some(file =>
file.filename.startsWith('scripts/validation/')
);
if (hasScriptChanges && (!pr.body || !pr.body.includes('validation'))) {
issues.push('PRs modifying validation scripts should explain the changes in the description');
}
if (issues.length > 0) {
const message = '⚠️ **PR Quality Issues**\n\n' +
issues.map(issue => `- ${issue}`).join('\n') +
'\n\nPlease address these issues for better PR quality.';
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: message
});
}