2017-07-07 04:25:38 +00:00
const schedule = require ( './schedule' ) ;
2018-05-09 06:03:59 +00:00
const { getUpdatedPackageFiles } = require ( './get-updated' ) ;
const { getAdditionalFiles } = require ( '../../manager/npm/post-update' ) ;
2017-08-26 14:10:18 +00:00
const { commitFilesToBranch } = require ( './commit' ) ;
const { getParentBranch } = require ( './parent' ) ;
const { tryBranchAutomerge } = require ( './automerge' ) ;
const { setUnpublishable } = require ( './status-checks' ) ;
const { prAlreadyExisted } = require ( './check-existing' ) ;
2017-06-29 05:29:41 +00:00
const prWorker = require ( '../pr' ) ;
2017-08-26 14:10:18 +00:00
const { isScheduledNow } = schedule ;
2017-02-14 07:08:40 +00:00
module . exports = {
2017-08-26 14:10:18 +00:00
processBranch ,
2017-02-14 07:08:40 +00:00
} ;
2018-05-09 06:03:59 +00:00
async function processBranch ( branchConfig , packageFiles ) {
logger . debug ( ` processBranch with ${ branchConfig . upgrades . length } upgrades ` ) ;
2017-08-26 14:10:18 +00:00
const config = { ... branchConfig } ;
2017-12-15 20:33:54 +00:00
const dependencies = config . upgrades
2017-08-26 14:10:18 +00:00
. map ( upgrade => upgrade . depName )
2017-12-15 20:33:54 +00:00
. filter ( v => v ) // remove nulls (happens for lock file maintenance)
. filter ( ( value , i , list ) => list . indexOf ( value ) === i ) ; // remove duplicates
2017-11-08 05:44:03 +00:00
logger . setMeta ( {
2017-08-26 14:10:18 +00:00
repository : config . repository ,
branch : config . branchName ,
dependencies ,
} ) ;
2018-01-11 10:49:01 +00:00
logger . debug ( 'processBranch()' ) ;
logger . trace ( { config } ) ;
2018-01-12 06:47:18 +00:00
await platform . setBaseBranch ( config . baseBranch ) ;
2018-01-11 10:49:01 +00:00
const branchExists = await platform . branchExists ( config . branchName ) ;
logger . debug ( ` branchExists= ${ branchExists } ` ) ;
2018-02-08 19:07:32 +00:00
if ( ! branchExists && config . prHourlyLimitReached ) {
logger . info ( 'Reached PR creation limit - skipping branch creation' ) ;
return 'pr-hourly-limit-reached' ;
}
2017-08-26 14:10:18 +00:00
try {
2018-02-11 18:58:59 +00:00
logger . info (
` Branch has ${ dependencies ? dependencies . length : 0 } upgrade(s) `
) ;
2017-06-29 17:50:26 +00:00
2017-11-10 12:32:33 +00:00
// Check if branch already existed
2017-12-27 14:20:32 +00:00
let pr = await prAlreadyExisted ( config ) ;
2017-10-18 13:28:51 +00:00
if ( pr ) {
2017-10-18 19:39:10 +00:00
logger . info (
{ prTitle : config . prTitle } ,
'Closed PR already exists. Skipping branch.'
) ;
2018-01-20 14:03:57 +00:00
if ( pr . state === 'closed' ) {
const subject = 'Renovate Ignore Notification' ;
let content ;
if ( config . isMajor ) {
content = ` As this PR has been closed unmerged, Renovate will ignore this upgrade and you will not receive PRs for *any* future ${
config . newVersionMajor
} . x releases . However , if you upgrade to $ {
config . newVersionMajor
} . x manually then Renovate will then reenable updates for minor and patch updates automatically . ` ;
} else if ( config . isDigest ) {
content = ` As this PR has been closed unmerged, Renovate will ignore this upgrade type and you will not receive PRs for *any* future ${
config . depName
} : $ {
config . currentTag
} digest updates . Digest updates will resume if you update the specified tag at any time . ` ;
} else {
content = ` As this PR has been closed unmerged, Renovate will now ignore this update ( ${
config . newVersion
} ) . You will still receive a PR once a newer version is released , so if you wish to permanently ignore this dependency , please add it to the \ ` ignoreDeps \` array of your renovate config. ` ;
}
content +=
2018-01-23 09:50:05 +00:00
'\n\nIf this PR was closed by mistake or you changed your mind, you can simply rename this PR and you will soon get a fresh replacement PR opened.' ;
2018-01-20 14:03:57 +00:00
await platform . ensureComment ( pr . number , subject , content ) ;
if ( branchExists ) {
await platform . deleteBranch ( config . branchName ) ;
}
} else if ( pr . state === 'merged' ) {
logger . info ( { pr : pr . number } , 'Merged PR is blocking this branch' ) ;
2018-01-10 09:26:57 +00:00
}
2017-08-28 13:50:11 +00:00
return 'already-existed' ;
2017-08-06 13:38:10 +00:00
}
2018-02-28 03:43:30 +00:00
if ( branchExists ) {
logger . debug ( 'Checking if PR has been edited' ) ;
pr = await platform . findPr ( config . branchName , config . prTitle , 'open' ) ;
}
2017-12-27 14:20:32 +00:00
if ( pr ) {
2017-12-28 15:29:03 +00:00
logger . debug ( { pr } , 'Found existing PR' ) ;
2017-12-27 14:20:32 +00:00
pr = await platform . getPr ( pr . number ) ;
2017-12-30 05:03:57 +00:00
if ( pr . state . startsWith ( 'open' ) ) {
2017-12-30 05:29:40 +00:00
logger . debug ( 'Existing PR is open' ) ;
2017-12-28 15:29:03 +00:00
if ( ! pr . canRebase ) {
const subject = 'PR has been edited' ;
2017-12-28 16:21:06 +00:00
logger . info ( subject ) ;
2017-12-28 15:29:03 +00:00
let content =
'As this PR has been edited, Renovate will stop updating it in order to not cause any conflicts or other problems.' ;
content +=
' If you wish to abandon your edits and have Renovate recreate this PR then you should rename this PR and then close it.' ;
await platform . ensureComment ( pr . number , subject , content ) ;
return 'pr-edited' ;
}
} else {
2018-02-07 11:02:51 +00:00
logger . info ( 'PR state is not open - aborting' ) ;
logger . debug ( { pr } ) ;
2017-12-28 16:21:06 +00:00
return 'pr-closed' ;
2017-12-27 14:20:32 +00:00
}
}
2017-11-10 12:32:33 +00:00
// Check schedule
config . isScheduledNow = isScheduledNow ( config ) ;
if ( ! config . isScheduledNow ) {
2018-01-11 10:49:01 +00:00
if ( ! branchExists ) {
2017-11-10 12:32:33 +00:00
logger . info ( 'Skipping branch creation as not within schedule' ) ;
return 'not-scheduled' ;
}
if ( config . updateNotScheduled === false ) {
logger . debug ( 'Skipping branch update as not within schedule' ) ;
return 'not-scheduled' ;
}
logger . debug (
'Branch exists but is not scheduled -- will update if necessary'
) ;
}
2018-03-21 10:40:13 +00:00
if (
2018-04-08 04:59:34 +00:00
config . type !== 'lockFileMaintenance' &&
2018-03-21 10:40:13 +00:00
config . unpublishSafe &&
! config . unpublishable &&
( config . prCreation === 'not-pending' ||
config . prCreation === 'status-success' )
) {
logger . info (
'Skipping branch creation due to unpublishSafe + status checks'
) ;
return 'pending' ;
}
2017-10-21 14:42:40 +00:00
Object . assign ( config , await getParentBranch ( config ) ) ;
2017-08-26 14:10:18 +00:00
logger . debug ( ` Using parentBranch: ${ config . parentBranch } ` ) ;
2017-10-21 14:42:40 +00:00
Object . assign ( config , await getUpdatedPackageFiles ( config ) ) ;
2018-02-11 18:58:59 +00:00
if ( config . updatedPackageFiles && config . updatedPackageFiles . length ) {
2017-08-26 14:10:18 +00:00
logger . debug (
` Updated ${ config . updatedPackageFiles . length } package files `
2017-04-21 08:12:41 +00:00
) ;
2017-08-26 14:10:18 +00:00
} else {
logger . debug ( 'No package files need updating' ) ;
2017-04-15 18:32:01 +00:00
}
2018-05-09 06:03:59 +00:00
Object . assign ( config , await getAdditionalFiles ( config , packageFiles ) ) ;
2018-02-11 18:58:59 +00:00
if ( config . updatedLockFiles && config . updatedLockFiles . length ) {
2017-08-26 14:10:18 +00:00
logger . debug (
2017-11-17 13:53:29 +00:00
{ updatedLockFiles : config . updatedLockFiles . map ( f => f . name ) } ,
2017-08-26 14:10:18 +00:00
` Updated ${ config . updatedLockFiles . length } lock files `
2017-08-08 21:03:52 +00:00
) ;
2017-08-26 14:10:18 +00:00
} else {
logger . debug ( 'No updated lock files in branch' ) ;
2017-08-08 21:03:52 +00:00
}
2018-01-11 10:49:01 +00:00
2017-11-27 07:25:07 +00:00
const committedFiles = await commitFilesToBranch ( config ) ;
2018-05-06 10:26:21 +00:00
// istanbul ignore if
2018-03-20 05:48:27 +00:00
if (
config . type === 'lockFileMaintenance' &&
! committedFiles &&
2018-03-21 14:53:48 +00:00
! config . parentBranch &&
branchExists
2018-03-20 05:48:27 +00:00
) {
2018-04-05 05:04:02 +00:00
logger . info (
2018-03-16 09:40:07 +00:00
'Deleting lock file maintenance branch as master lock file no longer needs updating'
) ;
2018-05-06 10:26:21 +00:00
await platform . deleteBranch ( config . branchName ) ;
return 'done' ;
2018-03-16 09:40:07 +00:00
}
2017-11-28 08:00:59 +00:00
if ( ! ( committedFiles || branchExists ) ) {
2017-11-27 07:25:07 +00:00
return 'no-work' ;
}
2017-08-26 14:10:18 +00:00
// Set branch statuses
await setUnpublishable ( config ) ;
// Try to automerge branch and finish if successful
2017-10-05 07:31:10 +00:00
const mergeStatus = await tryBranchAutomerge ( config ) ;
2018-04-11 07:39:35 +00:00
logger . debug ( ` mergeStatus= ${ mergeStatus } ` ) ;
2017-10-05 07:31:10 +00:00
if ( mergeStatus === 'automerged' ) {
2017-08-26 14:10:18 +00:00
logger . debug ( 'Branch is automerged - returning' ) ;
2017-08-28 13:50:11 +00:00
return 'automerged' ;
2017-12-28 16:19:59 +00:00
} else if (
mergeStatus === 'automerge aborted - PR exists' ||
mergeStatus === 'failed'
) {
logger . info ( { mergeStatus } , 'Branch automerge not possible' ) ;
2017-10-05 07:31:10 +00:00
config . forcePr = true ;
2017-08-26 14:10:18 +00:00
}
2018-03-22 08:26:20 +00:00
} catch ( err ) /* istanbul ignore next */ {
if ( err . message === 'rate-limit-exceeded' ) {
logger . debug ( 'Passing rate-limit-exceeded error up' ) ;
throw err ;
}
2018-02-03 14:45:43 +00:00
if ( err . message === 'repository-changed' ) {
logger . debug ( 'Passing repository-changed error up' ) ;
throw err ;
}
2018-03-21 10:17:54 +00:00
if ( err . message !== 'registry-failure' ) {
logger . error ( { err } , ` Error updating branch: ${ err . message } ` ) ;
}
2017-08-26 14:47:21 +00:00
// Don't throw here - we don't want to stop the other renovations
2017-08-28 13:50:11 +00:00
return 'error' ;
2017-06-29 17:50:26 +00:00
}
2017-06-22 07:03:36 +00:00
try {
2017-08-26 14:10:18 +00:00
logger . debug ( 'Ensuring PR' ) ;
2017-08-27 11:55:41 +00:00
logger . debug (
2017-11-07 10:52:15 +00:00
` There are ${ config . errors . length } errors and ${
config . warnings . length
} warnings `
2017-08-27 11:55:41 +00:00
) ;
2017-08-26 14:10:18 +00:00
const pr = await prWorker . ensurePr ( config ) ;
// TODO: ensurePr should check for automerge itself
if ( pr ) {
2017-10-19 12:05:10 +00:00
const topic = 'Lock file problem' ;
if ( config . lockFileErrors && config . lockFileErrors . length ) {
logger . warn (
{ lockFileErrors : config . lockFileErrors } ,
'lockFileErrors'
) ;
let content = ` Renovate failed when attempting to generate ` ;
content +=
config . lockFileErrors . length > 1 ? 'lock files' : 'a lock file' ;
content +=
2018-04-24 11:59:42 +00:00
'. This is usually happens when you have private modules but have not added configuration for [private module support](https://renovatebot.com/docs/deep-dives/private-modules). It is strongly recommended that you do not merge this PR as-is.' ;
2017-10-19 12:05:10 +00:00
content +=
'\n\nRenovate **will not retry** generating a lockfile for this PR unless either (a) the `package.json` in this branch needs updating, or (b) ' ;
if ( config . recreateClosed ) {
content +=
'you manually delete this PR so that it can be regenerated.' ;
} else {
content +=
'you rename then delete this PR unmerged, so that it can be regenerated.' ;
}
2017-11-08 12:26:55 +00:00
content += '\n\nThe output from `stderr` is included below:\n\n' ;
2017-10-19 12:05:10 +00:00
config . lockFileErrors . forEach ( error => {
2017-11-08 12:26:55 +00:00
content += ` ##### ${ error . lockFile } \n \n ` ;
content += ` \` \` \` \n ${ error . stderr } \n \` \` \` \n \n ` ;
2017-10-19 12:05:10 +00:00
} ) ;
2017-11-08 12:26:55 +00:00
await platform . ensureComment ( pr . number , topic , content ) ;
2017-10-19 12:05:10 +00:00
} else {
2017-11-16 20:54:13 +00:00
if ( config . updatedLockFiles && config . updatedLockFiles . length ) {
await platform . ensureCommentRemoval ( pr . number , topic ) ;
}
2017-10-19 12:05:10 +00:00
const prAutomerged = await prWorker . checkAutoMerge ( pr , config ) ;
if ( prAutomerged ) {
return 'automerged' ;
}
2017-08-28 13:50:11 +00:00
}
2017-06-22 07:03:36 +00:00
}
2018-03-23 06:56:21 +00:00
} catch ( err ) /* istanbul ignore next */ {
if ( err . message === 'rate-limit-exceeded' ) {
logger . debug ( 'Passing rate-limit-exceeded error up' ) ;
throw err ;
}
// Otherwise don't throw here - we don't want to stop the other renovations
2018-03-27 15:44:05 +00:00
logger . error ( { err } , ` Error ensuring PR: ${ err . message } ` ) ;
2017-06-22 07:03:36 +00:00
}
2018-01-11 10:49:01 +00:00
if ( ! branchExists ) {
return 'pr-created' ;
}
2017-08-28 13:50:11 +00:00
return 'done' ;
2017-06-22 07:03:36 +00:00
}