2017-07-07 04:25:38 +00:00
const schedule = require ( './schedule' ) ;
2017-10-25 04:48:08 +00:00
const { getUpdatedPackageFiles } = require ( '../../manager' ) ;
2017-08-26 14:10:18 +00:00
const { getUpdatedLockFiles } = require ( './lock-files' ) ;
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
} ;
2017-08-26 14:10:18 +00:00
async function processBranch ( branchConfig ) {
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 ,
} ) ;
logger . trace ( { config } , 'processBranch' ) ;
try {
logger . info ( ` Branch has ${ dependencies . length } 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.'
) ;
2017-10-18 13:28:51 +00:00
const subject = 'Renovate Ignore Notification' ;
2017-10-18 19:39:10 +00:00
let content ;
2017-10-18 13:28:51 +00:00
if ( config . isMajor ) {
2017-11-07 10:52:15 +00:00
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 . ` ;
2017-10-20 04:55:52 +00:00
} else if ( config . isDigest ) {
2017-11-07 10:52:15 +00:00
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 . ` ;
2017-10-18 13:28:51 +00:00
} else {
2017-11-07 10:52:15 +00:00
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. ` ;
2017-10-18 13:28:51 +00:00
}
2017-10-18 19:39:10 +00:00
content +=
'\n\nIf this PR was closed by mistake or you changed your mind, you can simply reopen or rename it to reactivate Renovate for this dependency version.' ;
2017-11-07 10:46:10 +00:00
await platform . ensureComment ( pr . number , subject , content ) ;
2017-08-28 13:50:11 +00:00
return 'already-existed' ;
2017-08-06 13:38:10 +00:00
}
2017-12-27 14:20:32 +00:00
logger . debug ( 'Checking if PR has been edited' ) ;
pr = await platform . findPr ( config . branchName , config . prTitle , 'open' ) ;
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-28 15:29:03 +00:00
if ( pr . state === 'open' ) {
logger . debug ( { pr } , 'Existing PR is open' ) ;
if ( ! pr . canRebase ) {
logger . warn ( 'PR has been edited' ) ;
/ *
const subject = 'PR has been edited' ;
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 {
logger . warn ( { pr } , 'PR state is not open' ) ;
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 ) {
if ( ! await platform . branchExists ( config . branchName ) ) {
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'
) ;
}
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 ) ) ;
2017-08-26 14:10:18 +00:00
if ( config . updatedPackageFiles . length ) {
logger . debug (
{ updatedPackageFiles : config . updatedPackageFiles } ,
` 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
}
2017-08-26 14:10:18 +00:00
Object . assign ( config , await getUpdatedLockFiles ( config ) ) ;
if ( config . updatedLockFiles . length ) {
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
}
2017-11-27 07:25:07 +00:00
const committedFiles = await commitFilesToBranch ( config ) ;
2017-11-28 08:00:59 +00:00
const branchExists = await platform . branchExists ( config . branchName ) ;
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
logger . debug ( 'Checking if we should automerge the branch' ) ;
2017-10-05 07:31:10 +00:00
const mergeStatus = await tryBranchAutomerge ( config ) ;
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
}
} catch ( err ) {
2017-09-02 06:51:49 +00:00
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 +=
'. This is usually happens when you have private modules but have not added configuration for [private module support](https://renovateapp.com/docs/deep-dives/private-modules). It is strongly recommended that you do not merge this PR as-is.' ;
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
}
2017-06-28 20:33:27 +00:00
} catch ( err ) {
2017-08-26 14:10:18 +00:00
logger . error ( { err } , ` Error ensuring PR: ${ err . message } ` ) ;
2017-08-28 13:50:11 +00:00
// Don't throw here - we don't want to stop the other renovations
2017-06-22 07:03:36 +00:00
}
2017-08-28 13:50:11 +00:00
return 'done' ;
2017-06-22 07:03:36 +00:00
}