Skip to content

Commit 764e454

Browse files
author
Rhys Koedijk
authored
Add compatibility score badge; Fix @??? mention text encoding issue (#1458)
* Add Dependabot compatibility score badge; Fixing GitHub @mention encoding issues in PR description * Clean up * Merge fixes * Fix formatting
1 parent 9789b17 commit 764e454

File tree

2 files changed

+35
-14
lines changed

2 files changed

+35
-14
lines changed

.github/dependabot.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ updates:
3838
time: '02:00'
3939
groups:
4040
dotnet-docker:
41-
patterns: ["dotnet/*"]
41+
patterns: ['dotnet/*']
4242

4343
- package-ecosystem: 'nuget'
4444
directory: '/'

extension/tasks/dependabotV2/utils/dependabot-cli/DependabotOutputProcessor.ts

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export class DependabotOutputProcessor implements IDependabotUpdateOutputProcess
6161
public async process(update: IDependabotUpdateOperation, type: string, data: any): Promise<boolean> {
6262
const project = this.taskInputs.project;
6363
const repository = this.taskInputs.repository;
64+
const packageManager = update?.job?.['package-manager'];
6465

6566
section(`Processing '${type}'`);
6667
if (this.debug) {
@@ -79,7 +80,7 @@ export class DependabotOutputProcessor implements IDependabotUpdateOutputProcess
7980
function (existingValue: string) {
8081
const repoDependencyLists = JSON.parse(existingValue || '{}');
8182
repoDependencyLists[repository] = repoDependencyLists[repository] || {};
82-
repoDependencyLists[repository][update.job['package-manager']] = {
83+
repoDependencyLists[repository][packageManager] = {
8384
'dependencies': data['dependencies'],
8485
'dependency-files': data['dependency_files'],
8586
'last-updated': new Date().toISOString(),
@@ -154,7 +155,7 @@ export class DependabotOutputProcessor implements IDependabotUpdateOutputProcess
154155
name: this.taskInputs.authorName || DependabotOutputProcessor.PR_DEFAULT_AUTHOR_NAME,
155156
},
156157
title: data['pr-title'],
157-
description: data['pr-body'],
158+
description: getPullRequestDescription(packageManager, data['pr-body'], data['dependencies']),
158159
commitMessage: data['commit-message'],
159160
autoComplete: this.taskInputs.setAutoComplete
160161
? {
@@ -180,7 +181,7 @@ export class DependabotOutputProcessor implements IDependabotUpdateOutputProcess
180181
labels: update.config.labels?.map((label) => label?.trim()) || [],
181182
workItems: update.config.milestone ? [update.config.milestone] : [],
182183
changes: changedFiles,
183-
properties: buildPullRequestProperties(update.job['package-manager'], dependencies),
184+
properties: buildPullRequestProperties(packageManager, dependencies),
184185
});
185186

186187
// Auto-approve the pull request, if required
@@ -207,13 +208,10 @@ export class DependabotOutputProcessor implements IDependabotUpdateOutputProcess
207208
}
208209

209210
// Find the pull request to update
210-
const pullRequestToUpdate = this.getPullRequestForDependencyNames(
211-
update.job['package-manager'],
212-
data['dependency-names'],
213-
);
211+
const pullRequestToUpdate = this.getPullRequestForDependencyNames(packageManager, data['dependency-names']);
214212
if (!pullRequestToUpdate) {
215213
error(
216-
`Could not find pull request to update for package manager '${update.job['package-manager']}' with dependencies '${data['dependency-names'].join(', ')}'`,
214+
`Could not find pull request to update for package manager '${packageManager}' with dependencies '${data['dependency-names'].join(', ')}'`,
217215
);
218216
return false;
219217
}
@@ -253,13 +251,10 @@ export class DependabotOutputProcessor implements IDependabotUpdateOutputProcess
253251
}
254252

255253
// Find the pull request to close
256-
const pullRequestToClose = this.getPullRequestForDependencyNames(
257-
update.job['package-manager'],
258-
data['dependency-names'],
259-
);
254+
const pullRequestToClose = this.getPullRequestForDependencyNames(packageManager, data['dependency-names']);
260255
if (!pullRequestToClose) {
261256
error(
262-
`Could not find pull request to close for package manager '${update.job['package-manager']}' with dependencies '${data['dependency-names'].join(', ')}'`,
257+
`Could not find pull request to close for package manager '${packageManager}' with dependencies '${data['dependency-names'].join(', ')}'`,
263258
);
264259
return false;
265260
}
@@ -444,3 +439,29 @@ function areEqual(a: string[], b: string[]): boolean {
444439
if (a.length !== b.length) return false;
445440
return a.every((name) => b.includes(name));
446441
}
442+
443+
function getPullRequestDescription(packageManager: string, body: string, dependencies: any[]): string {
444+
let header = '';
445+
let footer = '';
446+
447+
// Fix up GitHub mentions encoding issues by removing instances of the zero-width space '\u200B' as it does not render correctly in Azure DevOps.
448+
// https://github.com/dependabot/dependabot-core/issues/9572
449+
// https://github.com/dependabot/dependabot-core/blob/313fcff149b3126cb78b38d15f018907d729f8cc/common/lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb#L245-L252
450+
const description = (body || '').replace(new RegExp(decodeURIComponent('%EF%BF%BD%EF%BF%BD%EF%BF%BD'), 'g'), '');
451+
452+
// If there is exactly one dependency, add a compatibility score badge to the description header.
453+
// Compatibility scores are intended for single dependency security updates, not group updates.
454+
// https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores
455+
if (dependencies.length === 1) {
456+
const compatibilityScoreBadges = dependencies.map((dep) => {
457+
return `![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=${dep['name']}&package-manager=${packageManager}&previous-version=${dep['previous-version']}&new-version=${dep['version']})`;
458+
});
459+
header += compatibilityScoreBadges.join(' ') + '\n\n';
460+
}
461+
462+
// Build the full pull request description.
463+
// The header/footer must not be truncated. If the description is too long, we truncate the body.
464+
const maxDescriptionLength = 4000;
465+
const maxDescriptionLengthAfterHeaderAndFooter = maxDescriptionLength - header.length - footer.length;
466+
return `${header}${description.substring(0, maxDescriptionLengthAfterHeaderAndFooter)}${footer}`;
467+
}

0 commit comments

Comments
 (0)