Skip to content

Commit 1405875

Browse files
CopilotBorDevTech
andcommitted
Fix lint automation duplication and enhance issue titles
Co-authored-by: BorDevTech <73800053+BorDevTech@users.noreply.github.com>
1 parent c5148bb commit 1405875

3 files changed

Lines changed: 123 additions & 127 deletions

File tree

.github/workflows/lint-automation.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
name: 🔧 Automated Lint Issue Detection
22

33
on:
4+
# Run on push to main/develop branches
45
push:
56
branches: [ main, develop ]
7+
# Run on pull requests to main
68
pull_request:
79
branches: [ main ]
10+
# Run after Next.js workflow completion on main branch
11+
workflow_run:
12+
workflows: ["Deploy Next.js site to Pages"]
13+
types:
14+
- completed
15+
branches: [ main ]
16+
# Manual trigger for testing
817
workflow_dispatch:
918
inputs:
1019
create_issues:

.github/workflows/nextjs.yml

Lines changed: 2 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -86,120 +86,8 @@ jobs:
8686
with:
8787
path: ./out
8888

89-
# Lint analysis job - runs when build fails
90-
lint-analysis-on-failure:
91-
runs-on: ubuntu-latest
92-
needs: build
93-
if: needs.build.outputs.build-success != 'true'
94-
name: 🔍 Analyze Build Failures
95-
96-
steps:
97-
- name: 📦 Checkout repository
98-
uses: actions/checkout@v4
99-
100-
- name: 🟢 Setup Node.js
101-
uses: actions/setup-node@v4
102-
with:
103-
node-version: '20'
104-
cache: 'npm'
105-
106-
- name: 📥 Install dependencies
107-
run: npm ci
108-
109-
- name: 🔍 Run comprehensive lint analysis
110-
id: analyze
111-
run: |
112-
echo "🔍 Running lint analysis to identify build failures..."
113-
114-
# Run the enhanced lint analyzer that includes TypeScript checks
115-
npx tsx scripts/lint-automation/lint-analyzer.ts || true
116-
117-
# Check if we generated a report and if there are any issues
118-
if [ -f "lint-analysis-report.json" ]; then
119-
ISSUES_COUNT=$(jq '.summary.totalIssues' lint-analysis-report.json)
120-
echo "issues-count=${ISSUES_COUNT}" >> $GITHUB_OUTPUT
121-
122-
if [ "${ISSUES_COUNT}" -gt "0" ]; then
123-
echo "has-issues=true" >> $GITHUB_OUTPUT
124-
echo "📊 Found ${ISSUES_COUNT} issues causing build failure"
125-
else
126-
echo "has-issues=false" >> $GITHUB_OUTPUT
127-
echo "🤔 Build failed but no lint/TypeScript issues found"
128-
fi
129-
else
130-
echo "has-issues=false" >> $GITHUB_OUTPUT
131-
echo "issues-count=0" >> $GITHUB_OUTPUT
132-
echo "❌ Could not analyze build failure"
133-
fi
134-
135-
- name: 📄 Upload build failure analysis
136-
if: steps.analyze.outputs.has-issues == 'true'
137-
uses: actions/upload-artifact@v4
138-
with:
139-
name: build-failure-analysis-${{ github.run_number }}
140-
path: |
141-
lint-analysis-report.json
142-
lint-analysis-report.md
143-
retention-days: 30
144-
145-
- name: 🎯 Create GitHub issues for build failures
146-
if: steps.analyze.outputs.has-issues == 'true'
147-
env:
148-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
149-
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
150-
GITHUB_REPOSITORY_NAME: ${{ github.event.repository.name }}
151-
run: |
152-
echo "📝 Creating GitHub issues for build failures..."
153-
npx tsx scripts/lint-automation/github-issue-creator.ts
154-
155-
- name: 💬 Add deployment failure comment
156-
if: steps.analyze.outputs.has-issues == 'true'
157-
uses: actions/github-script@v7
158-
with:
159-
script: |
160-
const fs = require('fs');
161-
162-
try {
163-
const report = JSON.parse(fs.readFileSync('lint-analysis-report.json', 'utf8'));
164-
165-
// Find the most recent commit
166-
const { data: commits } = await github.rest.repos.listCommits({
167-
owner: context.repo.owner,
168-
repo: context.repo.repo,
169-
sha: context.sha,
170-
per_page: 1
171-
});
172-
173-
const comment = `## 🚨 Next.js Deployment Failed
174-
175-
**Build failed with ${report.summary.totalIssues} issues:**
176-
- ❌ ${report.summary.errorCount} errors
177-
- ⚠️ ${report.summary.warningCount} warnings
178-
- 📁 ${report.summary.affectedFiles} files affected
179-
180-
### 🔧 Most Common Issues:
181-
${report.summary.commonPatterns.map(p => `- ${p}`).join('\n')}
182-
183-
### 🎯 Immediate Actions Required:
184-
${report.recommendations.immediate.map(r => `- [ ] ${r}`).join('\n')}
185-
186-
**📊 Full analysis report:** See workflow artifacts for detailed breakdown.
187-
188-
**🤖 GitHub Issues:** Individual issues have been created for each problem to track resolution.
189-
190-
---
191-
*Automated deployment failure analysis - Commit: ${context.sha.substring(0, 7)}*`;
192-
193-
// Create a commit comment
194-
await github.rest.repos.createCommitComment({
195-
owner: context.repo.owner,
196-
repo: context.repo.repo,
197-
commit_sha: context.sha,
198-
body: comment
199-
});
200-
} catch (error) {
201-
console.log('Could not post commit comment:', error.message);
202-
}
89+
# Note: Lint analysis is now handled by the dedicated lint-automation workflow
90+
# This prevents duplicate issue creation and ensures proper workflow coordination
20391

20492
# Deployment job - only runs if build succeeds
20593
deploy:

scripts/lint-automation/github-issue-creator.ts

Lines changed: 112 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -459,11 +459,13 @@ All instances of \`${ruleId}\` violations have been fixed. This issue is now aut
459459
const category = fileIssues[0].category;
460460
const severity = fileIssues.some(issue => issue.severity === 'error') ? 'error' : 'warning';
461461

462-
// Create title using filename as requested by user
462+
// Create enhanced title with region context for API verify files
463+
const enhancedTitle = this.generateEnhancedTitle(filePath, fileName);
464+
463465
groups.push({
464466
category,
465-
title: fileName,
466-
body: this.generateFileIssueBody(fileName, filePath, fileIssues),
467+
title: enhancedTitle,
468+
body: this.generateFileIssueBody(enhancedTitle, filePath, fileIssues),
467469
labels: [
468470
'lint',
469471
'code-quality',
@@ -477,6 +479,67 @@ All instances of \`${ruleId}\` violations have been fixed. This issue is now aut
477479
return groups;
478480
}
479481

482+
/**
483+
* Generates an enhanced title that includes region context for API verify files
484+
* @param filePath - Full path to the file
485+
* @param fileName - Base filename
486+
* @returns Enhanced title with region context if applicable
487+
*/
488+
private generateEnhancedTitle(filePath: string, fileName: string): string {
489+
// Check if this is a file in the API verify directory structure
490+
const apiVerifyMatch = filePath.match(/app\/api\/verify\/([^\/]+)\/(.+)$/);
491+
492+
if (apiVerifyMatch) {
493+
const regionFolder = apiVerifyMatch[1];
494+
const fileInRegion = apiVerifyMatch[2];
495+
496+
// Convert region folder name to proper case for display
497+
// e.g., "arizona" -> "Arizona", "districtofcolumbia" -> "District of Columbia"
498+
const regionName = this.formatRegionName(regionFolder);
499+
500+
return `${regionName} - ${fileInRegion}`;
501+
}
502+
503+
// For non-API verify files, return the original filename
504+
return fileName;
505+
}
506+
507+
/**
508+
* Formats region folder names into proper display names
509+
* @param regionFolder - Raw folder name (e.g., "arizona", "districtofcolumbia")
510+
* @returns Formatted region name (e.g., "Arizona", "District of Columbia")
511+
*/
512+
private formatRegionName(regionFolder: string): string {
513+
// Handle special cases
514+
const specialCases: Record<string, string> = {
515+
'districtofcolumbia': 'District of Columbia',
516+
'newhampshire': 'New Hampshire',
517+
'newjersey': 'New Jersey',
518+
'newmexico': 'New Mexico',
519+
'newyork': 'New York',
520+
'northcarolina': 'North Carolina',
521+
'northdakota': 'North Dakota',
522+
'rhodeisland': 'Rhode Island',
523+
'southcarolina': 'South Carolina',
524+
'southdakota': 'South Dakota',
525+
'westvirginia': 'West Virginia',
526+
'britishcolumbia': 'British Columbia',
527+
'newbrunswick': 'New Brunswick',
528+
'newfoundland&labrador': 'Newfoundland & Labrador',
529+
'novascotia': 'Nova Scotia',
530+
'princeedwardisland': 'Prince Edward Island',
531+
'puertorico': 'Puerto Rico'
532+
};
533+
534+
// Check for special cases first
535+
if (specialCases[regionFolder.toLowerCase()]) {
536+
return specialCases[regionFolder.toLowerCase()];
537+
}
538+
539+
// For regular cases, just capitalize the first letter
540+
return regionFolder.charAt(0).toUpperCase() + regionFolder.slice(1);
541+
}
542+
480543
private generateSummaryIssueBody(report: IssueReport): string {
481544
let body = `## 📊 Lint Analysis Summary\n\n`;
482545

@@ -681,14 +744,18 @@ All instances of \`${ruleId}\` violations have been fixed. This issue is now aut
681744
return body;
682745
}
683746

684-
async checkExistingFileIssue(fileName: string): Promise<{ number: number; title: string; body: string } | null> {
747+
async checkExistingFileIssue(enhancedTitle: string): Promise<{ number: number; title: string; body: string } | null> {
685748
if (!this.token) return null;
686749

687750
try {
688-
// Search for issues with the filename as title
689-
const searchQuery = `repo:${this.owner}/${this.repo}+is:issue+is:open+"${fileName}"+label:lint+label:automated`;
751+
// Search for issues with the enhanced title or just the filename
752+
// This handles both old format (just filename) and new format (Region - filename)
753+
const fileNamePart = enhancedTitle.includes(' - ') ? enhancedTitle.split(' - ')[1] : enhancedTitle;
690754

691-
const response = await fetch(
755+
// First try exact match with enhanced title
756+
let searchQuery = `repo:${this.owner}/${this.repo}+is:issue+is:open+"${enhancedTitle}"+label:lint+label:automated`;
757+
758+
let response = await fetch(
692759
`${this.apiBase}/search/issues?q=${encodeURIComponent(searchQuery)}`,
693760
{
694761
headers: {
@@ -703,9 +770,9 @@ All instances of \`${ruleId}\` violations have been fixed. This issue is now aut
703770
const data = await response.json();
704771
if (data.total_count > 0) {
705772
// Find exact title match (case-insensitive)
706-
const exactMatch = data.items.find((issue: any) => issue.title.toLowerCase() === fileName.toLowerCase());
773+
const exactMatch = data.items.find((issue: any) => issue.title.toLowerCase() === enhancedTitle.toLowerCase());
707774
if (exactMatch) {
708-
console.log(`🔍 Found existing file-based issue for ${fileName}: #${exactMatch.number}`);
775+
console.log(`🔍 Found existing file-based issue for ${enhancedTitle}: #${exactMatch.number}`);
709776
return {
710777
number: exactMatch.number,
711778
title: exactMatch.title,
@@ -714,14 +781,46 @@ All instances of \`${ruleId}\` violations have been fixed. This issue is now aut
714781
}
715782
}
716783
}
784+
785+
// If no exact match found, try searching for just the filename part (for backward compatibility)
786+
if (fileNamePart !== enhancedTitle) {
787+
searchQuery = `repo:${this.owner}/${this.repo}+is:issue+is:open+"${fileNamePart}"+label:lint+label:automated`;
788+
789+
response = await fetch(
790+
`${this.apiBase}/search/issues?q=${encodeURIComponent(searchQuery)}`,
791+
{
792+
headers: {
793+
'Authorization': `Bearer ${this.token}`,
794+
'Accept': 'application/vnd.github.v3+json',
795+
'User-Agent': 'ClearView-Lint-Automation'
796+
}
797+
}
798+
);
799+
800+
if (response.ok) {
801+
const data = await response.json();
802+
if (data.total_count > 0) {
803+
// Find exact match with just the filename (for migration from old format)
804+
const exactMatch = data.items.find((issue: any) => issue.title.toLowerCase() === fileNamePart.toLowerCase());
805+
if (exactMatch) {
806+
console.log(`🔍 Found existing file-based issue (old format) for ${fileNamePart}: #${exactMatch.number}`);
807+
return {
808+
number: exactMatch.number,
809+
title: exactMatch.title,
810+
body: exactMatch.body
811+
};
812+
}
813+
}
814+
}
815+
}
717816
} catch (error) {
718-
console.warn(`⚠️ Could not check existing issues for file ${fileName}:`, error);
817+
console.warn(`⚠️ Could not check existing issues for file ${enhancedTitle}:`, error);
719818
}
720819

721820
return null;
722821
}
723822

724-
async closeOldIssueForMigration(issueNumber: number, fileName: string): Promise<void> {
823+
async closeOldIssueForMigration(issueNumber: number, enhancedTitle: string): Promise<void> {
725824
if (!this.token) return;
726825

727826
try {
@@ -731,7 +830,7 @@ All instances of \`${ruleId}\` violations have been fixed. This issue is now aut
731830
This issue is being closed as we're migrating to a new file-based issue format for better organization.
732831
733832
**Old format:** Rule-based grouping
734-
**New format:** File-based grouping (\`${fileName}\`)
833+
**New format:** File-based grouping with region context (\`${enhancedTitle}\`)
735834
736835
A new issue will be created with the updated format to track the same lint violations.
737836
@@ -755,7 +854,7 @@ A new issue will be created with the updated format to track the same lint viola
755854
});
756855

757856
if (response.ok) {
758-
console.log(`✅ Closed old format issue #${issueNumber} for migration to file-based format`);
857+
console.log(`✅ Closed old format issue #${issueNumber} for migration to ${enhancedTitle}`);
759858
} else {
760859
console.warn(`⚠️ Failed to close old format issue #${issueNumber}:`, response.statusText);
761860
}

0 commit comments

Comments
 (0)