2020-08-24 12:35:22 +00:00
import is from '@sindresorhus/is' ;
2020-09-21 20:04:11 +00:00
import { nameFromLevel } from 'bunyan' ;
2021-02-05 21:21:24 +00:00
import { getAdminConfig } from '../../config/admin' ;
2021-04-20 08:52:57 +00:00
import type { RenovateConfig } from '../../config/types' ;
2020-09-21 20:04:11 +00:00
import { getProblems , logger } from '../../logger' ;
2020-05-01 16:03:48 +00:00
import { Pr , platform } from '../../platform' ;
2020-08-18 10:19:19 +00:00
import { PrState } from '../../types' ;
2021-04-15 17:06:55 +00:00
import { BranchConfig , BranchResult } from '../types' ;
2019-01-06 13:47:42 +00:00
2020-01-10 10:35:49 +00:00
function getListItem ( branch : BranchConfig , type : string , pr? : Pr ) : string {
2018-10-04 08:07:59 +00:00
let item = ' - [ ] ' ;
item += ` <!-- ${ type } -branch= ${ branch . branchName } --> ` ;
2018-11-02 05:23:45 +00:00
if ( pr ) {
item += ` [ ${ branch . prTitle } ](../pull/ ${ pr . number } ) ` ;
2018-10-04 08:07:59 +00:00
} else {
item += branch . prTitle ;
}
2018-10-04 08:38:16 +00:00
const uniquePackages = [
2020-04-12 16:09:36 +00:00
. . . new Set ( branch . upgrades . map ( ( upgrade ) = > '`' + upgrade . depName + '`' ) ) ,
2018-10-04 08:38:16 +00:00
] ;
if ( uniquePackages . length < 2 ) {
2018-10-04 08:07:59 +00:00
return item + '\n' ;
}
2018-10-04 08:38:16 +00:00
return item + ' (' + uniquePackages . join ( ', ' ) + ')\n' ;
2018-10-04 08:07:59 +00:00
}
2020-09-21 20:04:11 +00:00
function appendRepoProblems ( config : RenovateConfig , issueBody : string ) : string {
let newIssueBody = issueBody ;
const repoProblems = new Set (
getProblems ( )
. filter (
( problem ) = >
problem . repository === config . repository && ! problem . artifactErrors
)
. map (
( problem ) = >
` ${ nameFromLevel [ problem . level ] . toUpperCase ( ) } : ${ problem . msg } `
)
) ;
if ( repoProblems . size ) {
newIssueBody += '## Repository problems\n\n' ;
newIssueBody +=
'These problems occurred while renovating this repository.\n\n' ;
for ( const repoProblem of repoProblems ) {
newIssueBody += ` - ${ repoProblem } \ n ` ;
}
newIssueBody += '\n' ;
}
return newIssueBody ;
}
2020-01-10 10:35:49 +00:00
export async function ensureMasterIssue (
config : RenovateConfig ,
branches : BranchConfig [ ]
) : Promise < void > {
2020-07-11 09:55:30 +00:00
// legacy/migrated issue
const reuseTitle = 'Update Dependencies (Renovate Bot)' ;
2019-04-28 06:23:00 +00:00
if (
2019-07-11 11:48:41 +00:00
! (
2020-07-11 09:55:30 +00:00
config . dependencyDashboard ||
2021-02-23 22:33:48 +00:00
config . dependencyDashboardApproval ||
config . packageRules ? . some ( ( rule ) = > rule . dependencyDashboardApproval ) ||
2019-07-11 11:48:41 +00:00
branches . some (
2020-07-11 09:55:30 +00:00
( branch ) = >
branch . dependencyDashboardApproval ||
branch . dependencyDashboardPrApproval
2019-07-11 11:48:41 +00:00
)
)
2019-04-28 06:23:00 +00:00
) {
2018-10-04 08:07:59 +00:00
return ;
2020-10-16 10:52:43 +00:00
}
// istanbul ignore if
2020-10-16 12:02:00 +00:00
if ( config . repoIsOnboarded === false ) {
2020-10-16 10:52:43 +00:00
logger . debug ( 'Repo is onboarding - skipping dependency dashboard' ) ;
return ;
2018-10-04 08:07:59 +00:00
}
2020-07-11 09:55:30 +00:00
logger . debug ( 'Ensuring Dependency Dashboard' ) ;
2020-08-24 12:35:22 +00:00
const hasBranches =
is . nonEmptyArray ( branches ) &&
2021-04-15 17:06:55 +00:00
branches . some ( ( branch ) = > branch . result !== BranchResult . Automerged ) ;
2020-08-24 12:35:22 +00:00
if ( config . dependencyDashboardAutoclose && ! hasBranches ) {
2021-02-05 21:21:24 +00:00
if ( getAdminConfig ( ) . dryRun ) {
2019-07-04 14:00:00 +00:00
logger . info (
2020-08-24 12:35:22 +00:00
'DRY-RUN: Would close Dependency Dashboard ' +
2020-07-11 09:55:30 +00:00
config . dependencyDashboardTitle
2019-07-04 14:00:00 +00:00
) ;
} else {
2020-08-24 12:35:22 +00:00
logger . debug ( 'Closing Dependency Dashboard' ) ;
await platform . ensureIssueClosing ( config . dependencyDashboardTitle ) ;
2019-07-04 14:00:00 +00:00
}
2018-10-04 08:07:59 +00:00
return ;
}
2020-07-23 13:35:43 +00:00
let issueBody = '' ;
if ( config . dependencyDashboardHeader ? . length ) {
issueBody += ` ${ config . dependencyDashboardHeader } \ n \ n ` ;
}
2020-09-21 20:04:11 +00:00
issueBody = appendRepoProblems ( config , issueBody ) ;
2018-10-04 08:07:59 +00:00
const pendingApprovals = branches . filter (
2021-04-15 17:06:55 +00:00
( branch ) = > branch . result === BranchResult . NeedsApproval
2018-10-04 08:07:59 +00:00
) ;
if ( pendingApprovals . length ) {
issueBody += '## Pending Approval\n\n' ;
2019-12-05 10:55:14 +00:00
issueBody += ` These branches will be created by Renovate only once you click their checkbox below. \ n \ n ` ;
2018-10-04 08:07:59 +00:00
for ( const branch of pendingApprovals ) {
issueBody += getListItem ( branch , 'approve' ) ;
}
issueBody += '\n' ;
}
const awaitingSchedule = branches . filter (
2021-04-15 17:06:55 +00:00
( branch ) = > branch . result === BranchResult . NotScheduled
2018-10-04 08:07:59 +00:00
) ;
if ( awaitingSchedule . length ) {
issueBody += '## Awaiting Schedule\n\n' ;
issueBody +=
'These updates are awaiting their schedule. Click on a checkbox to ignore the schedule.\n' ;
for ( const branch of awaitingSchedule ) {
issueBody += getListItem ( branch , 'unschedule' ) ;
}
issueBody += '\n' ;
}
2018-10-08 10:53:49 +00:00
const rateLimited = branches . filter (
2020-07-23 13:23:16 +00:00
( branch ) = >
2021-04-15 17:06:55 +00:00
branch . result === BranchResult . BranchLimitReached ||
branch . result === BranchResult . PrLimitReached ||
branch . result === BranchResult . CommitLimitReached
2018-10-04 08:07:59 +00:00
) ;
if ( rateLimited . length ) {
issueBody += '## Rate Limited\n\n' ;
issueBody +=
2019-08-26 05:57:51 +00:00
'These updates are currently rate limited. Click on a checkbox below to force their creation now.\n\n' ;
2018-10-04 08:07:59 +00:00
for ( const branch of rateLimited ) {
issueBody += getListItem ( branch , 'unlimit' ) ;
}
issueBody += '\n' ;
}
2020-08-31 14:05:38 +00:00
const errorList = branches . filter (
2021-04-15 17:06:55 +00:00
( branch ) = > branch . result === BranchResult . Error
2020-08-31 14:05:38 +00:00
) ;
2018-10-04 08:07:59 +00:00
if ( errorList . length ) {
issueBody += '## Errored\n\n' ;
issueBody +=
'These updates encountered an error and will be retried. Click a checkbox below to force a retry now.\n\n' ;
for ( const branch of errorList ) {
issueBody += getListItem ( branch , 'retry' ) ;
}
issueBody += '\n' ;
}
2019-07-11 11:48:41 +00:00
const awaitingPr = branches . filter (
2021-04-15 17:06:55 +00:00
( branch ) = > branch . result === BranchResult . NeedsPrApproval
2019-07-11 11:48:41 +00:00
) ;
if ( awaitingPr . length ) {
issueBody += '## PR Creation Approval Required\n\n' ;
issueBody +=
2019-08-26 05:57:51 +00:00
"These branches exist but PRs won't be created until you approve by ticking the checkbox.\n\n" ;
2019-07-11 11:48:41 +00:00
for ( const branch of awaitingPr ) {
issueBody += getListItem ( branch , 'approvePr' ) ;
}
issueBody += '\n' ;
}
2020-08-31 14:05:38 +00:00
const prEdited = branches . filter (
2021-04-15 17:06:55 +00:00
( branch ) = > branch . result === BranchResult . PrEdited
2020-08-31 14:05:38 +00:00
) ;
2018-10-04 11:54:28 +00:00
if ( prEdited . length ) {
issueBody += '## Edited/Blocked\n\n' ;
2019-12-05 10:55:14 +00:00
issueBody += ` These updates have been manually edited so Renovate will no longer make changes. To discard all commits and start over, check the box below. \ n \ n ` ;
2018-10-04 11:54:28 +00:00
for ( const branch of prEdited ) {
2019-03-06 23:20:22 +00:00
const pr = await platform . getBranchPr ( branch . branchName ) ;
issueBody += getListItem ( branch , 'rebase' , pr ) ;
2018-10-04 11:54:28 +00:00
}
issueBody += '\n' ;
}
2020-08-31 14:05:38 +00:00
const prPending = branches . filter (
2021-04-15 17:06:55 +00:00
( branch ) = > branch . result === BranchResult . Pending
2020-08-31 14:05:38 +00:00
) ;
2019-08-26 05:58:08 +00:00
if ( prPending . length ) {
issueBody += '## Pending Status Checks\n\n' ;
issueBody += ` These updates await pending status checks. To force their creation now, check the box below. \ n \ n ` ;
for ( const branch of prPending ) {
issueBody += getListItem ( branch , 'approvePr' ) ;
}
issueBody += '\n' ;
}
2018-10-04 08:07:59 +00:00
const otherRes = [
2021-04-15 17:06:55 +00:00
BranchResult . Pending ,
BranchResult . NeedsApproval ,
BranchResult . NeedsPrApproval ,
BranchResult . NotScheduled ,
BranchResult . PrLimitReached ,
BranchResult . CommitLimitReached ,
BranchResult . BranchLimitReached ,
BranchResult . AlreadyExisted ,
BranchResult . Error ,
BranchResult . Automerged ,
BranchResult . PrEdited ,
2018-10-04 08:07:59 +00:00
] ;
2020-04-12 16:09:36 +00:00
const inProgress = branches . filter (
2021-04-15 17:06:55 +00:00
( branch ) = > ! otherRes . includes ( branch . result )
2020-04-12 16:09:36 +00:00
) ;
2018-10-04 08:07:59 +00:00
if ( inProgress . length ) {
issueBody += '## Open\n\n' ;
issueBody +=
'These updates have all been created already. Click a checkbox below to force a retry/rebase of any.\n\n' ;
for ( const branch of inProgress ) {
const pr = await platform . getBranchPr ( branch . branchName ) ;
2018-11-02 05:23:45 +00:00
issueBody += getListItem ( branch , 'rebase' , pr ) ;
2018-10-04 08:07:59 +00:00
}
2019-04-28 07:04:50 +00:00
if ( inProgress . length > 2 ) {
issueBody += ' - [ ] ' ;
issueBody += '<!-- rebase-all-open-prs -->' ;
issueBody +=
'**Check this option to rebase all the above open PRs at once**' ;
issueBody += '\n' ;
}
2018-10-04 08:07:59 +00:00
issueBody += '\n' ;
}
2020-08-31 14:05:38 +00:00
const alreadyExisted = branches . filter (
2021-04-15 17:06:55 +00:00
( branch ) = > branch . result === BranchResult . AlreadyExisted
2018-10-04 08:07:59 +00:00
) ;
if ( alreadyExisted . length ) {
2020-10-08 06:27:09 +00:00
issueBody += '## Ignored or Blocked\n\n' ;
2018-10-04 08:07:59 +00:00
issueBody +=
2020-10-08 06:27:09 +00:00
'These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.\n\n' ;
2018-10-04 08:07:59 +00:00
for ( const branch of alreadyExisted ) {
2020-01-14 15:12:14 +00:00
const pr = await platform . findPr ( {
branchName : branch.branchName ,
prTitle : branch.prTitle ,
2020-08-18 10:19:19 +00:00
state : PrState.NotOpen ,
2020-01-14 15:12:14 +00:00
} ) ;
2018-11-02 05:23:45 +00:00
issueBody += getListItem ( branch , 'recreate' , pr ) ;
2018-10-04 08:07:59 +00:00
}
issueBody += '\n' ;
}
2019-04-28 07:04:50 +00:00
2020-08-24 12:35:22 +00:00
if ( ! hasBranches ) {
issueBody +=
'This repository currently has no open or pending branches.\n\n' ;
}
2020-07-23 13:35:43 +00:00
if ( config . dependencyDashboardFooter ? . length ) {
issueBody += ` --- \ n ${ config . dependencyDashboardFooter } \ n ` ;
2019-08-25 08:05:30 +00:00
}
2021-02-05 21:21:24 +00:00
if ( getAdminConfig ( ) . dryRun ) {
2019-07-04 14:00:00 +00:00
logger . info (
2020-07-11 09:55:30 +00:00
'DRY-RUN: Would ensure Dependency Dashboard ' +
config . dependencyDashboardTitle
2019-07-04 14:00:00 +00:00
) ;
} else {
2020-01-07 10:40:53 +00:00
await platform . ensureIssue ( {
2020-07-11 09:55:30 +00:00
title : config.dependencyDashboardTitle ,
reuseTitle ,
2020-01-07 10:40:53 +00:00
body : issueBody ,
} ) ;
2019-07-04 14:00:00 +00:00
}
2018-10-04 08:07:59 +00:00
}