Skip to content

Commit b2c6bfe

Browse files
committed
chore: improve single package prs
1 parent 512b1a3 commit b2c6bfe

File tree

4 files changed

+165
-110
lines changed

4 files changed

+165
-110
lines changed

src/pr/pr-generator.ts

Lines changed: 72 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export class PullRequestGenerator {
4747
author: 'github-actions[bot]',
4848
reviewers: [],
4949
assignees: [],
50-
labels: ['dependencies', 'automated'],
50+
labels: this.generateLabels(group),
5151
draft: false,
5252
}
5353

@@ -57,6 +57,30 @@ export class PullRequestGenerator {
5757
return prs
5858
}
5959

60+
/**
61+
* Generate labels for a pull request
62+
*/
63+
generateLabels(group: UpdateGroup): string[] {
64+
const labels = ['dependencies', 'automated']
65+
66+
// Add update type labels
67+
if (group.updateType === 'major') {
68+
labels.push('major')
69+
} else if (group.updateType === 'minor') {
70+
labels.push('minor')
71+
} else if (group.updateType === 'patch') {
72+
labels.push('patch')
73+
}
74+
75+
// For single package updates, add the specific package name as a label
76+
if (group.updates.length === 1) {
77+
const update = group.updates[0]
78+
labels.push(group.title) // This will be like "chore(deps): update dependency stripe to 18.4.0"
79+
}
80+
81+
return labels
82+
}
83+
6084
/**
6185
* Generate PR title for an update group
6286
*/
@@ -133,19 +157,22 @@ export class PullRequestGenerator {
133157

134158
let body = `This PR contains the following updates:\n\n`
135159

136-
// Add summary table (always show for clarity)
137-
body += `## Package Updates Summary\n\n`
138-
body += `| Type | Count |\n`
139-
body += `|------|-------|\n`
140-
if (packageJsonCount > 0)
141-
body += `| 📦 NPM Packages | ${packageJsonCount} |\n`
142-
if (dependencyFileCount > 0)
143-
body += `| 🔧 System Dependencies | ${dependencyFileCount} |\n`
144-
if (githubActionsCount > 0)
145-
body += `| 🚀 GitHub Actions | ${githubActionsCount} |\n`
146-
if (composerCount > 0)
147-
body += `| 🐘 Composer Packages | ${composerCount} |\n`
148-
body += `| **Total** | **${group.updates.length}** |\n\n`
160+
// Only show summary table for multi-package updates
161+
const isMultiPackageUpdate = group.updates.length > 1
162+
if (isMultiPackageUpdate) {
163+
body += `## Package Updates Summary\n\n`
164+
body += `| Type | Count |\n`
165+
body += `|------|-------|\n`
166+
if (packageJsonCount > 0)
167+
body += `| 📦 NPM Packages | ${packageJsonCount} |\n`
168+
if (dependencyFileCount > 0)
169+
body += `| 🔧 System Dependencies | ${dependencyFileCount} |\n`
170+
if (githubActionsCount > 0)
171+
body += `| 🚀 GitHub Actions | ${githubActionsCount} |\n`
172+
if (composerCount > 0)
173+
body += `| 🐘 Composer Packages | ${composerCount} |\n`
174+
body += `| **Total** | **${group.updates.length}** |\n\n`
175+
}
149176

150177
// Separate updates by type
151178
const packageJsonUpdates = group.updates.filter(update =>
@@ -217,12 +244,16 @@ export class PullRequestGenerator {
217244
packageCount: packageJsonUpdates.length,
218245
packages: packageJsonUpdates.map(u => u.name),
219246
})
220-
body += `## 📦 npm Dependencies\n\n`
221-
body += `![npm](https://img.shields.io/badge/npm-CB3837?style=flat&logo=npm&logoColor=white)\n\n`
222-
if (packageJsonUpdates.length === 1) {
223-
body += `*${packageJsonUpdates.length} package will be updated*\n\n`
247+
248+
// Only show section header for multi-package updates or when there are multiple package types
249+
if (isMultiPackageUpdate || packageJsonCount < group.updates.length) {
250+
body += `## 📦 npm Dependencies\n\n`
224251
}
225-
else if (packageJsonUpdates.length > 1) {
252+
253+
body += `![npm](https://img.shields.io/badge/npm-CB3837?style=flat&logo=npm&logoColor=white)\n\n`
254+
255+
// Only show count text for multi-package updates
256+
if (packageJsonUpdates.length > 1) {
226257
body += `*${packageJsonUpdates.length} packages will be updated*\n\n`
227258
}
228259
body += `| Package | Change | Age | Adoption | Passing | Confidence |\n`
@@ -301,12 +332,15 @@ export class PullRequestGenerator {
301332
}
302333
}
303334

304-
body += `## 🐘 PHP/Composer Dependencies\n\n`
305-
body += `![composer](https://img.shields.io/badge/composer-885630?style=flat&logo=composer&logoColor=white)\n\n`
306-
if (uniqueComposerUpdates.length === 1) {
307-
body += `*${uniqueComposerUpdates.length} package will be updated*\n\n`
335+
// Only show section header for multi-package updates or when there are multiple package types
336+
if (isMultiPackageUpdate || composerCount < group.updates.length) {
337+
body += `## 🐘 PHP/Composer Dependencies\n\n`
308338
}
309-
else if (uniqueComposerUpdates.length > 1) {
339+
340+
body += `![composer](https://img.shields.io/badge/composer-885630?style=flat&logo=composer&logoColor=white)\n\n`
341+
342+
// Only show count text for multi-package updates
343+
if (uniqueComposerUpdates.length > 1) {
310344
body += `*${uniqueComposerUpdates.length} packages will be updated*\n\n`
311345
}
312346
body += `| Package | Change | Age | Adoption | Passing | Confidence | Type | Update |\n`
@@ -354,14 +388,16 @@ export class PullRequestGenerator {
354388

355389
// Dependency files table (enhanced with more information)
356390
if (dependencyFileUpdates.length > 0) {
357-
body += `## 🔧 System Dependencies\n\n`
391+
// Only show section header for multi-package updates or when there are multiple package types
392+
if (isMultiPackageUpdate || dependencyFileCount < group.updates.length) {
393+
body += `## 🔧 System Dependencies\n\n`
394+
}
395+
358396
body += `![system](https://img.shields.io/badge/system-4CAF50?style=flat&logo=linux&logoColor=white)\n\n`
359397

398+
// Only show count text for multi-package updates
360399
const uniqueFiles = [...new Set(dependencyFileUpdates.map(u => u.file))]
361-
if (dependencyFileUpdates.length === 1) {
362-
body += `*${dependencyFileUpdates.length} package will be updated in \`${uniqueFiles[0].split('/').pop()}\`*\n\n`
363-
}
364-
else if (dependencyFileUpdates.length > 1) {
400+
if (dependencyFileUpdates.length > 1) {
365401
body += `*${dependencyFileUpdates.length} packages will be updated across ${uniqueFiles.length} file(s): ${uniqueFiles.map(f => `\`${f.split('/').pop()}\``).join(', ')}*\n\n`
366402
}
367403

@@ -397,13 +433,15 @@ export class PullRequestGenerator {
397433

398434
// GitHub Actions table (enhanced with more information)
399435
if (uniqueGithubActionsUpdates.length > 0) {
400-
body += `## 🚀 GitHub Actions\n\n`
436+
// Only show section header for multi-package updates or when there are multiple package types
437+
if (isMultiPackageUpdate || githubActionsCount < group.updates.length) {
438+
body += `## 🚀 GitHub Actions\n\n`
439+
}
440+
401441
body += `![github-actions](https://img.shields.io/badge/GitHub%20Actions-2088FF?style=flat&logo=github-actions&logoColor=white)\n\n`
402442

403-
if (uniqueGithubActionsUpdates.length === 1) {
404-
body += `*${uniqueGithubActionsUpdates.length} action will be updated*\n\n`
405-
}
406-
else if (uniqueGithubActionsUpdates.length > 1) {
443+
// Only show count text for multi-action updates
444+
if (uniqueGithubActionsUpdates.length > 1) {
407445
body += `*${uniqueGithubActionsUpdates.length} actions will be updated*\n\n`
408446
}
409447

test/pr-body-major-updates.test.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,17 @@ describe('PR Body Generation for Major Updates', () => {
3131
// |------|-------|
3232
// | **Total** | **1** |
3333

34-
// Should BE like Renovate's format:
35-
// | Type | Count |
36-
// |------|-------|
37-
// | 📦 NPM Packages | 1 |
38-
// | **Total** | **1** |
34+
// simplified format for single package updates:
35+
// No summary table, no section header, just the npm badge and package table
3936

40-
expect(body).toContain('## Package Updates Summary')
41-
expect(body).toContain('| 📦 NPM Packages | 1 |')
42-
expect(body).toContain('| **Total** | **1** |')
37+
expect(body).not.toContain('## Package Updates Summary') // Simplified format
38+
expect(body).not.toContain('| 📦 NPM Packages | 1 |') // Simplified format
39+
expect(body).not.toContain('| **Total** | **1** |') // Simplified format
4340

4441
// Should include the detailed package table (missing in original issue)
45-
expect(body).toContain('## 📦 npm Dependencies')
46-
expect(body).toContain('*1 package will be updated*')
42+
expect(body).not.toContain('## 📦 npm Dependencies') // Simplified format
43+
expect(body).not.toContain('*1 package will be updated*') // Simplified format
44+
expect(body).toContain('![npm](https://img.shields.io/badge/npm-CB3837') // Should have npm badge
4745
expect(body).toContain('| Package | Change | Age | Adoption | Passing | Confidence |')
4846

4947
// Should include package details
@@ -124,9 +122,11 @@ describe('PR Body Generation for Major Updates', () => {
124122

125123
const composerBody = await generator.generateBody(majorComposerUpdate)
126124

127-
expect(composerBody).toContain('| 🐘 Composer Packages | 1 |')
128-
expect(composerBody).toContain('## 🐘 PHP/Composer Dependencies')
129-
expect(composerBody).toContain('*1 package will be updated*')
125+
// Composer single package updates should also use simplified format
126+
expect(composerBody).not.toContain('| 🐘 Composer Packages | 1 |') // No summary table
127+
expect(composerBody).not.toContain('## 🐘 PHP/Composer Dependencies') // No section header
128+
expect(composerBody).not.toContain('*1 package will be updated*') // No count text
129+
expect(composerBody).toContain('![composer](https://img.shields.io/badge/composer-885630') // Should have composer badge
130130
expect(composerBody).toContain('laravel/framework')
131131

132132
// Test GitHub Action major update
@@ -148,9 +148,11 @@ describe('PR Body Generation for Major Updates', () => {
148148

149149
const actionBody = await generator.generateBody(majorActionUpdate)
150150

151-
expect(actionBody).toContain('| 🚀 GitHub Actions | 1 |')
152-
expect(actionBody).toContain('## 🚀 GitHub Actions')
153-
expect(actionBody).toContain('*1 action will be updated*')
151+
// GitHub Actions single update should also use simplified format
152+
expect(actionBody).not.toContain('| 🚀 GitHub Actions | 1 |') // No summary table
153+
expect(actionBody).not.toContain('## 🚀 GitHub Actions') // No section header
154+
expect(actionBody).not.toContain('*1 action will be updated*') // No count text
155+
expect(actionBody).toContain('![github-actions](https://img.shields.io/badge/GitHub%20Actions-2088FF') // Should have GitHub Actions badge
154156
expect(actionBody).toContain('actions/checkout')
155157
})
156158
})

test/pr-body-regression-stripe.test.ts

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,21 @@ describe('PR Body Regression - Stripe Issue', () => {
4242

4343
// The regression: PR body should NOT be sparse like PR #1453
4444
// It should include the detailed NPM table with badges and links
45+
// NOTE: Single package updates now have a simplified format without summary table
4546

46-
// 1. Should have package summary table
47-
expect(body).toContain('## Package Updates Summary')
48-
expect(body).toContain('| 📦 NPM Packages | 1 |')
49-
expect(body).toContain('| **Total** | **1** |')
47+
// 1. Should NOT have package summary table for single package updates (new simplified format)
48+
expect(body).not.toContain('## Package Updates Summary')
49+
expect(body).not.toContain('| 📦 NPM Packages | 1 |')
50+
expect(body).not.toContain('| **Total** | **1** |')
5051

51-
// 2. CRITICAL: Should have detailed NPM dependencies section (this was missing in #1453)
52-
expect(body).toContain('## 📦 npm Dependencies')
52+
// 2. Should NOT have npm section header for single package updates (new simplified format)
53+
expect(body).not.toContain('## 📦 npm Dependencies')
54+
55+
// 3. CRITICAL: Should have npm badge and detailed package table (this was missing in #1453)
5356
expect(body).toContain('![npm](https://img.shields.io/badge/npm-CB3837?style=flat&logo=npm&logoColor=white)')
54-
expect(body).toContain('*1 package will be updated*')
57+
58+
// Should NOT have package count text for single packages (new simplified format)
59+
expect(body).not.toContain('*1 package will be updated*')
5560

5661
// 3. Should have detailed package table with badges (missing in #1453)
5762
expect(body).toContain('| Package | Change | Age | Adoption | Passing | Confidence |')
@@ -113,10 +118,11 @@ describe('PR Body Regression - Stripe Issue', () => {
113118

114119
const body = await generator.generateBody(relativePathUpdate)
115120

116-
// Should work correctly with relative path
117-
expect(body).toContain('| 📦 NPM Packages | 1 |')
118-
expect(body).toContain('## 📦 npm Dependencies')
119-
expect(body).toContain('| Package | Change | Age | Adoption | Passing | Confidence |')
121+
// Should work correctly with relative path (new simplified format)
122+
expect(body).not.toContain('| 📦 NPM Packages | 1 |') // No summary table for single packages
123+
expect(body).not.toContain('## 📦 npm Dependencies') // No section header for single packages
124+
expect(body).toContain('| Package | Change | Age | Adoption | Passing | Confidence |') // Should have detailed table
125+
expect(body).toContain('![npm](https://img.shields.io/badge/npm-CB3837') // Should have npm badge
120126
expect(body.length).toBeGreaterThan(2000)
121127

122128
// Test absolute path (common in CI environments)
@@ -137,10 +143,11 @@ describe('PR Body Regression - Stripe Issue', () => {
137143

138144
const bodyAbsolute = await generator.generateBody(absolutePathUpdate)
139145

140-
// Should work correctly with absolute path
141-
expect(bodyAbsolute).toContain('| 📦 NPM Packages | 1 |')
142-
expect(bodyAbsolute).toContain('## 📦 npm Dependencies')
143-
expect(bodyAbsolute).toContain('| Package | Change | Age | Adoption | Passing | Confidence |')
146+
// Should work correctly with absolute path (new simplified format)
147+
expect(bodyAbsolute).not.toContain('| 📦 NPM Packages | 1 |') // No summary table for single packages
148+
expect(bodyAbsolute).not.toContain('## 📦 npm Dependencies') // No section header for single packages
149+
expect(bodyAbsolute).toContain('| Package | Change | Age | Adoption | Passing | Confidence |') // Should have detailed table
150+
expect(bodyAbsolute).toContain('![npm](https://img.shields.io/badge/npm-CB3837') // Should have npm badge
144151
expect(bodyAbsolute.length).toBeGreaterThan(2000)
145152
})
146153

@@ -193,14 +200,14 @@ describe('PR Body Regression - Stripe Issue', () => {
193200
// Our output should NOT match this broken minimal pattern
194201
expect(body).not.toContain(brokenPattern)
195202

196-
// Specifically check that we have content between summary and release notes
197-
const summaryToReleaseNotes = body.substring(
198-
body.indexOf('| **Total** | **1** |'),
199-
body.indexOf('### Release Notes'),
200-
)
203+
// For single package updates, we now have a simplified format
204+
// Check that we have substantial content before release notes
205+
const beforeReleaseNotes = body.substring(0, body.indexOf('### Release Notes'))
201206

202-
// Should have substantial content (NPM section) between summary and release notes
203-
expect(summaryToReleaseNotes).toContain('## 📦 npm Dependencies')
204-
expect(summaryToReleaseNotes.length).toBeGreaterThan(500) // Should have substantial content
207+
// Should have the npm badge and package table (the key content that was missing in #1453)
208+
expect(beforeReleaseNotes).toContain('![npm](https://img.shields.io/badge/npm-CB3837')
209+
expect(beforeReleaseNotes).toContain('| Package | Change | Age | Adoption | Passing | Confidence |')
210+
expect(beforeReleaseNotes).toContain('stripe')
211+
expect(beforeReleaseNotes.length).toBeGreaterThan(500) // Should have substantial content
205212
})
206213
})

0 commit comments

Comments
 (0)