@@ -61,6 +61,7 @@ export class DependabotOutputProcessor implements IDependabotUpdateOutputProcess
61
61
public async process ( update : IDependabotUpdateOperation , type : string , data : any ) : Promise < boolean > {
62
62
const project = this . taskInputs . project ;
63
63
const repository = this . taskInputs . repository ;
64
+ const packageManager = update ?. job ?. [ 'package-manager' ] ;
64
65
65
66
section ( `Processing '${ type } '` ) ;
66
67
if ( this . debug ) {
@@ -79,7 +80,7 @@ export class DependabotOutputProcessor implements IDependabotUpdateOutputProcess
79
80
function ( existingValue : string ) {
80
81
const repoDependencyLists = JSON . parse ( existingValue || '{}' ) ;
81
82
repoDependencyLists [ repository ] = repoDependencyLists [ repository ] || { } ;
82
- repoDependencyLists [ repository ] [ update . job [ 'package-manager' ] ] = {
83
+ repoDependencyLists [ repository ] [ packageManager ] = {
83
84
'dependencies' : data [ 'dependencies' ] ,
84
85
'dependency-files' : data [ 'dependency_files' ] ,
85
86
'last-updated' : new Date ( ) . toISOString ( ) ,
@@ -154,7 +155,7 @@ export class DependabotOutputProcessor implements IDependabotUpdateOutputProcess
154
155
name : this . taskInputs . authorName || DependabotOutputProcessor . PR_DEFAULT_AUTHOR_NAME ,
155
156
} ,
156
157
title : data [ 'pr-title' ] ,
157
- description : data [ 'pr-body' ] ,
158
+ description : getPullRequestDescription ( packageManager , data [ 'pr-body' ] , data [ 'dependencies' ] ) ,
158
159
commitMessage : data [ 'commit-message' ] ,
159
160
autoComplete : this . taskInputs . setAutoComplete
160
161
? {
@@ -180,7 +181,7 @@ export class DependabotOutputProcessor implements IDependabotUpdateOutputProcess
180
181
labels : update . config . labels ?. map ( ( label ) => label ?. trim ( ) ) || [ ] ,
181
182
workItems : update . config . milestone ? [ update . config . milestone ] : [ ] ,
182
183
changes : changedFiles ,
183
- properties : buildPullRequestProperties ( update . job [ 'package-manager' ] , dependencies ) ,
184
+ properties : buildPullRequestProperties ( packageManager , dependencies ) ,
184
185
} ) ;
185
186
186
187
// Auto-approve the pull request, if required
@@ -207,13 +208,10 @@ export class DependabotOutputProcessor implements IDependabotUpdateOutputProcess
207
208
}
208
209
209
210
// 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' ] ) ;
214
212
if ( ! pullRequestToUpdate ) {
215
213
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 ( ', ' ) } '` ,
217
215
) ;
218
216
return false ;
219
217
}
@@ -253,13 +251,10 @@ export class DependabotOutputProcessor implements IDependabotUpdateOutputProcess
253
251
}
254
252
255
253
// 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' ] ) ;
260
255
if ( ! pullRequestToClose ) {
261
256
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 ( ', ' ) } '` ,
263
258
) ;
264
259
return false ;
265
260
}
@@ -444,3 +439,29 @@ function areEqual(a: string[], b: string[]): boolean {
444
439
if ( a . length !== b . length ) return false ;
445
440
return a . every ( ( name ) => b . includes ( name ) ) ;
446
441
}
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 `` ;
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