2020-09-21 20:04:11 +00:00
import { ERROR , WARN } from 'bunyan' ;
2023-05-17 08:15:12 +00:00
import { codeBlock } from 'common-tags' ;
2020-01-10 10:35:49 +00:00
import { mock } from 'jest-mock-extended' ;
2022-05-16 10:20:31 +00:00
import { Fixtures } from '../../../test/fixtures' ;
2020-09-21 20:04:11 +00:00
import {
RenovateConfig ,
logger ,
2022-06-21 09:39:30 +00:00
mockedFunction ,
2020-09-21 20:04:11 +00:00
platform ,
} from '../../../test/util' ;
2023-06-16 17:57:34 +00:00
import { getConfig } from '../../config/defaults' ;
2021-11-23 20:10:45 +00:00
import { GlobalConfig } from '../../config/global' ;
2022-06-23 14:25:55 +00:00
import type {
PackageDependency ,
2023-02-20 14:58:49 +00:00
PackageFile ,
2022-06-23 14:25:55 +00:00
} from '../../modules/manager/types' ;
2022-03-03 09:35:26 +00:00
import type { Platform } from '../../modules/platform' ;
2022-08-15 06:00:26 +00:00
import {
GitHubMaxPrBodyLen ,
massageMarkdown ,
} from '../../modules/platform/github' ;
2022-08-29 20:36:14 +00:00
import { regEx } from '../../util/regex' ;
2022-11-20 07:34:23 +00:00
import type { BranchConfig , BranchUpgradeConfig } from '../types' ;
2020-07-21 13:13:56 +00:00
import * as dependencyDashboard from './dependency-dashboard' ;
2023-05-17 08:15:12 +00:00
import { getDashboardMarkdownVulnerabilities } from './dependency-dashboard' ;
2022-05-16 10:20:31 +00:00
import { PackageFiles } from './package-files' ;
2019-07-17 08:14:56 +00:00
2023-05-17 08:15:12 +00:00
const createVulnerabilitiesMock = jest . fn ( ) ;
jest . mock ( './process/vulnerabilities' , ( ) = > {
return {
__esModule : true ,
Vulnerabilities : class {
static create() {
return createVulnerabilitiesMock ( ) ;
}
} ,
} ;
} ) ;
2020-03-02 11:06:16 +00:00
type PrUpgrade = BranchUpgradeConfig ;
2022-09-12 14:58:52 +00:00
const massageMdSpy = platform . massageMarkdown ;
const getIssueSpy = platform . getIssue ;
2020-01-10 10:35:49 +00:00
let config : RenovateConfig ;
2022-04-12 14:49:49 +00:00
2019-07-04 14:00:00 +00:00
beforeEach ( ( ) = > {
2022-06-23 14:25:55 +00:00
massageMdSpy . mockImplementation ( massageMarkdown ) ;
2020-01-10 10:35:49 +00:00
config = getConfig ( ) ;
2022-11-01 14:46:09 +00:00
config . platform = 'github' ;
2019-07-04 14:00:00 +00:00
config . errors = [ ] ;
config . warnings = [ ] ;
} ) ;
2022-06-23 14:25:55 +00:00
function genRandString ( length : number ) : string {
let result = '' ;
const chars = 'abcdefghijklmnopqrstuvwxyz' ;
const charsLen = chars . length ;
for ( let i = 0 ; i < length ; i ++ ) {
result += chars . charAt ( Math . floor ( Math . random ( ) * charsLen ) ) ;
}
return result ;
}
function genRandPackageFile (
depsNum : number ,
2023-11-07 15:50:29 +00:00
depNameLen : number ,
2023-02-20 14:58:49 +00:00
) : Record < string , PackageFile [ ] > {
2022-06-23 14:25:55 +00:00
const deps : PackageDependency [ ] = [ ] ;
for ( let i = 0 ; i < depsNum ; i ++ ) {
deps . push ( {
depName : genRandString ( depNameLen ) ,
2022-08-15 06:00:26 +00:00
currentValue : '1.0.0' ,
2022-06-23 14:25:55 +00:00
} ) ;
}
return { npm : [ { packageFile : 'package.json' , deps } ] } ;
}
2019-07-04 14:00:00 +00:00
async function dryRun (
2020-01-10 10:35:49 +00:00
branches : BranchConfig [ ] ,
2022-09-12 14:58:52 +00:00
platform : jest.MockedObject < Platform > ,
2022-11-15 06:46:37 +00:00
ensureIssueClosingCalls : number ,
2023-11-07 15:50:29 +00:00
ensureIssueCalls : number ,
2019-07-04 14:00:00 +00:00
) {
2022-04-11 20:29:02 +00:00
GlobalConfig . set ( { dryRun : 'full' } ) ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2019-07-04 14:00:00 +00:00
expect ( platform . ensureIssueClosing ) . toHaveBeenCalledTimes (
2023-11-07 15:50:29 +00:00
ensureIssueClosingCalls ,
2019-07-04 14:00:00 +00:00
) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( ensureIssueCalls ) ;
}
2021-08-18 05:46:56 +00:00
describe ( 'workers/repository/dependency-dashboard' , ( ) = > {
2021-06-16 12:05:36 +00:00
describe ( 'readDashboardBody()' , ( ) = > {
2023-06-29 08:36:56 +00:00
it ( 'parses invalid dashboard body without throwing error' , async ( ) = > {
const conf : RenovateConfig = { } ;
conf . prCreation = 'approval' ;
platform . findIssue . mockResolvedValueOnce ( {
title : '' ,
number : 1 ,
body : null as never ,
} ) ;
await dependencyDashboard . readDashboardBody ( conf ) ;
expect ( conf ) . toEqual ( {
dependencyDashboardChecks : { } ,
dependencyDashboardAllPending : false ,
dependencyDashboardAllRateLimited : false ,
dependencyDashboardIssue : 1 ,
dependencyDashboardRebaseAllOpen : false ,
dependencyDashboardTitle : 'Dependency Dashboard' ,
prCreation : 'approval' ,
} ) ;
} ) ;
2021-06-16 12:05:36 +00:00
it ( 'reads dashboard body' , async ( ) = > {
const conf : RenovateConfig = { } ;
conf . prCreation = 'approval' ;
platform . findIssue . mockResolvedValueOnce ( {
title : '' ,
number : 1 ,
body :
2022-08-21 19:04:17 +00:00
Fixtures . get ( 'dependency-dashboard-with-8-PR.txt' ) . replace (
'- [ ]' ,
2023-11-07 15:50:29 +00:00
'- [x]' ,
2022-08-21 19:04:17 +00:00
) + '\n\n - [x] <!-- rebase-all-open-prs -->' ,
2021-06-16 12:05:36 +00:00
} ) ;
await dependencyDashboard . readDashboardBody ( conf ) ;
2021-11-07 15:34:42 +00:00
expect ( conf ) . toEqual ( {
2022-08-29 20:36:14 +00:00
dependencyDashboardAllPending : false ,
dependencyDashboardAllRateLimited : false ,
2021-11-07 15:34:42 +00:00
dependencyDashboardChecks : {
branchName1 : 'approve' ,
} ,
dependencyDashboardIssue : 1 ,
dependencyDashboardRebaseAllOpen : true ,
dependencyDashboardTitle : 'Dependency Dashboard' ,
prCreation : 'approval' ,
} ) ;
2021-06-16 12:05:36 +00:00
} ) ;
2022-08-29 20:36:14 +00:00
2023-05-02 08:54:49 +00:00
it ( 'reads dashboard body and apply checkedBranches' , async ( ) = > {
const conf : RenovateConfig = { } ;
conf . prCreation = 'approval' ;
conf . checkedBranches = [ 'branch1' , 'branch2' ] ;
platform . findIssue . mockResolvedValueOnce ( {
title : '' ,
number : 1 ,
body : Fixtures.get ( 'dependency-dashboard-with-8-PR.txt' ) ,
} ) ;
await dependencyDashboard . readDashboardBody ( conf ) ;
expect ( conf ) . toEqual ( {
checkedBranches : [ 'branch1' , 'branch2' ] ,
dependencyDashboardAllPending : false ,
dependencyDashboardAllRateLimited : false ,
dependencyDashboardChecks : {
branch1 : 'global-config' ,
branch2 : 'global-config' ,
} ,
dependencyDashboardIssue : 1 ,
dependencyDashboardRebaseAllOpen : false ,
dependencyDashboardTitle : 'Dependency Dashboard' ,
prCreation : 'approval' ,
} ) ;
} ) ;
2022-08-29 20:36:14 +00:00
it ( 'reads dashboard body all pending approval' , async ( ) = > {
const conf : RenovateConfig = { } ;
conf . prCreation = 'approval' ;
platform . findIssue . mockResolvedValueOnce ( {
title : '' ,
number : 1 ,
body : Fixtures.get ( 'dependency-dashboard-with-8-PR.txt' ) . replace (
'- [ ] <!-- approve-all-pending-prs -->' ,
2023-11-07 15:50:29 +00:00
'- [x] <!-- approve-all-pending-prs -->' ,
2022-08-29 20:36:14 +00:00
) ,
} ) ;
await dependencyDashboard . readDashboardBody ( conf ) ;
expect ( conf ) . toEqual ( {
dependencyDashboardChecks : {
branchName1 : 'approve' ,
branchName2 : 'approve' ,
} ,
dependencyDashboardIssue : 1 ,
dependencyDashboardRebaseAllOpen : false ,
dependencyDashboardTitle : 'Dependency Dashboard' ,
prCreation : 'approval' ,
dependencyDashboardAllPending : true ,
dependencyDashboardAllRateLimited : false ,
} ) ;
} ) ;
it ( 'reads dashboard body open all rate-limited' , async ( ) = > {
const conf : RenovateConfig = { } ;
conf . prCreation = 'approval' ;
platform . findIssue . mockResolvedValueOnce ( {
title : '' ,
number : 1 ,
body : Fixtures.get ( 'dependency-dashboard-with-8-PR.txt' ) . replace (
'- [ ] <!-- create-all-rate-limited-prs -->' ,
2023-11-07 15:50:29 +00:00
'- [x] <!-- create-all-rate-limited-prs -->' ,
2022-08-29 20:36:14 +00:00
) ,
} ) ;
await dependencyDashboard . readDashboardBody ( conf ) ;
expect ( conf ) . toEqual ( {
dependencyDashboardChecks : {
branchName5 : 'unlimit' ,
branchName6 : 'unlimit' ,
} ,
dependencyDashboardIssue : 1 ,
dependencyDashboardRebaseAllOpen : false ,
dependencyDashboardTitle : 'Dependency Dashboard' ,
prCreation : 'approval' ,
dependencyDashboardAllPending : false ,
dependencyDashboardAllRateLimited : true ,
} ) ;
} ) ;
2023-11-16 15:53:27 +00:00
it ( 'does not read dashboard body but applies checkedBranches regardless' , async ( ) = > {
const conf : RenovateConfig = { } ;
conf . dependencyDashboard = false ;
conf . checkedBranches = [ 'branch1' , 'branch2' ] ;
await dependencyDashboard . readDashboardBody ( conf ) ;
expect ( conf ) . toEqual ( {
checkedBranches : [ 'branch1' , 'branch2' ] ,
dependencyDashboard : false ,
dependencyDashboardAllPending : false ,
dependencyDashboardAllRateLimited : false ,
dependencyDashboardChecks : {
branch1 : 'global-config' ,
branch2 : 'global-config' ,
} ,
dependencyDashboardRebaseAllOpen : false ,
} ) ;
} ) ;
2021-06-16 12:05:36 +00:00
} ) ;
2021-06-14 05:07:44 +00:00
describe ( 'ensureDependencyDashboard()' , ( ) = > {
2021-02-05 21:21:24 +00:00
beforeEach ( ( ) = > {
2022-05-16 10:20:31 +00:00
PackageFiles . add ( 'main' , null ) ;
2021-11-23 20:10:45 +00:00
GlobalConfig . reset ( ) ;
2023-02-03 07:00:58 +00:00
logger . getProblems . mockReturnValue ( [ ] ) ;
2021-02-05 21:21:24 +00:00
} ) ;
2022-04-12 14:49:49 +00:00
2021-06-14 05:07:44 +00:00
it ( 'do nothing if dependencyDashboard is disabled' , async ( ) = > {
2020-01-10 10:35:49 +00:00
const branches : BranchConfig [ ] = [ ] ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2021-08-25 12:11:18 +00:00
expect ( platform . ensureIssueClosing ) . toHaveBeenCalledTimes ( 1 ) ;
2019-07-04 14:00:00 +00:00
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 0 ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 1 , 0 ) ;
2019-07-04 14:00:00 +00:00
} ) ;
2021-06-14 05:07:44 +00:00
it ( 'do nothing if it has no dependencyDashboardApproval branches' , async ( ) = > {
2019-07-04 14:00:00 +00:00
const branches = [
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr1' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr2' ,
2020-07-11 09:55:30 +00:00
dependencyDashboardApproval : false ,
2019-07-04 14:00:00 +00:00
} ,
] ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2021-08-25 12:11:18 +00:00
expect ( platform . ensureIssueClosing ) . toHaveBeenCalledTimes ( 1 ) ;
2019-07-04 14:00:00 +00:00
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 0 ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 1 , 0 ) ;
2019-07-04 14:00:00 +00:00
} ) ;
2020-07-11 09:55:30 +00:00
it ( 'closes Dependency Dashboard when there is 0 PR opened and dependencyDashboardAutoclose is true' , async ( ) = > {
2020-01-10 10:35:49 +00:00
const branches : BranchConfig [ ] = [ ] ;
2020-07-11 09:55:30 +00:00
config . dependencyDashboard = true ;
config . dependencyDashboardAutoclose = true ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2019-07-04 14:00:00 +00:00
expect ( platform . ensureIssueClosing ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssueClosing . mock . calls [ 0 ] [ 0 ] ) . toBe (
2023-11-07 15:50:29 +00:00
config . dependencyDashboardTitle ,
2019-07-04 14:00:00 +00:00
) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 0 ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 1 , 0 ) ;
2019-07-04 14:00:00 +00:00
} ) ;
2020-07-11 09:55:30 +00:00
it ( 'closes Dependency Dashboard when all branches are automerged and dependencyDashboardAutoclose is true' , async ( ) = > {
2020-03-02 11:06:16 +00:00
const branches : BranchConfig [ ] = [
2020-08-31 14:05:38 +00:00
{
. . . mock < BranchConfig > ( ) ,
prTitle : 'pr1' ,
2022-11-20 07:34:23 +00:00
result : 'automerged' ,
2020-08-31 14:05:38 +00:00
} ,
2019-07-04 14:00:00 +00:00
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr2' ,
2022-11-20 07:34:23 +00:00
result : 'automerged' ,
2020-07-11 09:55:30 +00:00
dependencyDashboardApproval : false ,
2019-07-04 14:00:00 +00:00
} ,
] ;
2020-07-11 09:55:30 +00:00
config . dependencyDashboard = true ;
config . dependencyDashboardAutoclose = true ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2019-07-04 14:00:00 +00:00
expect ( platform . ensureIssueClosing ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssueClosing . mock . calls [ 0 ] [ 0 ] ) . toBe (
2023-11-07 15:50:29 +00:00
config . dependencyDashboardTitle ,
2019-07-04 14:00:00 +00:00
) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 0 ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 1 , 0 ) ;
2019-07-04 14:00:00 +00:00
} ) ;
2020-07-11 09:55:30 +00:00
it ( 'open or update Dependency Dashboard when all branches are closed and dependencyDashboardAutoclose is false' , async ( ) = > {
2020-01-10 10:35:49 +00:00
const branches : BranchConfig [ ] = [ ] ;
2020-07-11 09:55:30 +00:00
config . dependencyDashboard = true ;
2022-01-26 12:23:56 +00:00
config . dependencyDashboardHeader = 'This is a header' ;
2020-08-24 12:35:22 +00:00
config . dependencyDashboardFooter = 'And this is a footer' ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2019-07-04 14:00:00 +00:00
expect ( platform . ensureIssueClosing ) . toHaveBeenCalledTimes ( 0 ) ;
2021-02-24 08:34:25 +00:00
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . title ) . toBe (
2023-11-07 15:50:29 +00:00
config . dependencyDashboardTitle ,
2021-02-24 08:34:25 +00:00
) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2021-02-24 08:34:25 +00:00
} ) ;
it ( 'open or update Dependency Dashboard when rules contain approvals' , async ( ) = > {
const branches : BranchConfig [ ] = [ ] ;
2022-01-26 12:23:56 +00:00
config . repository = 'test' ;
2021-02-24 08:34:25 +00:00
config . packageRules = [
{
dependencyDashboardApproval : true ,
} ,
{ } ,
] ;
2022-01-26 12:23:56 +00:00
config . dependencyDashboardHeader =
'This is a header for platform:{{platform}}' ;
config . dependencyDashboardFooter =
'And this is a footer for repository:{{repository}}' ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2021-02-24 08:34:25 +00:00
expect ( platform . ensureIssueClosing ) . toHaveBeenCalledTimes ( 0 ) ;
2019-07-04 14:00:00 +00:00
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
2020-01-07 10:40:53 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . title ) . toBe (
2023-11-07 15:50:29 +00:00
config . dependencyDashboardTitle ,
2019-07-04 14:00:00 +00:00
) ;
2022-01-26 12:23:56 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatch (
2023-11-07 15:50:29 +00:00
/platform:github/ ,
2022-01-26 12:23:56 +00:00
) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatch (
2023-11-07 15:50:29 +00:00
/repository:test/ ,
2022-01-26 12:23:56 +00:00
) ;
2020-08-24 12:35:22 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
2019-07-04 14:00:00 +00:00
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2019-07-04 14:00:00 +00:00
} ) ;
it ( 'checks an issue with 2 Pending Approvals, 2 not scheduled, 2 pr-hourly-limit-reached and 2 in error' , async ( ) = > {
2020-03-02 11:06:16 +00:00
const branches : BranchConfig [ ] = [
2019-07-04 14:00:00 +00:00
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr1' ,
2020-03-02 11:06:16 +00:00
upgrades : [ { . . . mock < BranchUpgradeConfig > ( ) , depName : 'dep1' } ] ,
2022-11-20 07:34:23 +00:00
result : 'needs-approval' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName1' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr2' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep2' } ] ,
2022-11-20 07:34:23 +00:00
result : 'needs-approval' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName2' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr3' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep3' } ] ,
2022-11-20 07:34:23 +00:00
result : 'not-scheduled' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName3' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr4' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep4' } ] ,
2022-11-20 07:34:23 +00:00
result : 'not-scheduled' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName4' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr5' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep5' } ] ,
2022-11-20 07:34:23 +00:00
result : 'pr-limit-reached' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName5' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr6' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep6' } ] ,
2022-11-20 07:34:23 +00:00
result : 'pr-limit-reached' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName6' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr7' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep7' } ] ,
2022-11-20 07:34:23 +00:00
result : 'error' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName7' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr8' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep8' } ] ,
2022-11-20 07:34:23 +00:00
result : 'error' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName8' ,
} ,
2021-06-07 10:15:19 +00:00
{
. . . mock < BranchConfig > ( ) ,
prTitle : 'pr9' ,
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep9' } ] ,
2022-11-20 07:34:23 +00:00
result : 'done' ,
2021-06-07 10:15:19 +00:00
prBlockedBy : 'BranchAutomerge' ,
branchName : 'branchName9' ,
} ,
2019-07-04 14:00:00 +00:00
] ;
2020-07-11 09:55:30 +00:00
config . dependencyDashboard = true ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2019-07-04 14:00:00 +00:00
expect ( platform . ensureIssueClosing ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
2020-01-07 10:40:53 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . title ) . toBe (
2023-11-07 15:50:29 +00:00
config . dependencyDashboardTitle ,
2019-07-04 14:00:00 +00:00
) ;
2020-01-07 10:40:53 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toBe (
2023-11-07 15:50:29 +00:00
Fixtures . get ( 'dependency-dashboard-with-8-PR.txt' ) ,
2019-07-04 14:00:00 +00:00
) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2019-07-04 14:00:00 +00:00
} ) ;
it ( 'checks an issue with 2 PR pr-edited' , async ( ) = > {
2020-03-02 11:06:16 +00:00
const branches : BranchConfig [ ] = [
2019-07-04 14:00:00 +00:00
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2021-06-05 11:19:20 +00:00
prNo : 1 ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr1' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep1' } ] ,
2022-11-20 07:34:23 +00:00
result : 'pr-edited' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName1' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2021-06-05 11:19:20 +00:00
prNo : 2 ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr2' ,
2020-01-10 10:35:49 +00:00
upgrades : [
{ . . . mock < PrUpgrade > ( ) , depName : 'dep2' } ,
{ . . . mock < PrUpgrade > ( ) , depName : 'dep3' } ,
] ,
2022-11-20 07:34:23 +00:00
result : 'pr-edited' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName2' ,
} ,
] ;
2020-07-11 09:55:30 +00:00
config . dependencyDashboard = true ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2019-07-04 14:00:00 +00:00
expect ( platform . ensureIssueClosing ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
2020-01-07 10:40:53 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . title ) . toBe (
2023-11-07 15:50:29 +00:00
config . dependencyDashboardTitle ,
2019-07-04 14:00:00 +00:00
) ;
2020-01-07 10:40:53 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toBe (
2023-11-07 15:50:29 +00:00
Fixtures . get ( 'dependency-dashboard-with-2-PR-edited.txt' ) ,
2019-07-04 14:00:00 +00:00
) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2019-07-04 14:00:00 +00:00
} ) ;
it ( 'checks an issue with 3 PR in progress and rebase all option' , async ( ) = > {
2020-03-02 11:06:16 +00:00
const branches : BranchConfig [ ] = [
2019-07-04 14:00:00 +00:00
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr1' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep1' } ] ,
2022-11-20 07:34:23 +00:00
result : 'rebase' ,
2021-06-05 11:19:20 +00:00
prNo : 1 ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName1' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr2' ,
2021-06-05 11:19:20 +00:00
prNo : 2 ,
2020-01-10 10:35:49 +00:00
upgrades : [
{ . . . mock < PrUpgrade > ( ) , depName : 'dep2' } ,
{ . . . mock < PrUpgrade > ( ) , depName : 'dep3' } ,
] ,
2022-11-20 07:34:23 +00:00
result : 'rebase' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName2' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr3' ,
2021-06-05 11:19:20 +00:00
prNo : 3 ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep3' } ] ,
2022-11-20 07:34:23 +00:00
result : 'rebase' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName3' ,
} ,
] ;
2020-07-11 09:55:30 +00:00
config . dependencyDashboard = true ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2019-07-04 14:00:00 +00:00
expect ( platform . ensureIssueClosing ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
2020-01-07 10:40:53 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . title ) . toBe (
2023-11-07 15:50:29 +00:00
config . dependencyDashboardTitle ,
2019-07-04 14:00:00 +00:00
) ;
2020-01-07 10:40:53 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toBe (
2023-11-07 15:50:29 +00:00
Fixtures . get ( 'dependency-dashboard-with-3-PR-in-progress.txt' ) ,
2019-07-04 14:00:00 +00:00
) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2019-07-04 14:00:00 +00:00
} ) ;
it ( 'checks an issue with 2 PR closed / ignored' , async ( ) = > {
2020-03-02 11:06:16 +00:00
const branches : BranchConfig [ ] = [
2019-07-04 14:00:00 +00:00
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr1' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep1' } ] ,
2022-11-20 07:34:23 +00:00
result : 'already-existed' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName1' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-04 14:00:00 +00:00
prTitle : 'pr2' ,
2020-01-10 10:35:49 +00:00
upgrades : [
{ . . . mock < PrUpgrade > ( ) , depName : 'dep2' } ,
{ . . . mock < PrUpgrade > ( ) , depName : 'dep3' } ,
] ,
2022-11-20 07:34:23 +00:00
result : 'already-existed' ,
2019-07-04 14:00:00 +00:00
branchName : 'branchName2' ,
} ,
] ;
2020-07-11 09:55:30 +00:00
config . dependencyDashboard = true ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2019-07-04 14:00:00 +00:00
expect ( platform . ensureIssueClosing ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
2020-01-07 10:40:53 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . title ) . toBe (
2023-11-07 15:50:29 +00:00
config . dependencyDashboardTitle ,
2019-07-04 14:00:00 +00:00
) ;
2020-01-07 10:40:53 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toBe (
2023-11-07 15:50:29 +00:00
Fixtures . get ( 'dependency-dashboard-with-2-PR-closed-ignored.txt' ) ,
2019-07-04 14:00:00 +00:00
) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2019-07-04 14:00:00 +00:00
} ) ;
2019-07-11 11:48:41 +00:00
it ( 'checks an issue with 3 PR in approval' , async ( ) = > {
2020-03-02 11:06:16 +00:00
const branches : BranchConfig [ ] = [
2019-07-11 11:48:41 +00:00
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-11 11:48:41 +00:00
prTitle : 'pr1' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep1' } ] ,
2022-11-20 07:34:23 +00:00
result : 'needs-pr-approval' ,
2019-07-11 11:48:41 +00:00
branchName : 'branchName1' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-11 11:48:41 +00:00
prTitle : 'pr2' ,
2020-01-10 10:35:49 +00:00
upgrades : [
{ . . . mock < PrUpgrade > ( ) , depName : 'dep2' } ,
{ . . . mock < PrUpgrade > ( ) , depName : 'dep3' } ,
] ,
2022-11-20 07:34:23 +00:00
result : 'needs-pr-approval' ,
2019-07-11 11:48:41 +00:00
branchName : 'branchName2' ,
} ,
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-07-11 11:48:41 +00:00
prTitle : 'pr3' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep3' } ] ,
2022-11-20 07:34:23 +00:00
result : 'needs-pr-approval' ,
2019-07-11 11:48:41 +00:00
branchName : 'branchName3' ,
} ,
2019-08-26 06:51:04 +00:00
{
2020-01-10 10:35:49 +00:00
. . . mock < BranchConfig > ( ) ,
2019-08-26 06:51:04 +00:00
prTitle : 'pr4' ,
2020-01-10 10:35:49 +00:00
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep4' } ] ,
2022-11-20 07:34:23 +00:00
result : 'pending' ,
2019-08-26 06:51:04 +00:00
branchName : 'branchName4' ,
} ,
2019-07-11 11:48:41 +00:00
] ;
2020-07-11 09:55:30 +00:00
config . dependencyDashboard = true ;
config . dependencyDashboardPrApproval = true ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2019-07-11 11:48:41 +00:00
expect ( platform . ensureIssueClosing ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
2020-01-07 10:40:53 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . title ) . toBe (
2023-11-07 15:50:29 +00:00
config . dependencyDashboardTitle ,
2019-07-11 11:48:41 +00:00
) ;
2020-01-07 10:40:53 +00:00
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toBe (
2023-11-07 15:50:29 +00:00
Fixtures . get ( 'dependency-dashboard-with-3-PR-in-approval.txt' ) ,
2019-07-11 11:48:41 +00:00
) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2019-07-11 11:48:41 +00:00
} ) ;
2020-09-21 20:04:11 +00:00
it ( 'contains logged problems' , async ( ) = > {
const branches : BranchConfig [ ] = [
{
. . . mock < BranchConfig > ( ) ,
prTitle : 'pr1' ,
upgrades : [
{ . . . mock < PrUpgrade > ( ) , depName : 'dep1' , repository : 'repo1' } ,
] ,
2022-11-20 07:34:23 +00:00
result : 'pending' ,
2020-09-21 20:04:11 +00:00
branchName : 'branchName1' ,
} ,
] ;
logger . getProblems . mockReturnValueOnce ( [
{
level : ERROR ,
msg : 'everything is broken' ,
} ,
{
level : WARN ,
msg : 'just a bit' ,
} ,
{
level : ERROR ,
msg : 'i am a duplicated problem' ,
} ,
{
level : ERROR ,
msg : 'i am a duplicated problem' ,
} ,
{
level : ERROR ,
msg : 'i am a non-duplicated problem' ,
} ,
{
level : WARN ,
msg : 'i am a non-duplicated problem' ,
} ,
{
level : WARN ,
msg : 'i am an artifact error' ,
artifactErrors : { } ,
} ,
] ) ;
config . dependencyDashboard = true ;
2021-06-01 13:07:54 +00:00
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2020-09-21 20:04:11 +00:00
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
} ) ;
2022-04-12 14:49:49 +00:00
2023-08-08 15:36:36 +00:00
it ( 'contains logged problems with custom header' , async ( ) = > {
const branches : BranchConfig [ ] = [
{
. . . mock < BranchConfig > ( ) ,
prTitle : 'pr1' ,
upgrades : [
{ . . . mock < PrUpgrade > ( ) , depName : 'dep1' , repository : 'repo1' } ,
] ,
result : 'pending' ,
branchName : 'branchName1' ,
} ,
] ;
logger . getProblems . mockReturnValueOnce ( [
{
level : ERROR ,
msg : 'i am a non-duplicated problem' ,
} ,
] ) ;
config . dependencyDashboard = true ;
config . customizeDashboard = {
repoProblemsHeader : 'platform is {{platform}}' ,
} ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toContain (
2023-11-07 15:50:29 +00:00
'platform is github' ,
2023-08-08 15:36:36 +00:00
) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
} ) ;
2022-08-29 20:36:14 +00:00
it ( 'dependency Dashboard All Pending Approval' , async ( ) = > {
const branches : BranchConfig [ ] = [
{
. . . mock < BranchConfig > ( ) ,
prTitle : 'pr1' ,
upgrades : [ { . . . mock < BranchUpgradeConfig > ( ) , depName : 'dep1' } ] ,
2022-11-20 07:34:23 +00:00
result : 'needs-approval' ,
2022-08-29 20:36:14 +00:00
branchName : 'branchName1' ,
} ,
{
. . . mock < BranchConfig > ( ) ,
prTitle : 'pr2' ,
upgrades : [ { . . . mock < BranchUpgradeConfig > ( ) , depName : 'dep2' } ] ,
2022-11-20 07:34:23 +00:00
result : 'needs-approval' ,
2022-08-29 20:36:14 +00:00
branchName : 'branchName2' ,
} ,
] ;
config . dependencyDashboard = true ;
config . dependencyDashboardChecks = {
branchName1 : 'approve-branch' ,
branchName2 : 'approve-branch' ,
} ;
config . dependencyDashboardIssue = 1 ;
2022-09-12 14:58:52 +00:00
getIssueSpy . mockResolvedValueOnce ( {
2022-08-29 20:36:14 +00:00
title : 'Dependency Dashboard' ,
body : ` This issue contains a list of Renovate updates and their statuses.
# # Pending Approval
These branches will be created by Renovate only once you click their checkbox below .
- [ ] <!-- approve - branch=branchName1 --> pr1
- [ ] <!-- approve - branch=branchName2 --> pr2
- [ x ] <!-- approve - all - pending - prs --> 🔐 * * Create all pending approval PRs at once * * 🔐 ` ,
} ) ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
const checkApprovePendingSelectAll = regEx (
2023-11-07 15:50:29 +00:00
/ - \[ ] <!-- approve-all-pending-prs -->/g ,
2022-08-29 20:36:14 +00:00
) ;
const checkApprovePendingBranch1 = regEx (
2023-11-07 15:50:29 +00:00
/ - \[ ] <!-- approve-branch=branchName1 -->pr1/g ,
2022-08-29 20:36:14 +00:00
) ;
const checkApprovePendingBranch2 = regEx (
2023-11-07 15:50:29 +00:00
/ - \[ ] <!-- approve-branch=branchName2 -->pr2/g ,
2022-08-29 20:36:14 +00:00
) ;
expect (
checkApprovePendingSelectAll . test (
2023-11-07 15:50:29 +00:00
platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ,
) ,
2022-08-29 20:36:14 +00:00
) . toBeTrue ( ) ;
expect (
checkApprovePendingBranch1 . test (
2023-11-07 15:50:29 +00:00
platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ,
) ,
2022-08-29 20:36:14 +00:00
) . toBeTrue ( ) ;
expect (
checkApprovePendingBranch2 . test (
2023-11-07 15:50:29 +00:00
platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ,
) ,
2022-08-29 20:36:14 +00:00
) . toBeTrue ( ) ;
} ) ;
it ( 'dependency Dashboard Open All rate-limited' , async ( ) = > {
const branches : BranchConfig [ ] = [
{
. . . mock < BranchConfig > ( ) ,
prTitle : 'pr1' ,
upgrades : [ { . . . mock < BranchUpgradeConfig > ( ) , depName : 'dep1' } ] ,
2022-11-20 07:34:23 +00:00
result : 'branch-limit-reached' ,
2022-08-29 20:36:14 +00:00
branchName : 'branchName1' ,
} ,
{
. . . mock < BranchConfig > ( ) ,
prTitle : 'pr2' ,
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep2' } ] ,
2022-11-20 07:34:23 +00:00
result : 'pr-limit-reached' ,
2022-08-29 20:36:14 +00:00
branchName : 'branchName2' ,
} ,
] ;
config . dependencyDashboard = true ;
config . dependencyDashboardChecks = {
branchName1 : 'unlimit-branch' ,
branchName2 : 'unlimit-branch' ,
} ;
config . dependencyDashboardIssue = 1 ;
2022-09-12 14:58:52 +00:00
getIssueSpy . mockResolvedValueOnce ( {
2022-08-29 20:36:14 +00:00
title : 'Dependency Dashboard' ,
body : ` This issue contains a list of Renovate updates and their statuses.
# # Rate - limited
These updates are currently rate - limited . Click on a checkbox below to force their creation now .
- [ x ] <!-- create - all - rate - limited - prs --> * * Open all rate - limited PRs * *
- [ ] <!-- unlimit - branch=branchName1 --> pr1
- [ ] <!-- unlimit - branch=branchName2 --> pr2 ` ,
} ) ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
const checkRateLimitedSelectAll = regEx (
2023-11-07 15:50:29 +00:00
/ - \[ ] <!-- create-all-rate-limited-prs -->/g ,
2022-08-29 20:36:14 +00:00
) ;
const checkRateLimitedBranch1 = regEx (
2023-11-07 15:50:29 +00:00
/ - \[ ] <!-- unlimit-branch=branchName1 -->pr1/g ,
2022-08-29 20:36:14 +00:00
) ;
const checkRateLimitedBranch2 = regEx (
2023-11-07 15:50:29 +00:00
/ - \[ ] <!-- unlimit-branch=branchName2 -->pr2/g ,
2022-08-29 20:36:14 +00:00
) ;
expect (
checkRateLimitedSelectAll . test (
2023-11-07 15:50:29 +00:00
platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ,
) ,
2022-08-29 20:36:14 +00:00
) . toBeTrue ( ) ;
expect (
2023-11-07 15:50:29 +00:00
checkRateLimitedBranch1 . test (
platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ,
) ,
2022-08-29 20:36:14 +00:00
) . toBeTrue ( ) ;
expect (
2023-11-07 15:50:29 +00:00
checkRateLimitedBranch2 . test (
platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ,
) ,
2022-08-29 20:36:14 +00:00
) . toBeTrue ( ) ;
} ) ;
2021-06-18 17:31:25 +00:00
it ( 'rechecks branches' , async ( ) = > {
const branches : BranchConfig [ ] = [
{
. . . mock < BranchConfig > ( ) ,
prTitle : 'pr1' ,
upgrades : [ { . . . mock < BranchUpgradeConfig > ( ) , depName : 'dep1' } ] ,
2022-11-20 07:34:23 +00:00
result : 'needs-approval' ,
2021-06-18 17:31:25 +00:00
branchName : 'branchName1' ,
} ,
{
. . . mock < BranchConfig > ( ) ,
prTitle : 'pr2' ,
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep2' } ] ,
2022-11-20 07:34:23 +00:00
result : 'needs-approval' ,
2021-06-18 17:31:25 +00:00
branchName : 'branchName2' ,
} ,
{
. . . mock < BranchConfig > ( ) ,
prTitle : 'pr3' ,
upgrades : [ { . . . mock < PrUpgrade > ( ) , depName : 'dep3' } ] ,
2022-11-20 07:34:23 +00:00
result : 'not-scheduled' ,
2021-06-18 17:31:25 +00:00
branchName : 'branchName3' ,
} ,
] ;
config . dependencyDashboard = true ;
config . dependencyDashboardChecks = { branchName2 : 'approve-branch' } ;
config . dependencyDashboardIssue = 1 ;
2024-01-22 09:07:37 +00:00
mockedFunction ( platform . getIssue ) . mockResolvedValueOnce ( {
title : 'Dependency Dashboard' ,
body : '' ,
} ) ;
2022-09-12 14:58:52 +00:00
mockedFunction ( platform . getIssue ) . mockResolvedValueOnce ( {
2021-06-18 17:31:25 +00:00
title : 'Dependency Dashboard' ,
body : ` This issue contains a list of Renovate updates and their statuses.
# # Pending Approval
These branches will be created by Renovate only once you click their checkbox below .
- [ ] <!-- approve - branch=branchName1 --> pr1
- [ x ] <!-- approve - branch=branchName2 --> pr2
# # Awaiting Schedule
2021-06-20 15:44:03 +00:00
These updates are awaiting their schedule . Click on a checkbox to get an update now .
2022-01-29 05:02:25 +00:00
2021-06-18 17:31:25 +00:00
- [ x ] <!-- unschedule - branch=branchName3 --> pr3
- [ x ] <!-- rebase - all - open - prs --> '
` ,
} ) ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
} ) ;
2021-07-09 07:41:43 +00:00
2024-01-22 09:07:37 +00:00
it ( 'skips fetching issue if content unchanged' , async ( ) = > {
const branches : BranchConfig [ ] = [ ] ;
config . dependencyDashboard = true ;
config . dependencyDashboardChecks = { } ;
config . dependencyDashboardIssue = 1 ;
mockedFunction ( platform . getIssue ) . mockResolvedValueOnce ( {
title : 'Dependency Dashboard' ,
body : ` This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more.
This repository currently has no open or pending branches .
# # Detected dependencies
None detected
` ,
} ) ;
mockedFunction ( platform . getIssue ) . mockResolvedValueOnce ( {
title : 'Dependency Dashboard' ,
body : '' ,
} ) ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
expect ( platform . ensureIssue ) . not . toHaveBeenCalled ( ) ;
} ) ;
2021-07-09 07:41:43 +00:00
it ( 'forwards configured labels to the ensure issue call' , async ( ) = > {
const branches : BranchConfig [ ] = [ ] ;
config . dependencyDashboard = true ;
config . dependencyDashboardLabels = [ 'RenovateBot' , 'Maintenance' ] ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . labels ) . toStrictEqual ( [
'RenovateBot' ,
'Maintenance' ,
] ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2021-07-09 07:41:43 +00:00
} ) ;
2022-05-16 10:20:31 +00:00
describe ( 'checks detected dependencies section' , ( ) = > {
const packageFiles = Fixtures . getJson ( './package-files.json' ) ;
2022-06-07 08:19:08 +00:00
const packageFilesWithDigest = Fixtures . getJson (
2023-11-07 15:50:29 +00:00
'./package-files-digest.json' ,
2022-06-07 08:19:08 +00:00
) ;
2022-05-16 10:20:31 +00:00
let config : RenovateConfig ;
beforeAll ( ( ) = > {
GlobalConfig . reset ( ) ;
config = getConfig ( ) ;
config . dependencyDashboard = true ;
} ) ;
describe ( 'single base branch repo' , ( ) = > {
beforeEach ( ( ) = > {
PackageFiles . clear ( ) ;
2022-08-15 06:00:26 +00:00
PackageFiles . add ( 'main' , packageFiles ) ;
2022-05-16 10:20:31 +00:00
} ) ;
it ( 'add detected dependencies to the Dependency Dashboard body' , async ( ) = > {
const branches : BranchConfig [ ] = [ ] ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2022-05-16 10:20:31 +00:00
} ) ;
it ( 'show default message in issues body when packageFiles is empty' , async ( ) = > {
const branches : BranchConfig [ ] = [ ] ;
PackageFiles . clear ( ) ;
PackageFiles . add ( 'main' , { } ) ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2022-05-16 10:20:31 +00:00
} ) ;
it ( 'show default message in issues body when when packageFiles is null' , async ( ) = > {
const branches : BranchConfig [ ] = [ ] ;
PackageFiles . clear ( ) ;
PackageFiles . add ( 'main' , null ) ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2022-06-07 08:19:08 +00:00
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2022-06-07 08:19:08 +00:00
} ) ;
it ( 'shows different combinations of version+digest for a given dependency' , async ( ) = > {
const branches : BranchConfig [ ] = [ ] ;
PackageFiles . add ( 'main' , packageFilesWithDigest ) ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
2022-05-16 10:20:31 +00:00
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2022-05-16 10:20:31 +00:00
} ) ;
} ) ;
describe ( 'multi base branch repo' , ( ) = > {
beforeEach ( ( ) = > {
2022-08-15 06:00:26 +00:00
PackageFiles . clear ( ) ;
2022-05-16 10:20:31 +00:00
PackageFiles . add ( 'main' , packageFiles ) ;
PackageFiles . add ( 'dev' , packageFiles ) ;
} ) ;
it ( 'add detected dependencies to the Dependency Dashboard body' , async ( ) = > {
const branches : BranchConfig [ ] = [ ] ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2022-05-16 10:20:31 +00:00
} ) ;
it ( 'show default message in issues body when packageFiles is empty' , async ( ) = > {
const branches : BranchConfig [ ] = [ ] ;
PackageFiles . add ( 'main' , { } ) ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2022-05-16 10:20:31 +00:00
} ) ;
it ( 'show default message in issues body when when packageFiles is null' , async ( ) = > {
const branches : BranchConfig [ ] = [ ] ;
PackageFiles . add ( 'main' , null ) ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2022-05-16 10:20:31 +00:00
} ) ;
2022-06-23 14:25:55 +00:00
it ( 'truncates the body of a really big repo' , async ( ) = > {
const branches : BranchConfig [ ] = [ ] ;
const packageFilesBigRepo = genRandPackageFile ( 100 , 700 ) ;
2022-08-15 06:00:26 +00:00
PackageFiles . clear ( ) ;
2022-06-23 14:25:55 +00:00
PackageFiles . add ( 'main' , packageFilesBigRepo ) ;
await dependencyDashboard . ensureDependencyDashboard ( config , branches ) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
2022-08-15 06:00:26 +00:00
expect (
platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body . length <
2023-11-07 15:50:29 +00:00
GitHubMaxPrBodyLen ,
2022-08-15 06:00:26 +00:00
) . toBeTrue ( ) ;
2022-06-23 14:25:55 +00:00
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2022-06-23 14:25:55 +00:00
} ) ;
2022-05-16 10:20:31 +00:00
} ) ;
2022-08-02 13:06:37 +00:00
describe ( 'dependency dashboard lookup warnings' , ( ) = > {
beforeEach ( ( ) = > {
PackageFiles . add ( 'main' , packageFiles ) ;
PackageFiles . add ( 'dev' , packageFiles ) ;
} ) ;
afterEach ( ( ) = > {
PackageFiles . clear ( ) ;
} ) ;
it ( 'Dependency Lookup Warnings message in issues body' , async ( ) = > {
const branches : BranchConfig [ ] = [ ] ;
PackageFiles . add ( 'main' , {
npm : [ { packageFile : 'package.json' , deps : [ ] } ] ,
} ) ;
const dep = [
{
warnings : [ { message : 'dependency-2' , topic : '' } ] ,
} ,
] ;
2023-02-20 14:58:49 +00:00
const packageFiles : Record < string , PackageFile [ ] > = {
2022-08-02 13:06:37 +00:00
npm : [ { packageFile : 'package.json' , deps : dep } ] ,
} ;
await dependencyDashboard . ensureDependencyDashboard (
config ,
branches ,
2023-11-07 15:50:29 +00:00
packageFiles ,
2022-08-02 13:06:37 +00:00
) ;
expect ( platform . ensureIssue ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( platform . ensureIssue . mock . calls [ 0 ] [ 0 ] . body ) . toMatchSnapshot ( ) ;
// same with dry run
2022-11-15 06:46:37 +00:00
await dryRun ( branches , platform , 0 , 1 ) ;
2022-08-02 13:06:37 +00:00
} ) ;
} ) ;
2022-08-15 06:00:26 +00:00
describe ( 'PackageFiles.getDashboardMarkdown()' , ( ) = > {
const note =
2023-12-14 07:16:13 +00:00
'> ℹ **Note**\n> \n> Detected dependencies section has been truncated\n\n' ;
2022-08-15 06:00:26 +00:00
const title = ` ## Detected dependencies \ n \ n ` ;
beforeEach ( ( ) = > {
PackageFiles . clear ( ) ;
} ) ;
it ( 'does not truncates as there is enough space to fit' , ( ) = > {
PackageFiles . add ( 'main' , packageFiles ) ;
2022-08-18 18:52:17 +00:00
const nonTruncated = PackageFiles . getDashboardMarkdown ( Infinity ) ;
2022-08-15 06:00:26 +00:00
const len = ( title + note + nonTruncated ) . length ;
2022-08-18 18:52:17 +00:00
const truncated = PackageFiles . getDashboardMarkdown ( len ) ;
const truncatedWithTitle = PackageFiles . getDashboardMarkdown ( len ) ;
2022-08-15 06:00:26 +00:00
expect ( truncated . length === nonTruncated . length ) . toBeTrue ( ) ;
expect ( truncatedWithTitle . includes ( note ) ) . toBeFalse ( ) ;
} ) ;
it ( 'removes a branch with no managers' , ( ) = > {
PackageFiles . add ( 'main' , packageFiles ) ;
PackageFiles . add ( 'dev' , packageFilesWithDigest ) ;
2022-08-18 18:52:17 +00:00
const md = PackageFiles . getDashboardMarkdown ( Infinity , false ) ;
2022-08-15 06:00:26 +00:00
const len = md . length ;
PackageFiles . add ( 'empty/branch' , { } ) ;
2022-08-18 18:52:17 +00:00
const truncated = PackageFiles . getDashboardMarkdown ( len , false ) ;
2022-08-15 06:00:26 +00:00
expect ( truncated . includes ( 'empty/branch' ) ) . toBeFalse ( ) ;
expect ( truncated . length === len ) . toBeTrue ( ) ;
} ) ;
it ( 'removes a manager with no package files' , ( ) = > {
PackageFiles . add ( 'main' , packageFiles ) ;
2022-08-18 18:52:17 +00:00
const md = PackageFiles . getDashboardMarkdown ( Infinity , false ) ;
2022-08-15 06:00:26 +00:00
const len = md . length ;
PackageFiles . add ( 'dev' , { dockerfile : [ ] } ) ;
2022-08-18 18:52:17 +00:00
const truncated = PackageFiles . getDashboardMarkdown ( len , false ) ;
2022-08-15 06:00:26 +00:00
expect ( truncated . includes ( 'dev' ) ) . toBeFalse ( ) ;
expect ( truncated . length === len ) . toBeTrue ( ) ;
} ) ;
it ( 'does nothing when there are no base branches left' , ( ) = > {
2022-08-18 18:52:17 +00:00
const truncated = PackageFiles . getDashboardMarkdown ( - 1 , false ) ;
2022-08-15 06:00:26 +00:00
expect ( truncated ) . toBe ( '' ) ;
} ) ;
it ( 'removes an entire base branch' , ( ) = > {
PackageFiles . add ( 'main' , packageFiles ) ;
2022-08-18 18:52:17 +00:00
const md = PackageFiles . getDashboardMarkdown ( Infinity ) ;
2022-08-15 06:00:26 +00:00
const len = md . length + note . length ;
PackageFiles . add ( 'dev' , packageFilesWithDigest ) ;
2022-08-18 18:52:17 +00:00
const truncated = PackageFiles . getDashboardMarkdown ( len ) ;
2022-08-15 06:00:26 +00:00
expect ( truncated . includes ( 'dev' ) ) . toBeFalse ( ) ;
expect ( truncated . length === len ) . toBeTrue ( ) ;
} ) ;
it ( 'ensures original data is unchanged' , ( ) = > {
PackageFiles . add ( 'main' , packageFiles ) ;
PackageFiles . add ( 'dev' , packageFilesWithDigest ) ;
2022-08-18 18:52:17 +00:00
const pre = PackageFiles . getDashboardMarkdown ( Infinity ) ;
const truncated = PackageFiles . getDashboardMarkdown ( - 1 , false ) ;
const post = PackageFiles . getDashboardMarkdown ( Infinity ) ;
2022-08-15 06:00:26 +00:00
expect ( truncated ) . toBe ( '' ) ;
expect ( pre === post ) . toBeTrue ( ) ;
expect ( post . includes ( 'main' ) ) . toBeTrue ( ) ;
expect ( post . includes ( 'dev' ) ) . toBeTrue ( ) ;
} ) ;
} ) ;
2022-05-16 10:20:31 +00:00
} ) ;
2019-07-04 14:00:00 +00:00
} ) ;
2023-05-17 08:15:12 +00:00
describe ( 'getDashboardMarkdownVulnerabilities()' , ( ) = > {
const packageFiles = Fixtures . getJson < Record < string , PackageFile [ ] > > (
2023-11-07 15:50:29 +00:00
'./package-files.json' ,
2023-05-17 08:15:12 +00:00
) ;
it ( 'return empty string if summary is empty' , async ( ) = > {
const result = await getDashboardMarkdownVulnerabilities (
config ,
2023-11-07 15:50:29 +00:00
packageFiles ,
2023-05-17 08:15:12 +00:00
) ;
expect ( result ) . toBeEmpty ( ) ;
} ) ;
it ( 'return empty string if summary is set to none' , async ( ) = > {
const result = await getDashboardMarkdownVulnerabilities (
{
. . . config ,
dependencyDashboardOSVVulnerabilitySummary : 'none' ,
} ,
2023-11-07 15:50:29 +00:00
packageFiles ,
2023-05-17 08:15:12 +00:00
) ;
expect ( result ) . toBeEmpty ( ) ;
} ) ;
it ( 'return no data section if summary is set to all and no vulnerabilities' , async ( ) = > {
const fetchVulnerabilitiesMock = jest . fn ( ) ;
createVulnerabilitiesMock . mockResolvedValueOnce ( {
fetchVulnerabilities : fetchVulnerabilitiesMock ,
} ) ;
fetchVulnerabilitiesMock . mockResolvedValueOnce ( [ ] ) ;
const result = await getDashboardMarkdownVulnerabilities (
{
. . . config ,
dependencyDashboardOSVVulnerabilitySummary : 'all' ,
} ,
2023-11-07 15:50:29 +00:00
{ } ,
2023-05-17 08:15:12 +00:00
) ;
expect ( result ) . toBe (
2023-11-07 15:50:29 +00:00
` ## Vulnerabilities \ n \ nRenovate has not found any CVEs on [osv.dev](https://osv.dev). \ n \ n ` ,
2023-05-17 08:15:12 +00:00
) ;
} ) ;
it ( 'return all vulnerabilities if set to all and disabled osvVulnerabilities' , async ( ) = > {
const fetchVulnerabilitiesMock = jest . fn ( ) ;
createVulnerabilitiesMock . mockResolvedValueOnce ( {
fetchVulnerabilities : fetchVulnerabilitiesMock ,
} ) ;
fetchVulnerabilitiesMock . mockResolvedValueOnce ( [
{
packageName : 'express' ,
depVersion : '4.17.3' ,
fixedVersion : '4.18.1' ,
packageFileConfig : {
manager : 'npm' ,
} ,
vulnerability : {
id : 'GHSA-29mw-wpgm-hmr9' ,
} ,
} ,
{
packageName : 'cookie-parser' ,
depVersion : '1.4.6' ,
packageFileConfig : {
manager : 'npm' ,
} ,
vulnerability : {
id : 'GHSA-35jh-r3h4-6jhm' ,
} ,
} ,
] ) ;
const result = await getDashboardMarkdownVulnerabilities (
{
. . . config ,
dependencyDashboardOSVVulnerabilitySummary : 'all' ,
osvVulnerabilityAlerts : true ,
} ,
2023-11-07 15:50:29 +00:00
packageFiles ,
2023-05-17 08:15:12 +00:00
) ;
expect ( result . trimEnd ( ) ) . toBe ( codeBlock ` ## Vulnerabilities
\ ` 1 \` / \` 2 \` CVEs have Renovate fixes.
< details > < summary > npm < / summary >
< blockquote >
< details > < summary > undefined < / summary >
< blockquote >
< details > < summary > express < / summary >
< blockquote >
- [ GHSA - 29 mw - wpgm - hmr9 ] ( https : //osv.dev/vulnerability/GHSA-29mw-wpgm-hmr9) (fixed in 4.18.1)
< / blockquote >
< / details >
< details > < summary > cookie - parser < / summary >
< blockquote >
- [ GHSA - 35 jh - r3h4 - 6 jhm ] ( https : //osv.dev/vulnerability/GHSA-35jh-r3h4-6jhm)
< / blockquote >
< / details >
< / blockquote >
< / details >
< / blockquote >
< / details > ` );
} ) ;
it ( 'return unresolved vulnerabilities if set to "unresolved"' , async ( ) = > {
const fetchVulnerabilitiesMock = jest . fn ( ) ;
createVulnerabilitiesMock . mockResolvedValueOnce ( {
fetchVulnerabilities : fetchVulnerabilitiesMock ,
} ) ;
fetchVulnerabilitiesMock . mockResolvedValueOnce ( [
{
packageName : 'express' ,
depVersion : '4.17.3' ,
fixedVersion : '4.18.1' ,
packageFileConfig : {
manager : 'npm' ,
} ,
vulnerability : {
id : 'GHSA-29mw-wpgm-hmr9' ,
} ,
} ,
{
packageName : 'cookie-parser' ,
depVersion : '1.4.6' ,
packageFileConfig : {
manager : 'npm' ,
} ,
vulnerability : {
id : 'GHSA-35jh-r3h4-6jhm' ,
} ,
} ,
] ) ;
const result = await getDashboardMarkdownVulnerabilities (
{
. . . config ,
dependencyDashboardOSVVulnerabilitySummary : 'unresolved' ,
} ,
2023-11-07 15:50:29 +00:00
packageFiles ,
2023-05-17 08:15:12 +00:00
) ;
expect ( result . trimEnd ( ) ) . toBe ( codeBlock ` ## Vulnerabilities
\ ` 1 \` / \` 2 \` CVEs have possible Renovate fixes.
See [ \ ` osvVulnerabilityAlerts \` ](https://docs.renovatebot.com/configuration-options/#osvvulnerabilityalerts) to allow Renovate to supply fixes.
< details > < summary > npm < / summary >
< blockquote >
< details > < summary > undefined < / summary >
< blockquote >
< details > < summary > cookie - parser < / summary >
< blockquote >
- [ GHSA - 35 jh - r3h4 - 6 jhm ] ( https : //osv.dev/vulnerability/GHSA-35jh-r3h4-6jhm)
< / blockquote >
< / details >
< / blockquote >
< / details >
< / blockquote >
< / details > ` );
} ) ;
} ) ;
2019-07-04 14:00:00 +00:00
} ) ;