Use Prettier (#181)

This commit is contained in:
Rhys Arkins 2017-04-21 10:12:41 +02:00 committed by GitHub
parent fc8ecb6af4
commit 06f8d50f5e
31 changed files with 833 additions and 375 deletions

View file

@ -4,15 +4,18 @@ module.exports = {
},
'extends': [
'airbnb-base',
'prettier',
],
'plugins': [
'import',
'promise',
'import',
'promise',
'prettier',
],
'rules': {
'no-use-before-define': 0,
'no-restricted-syntax': 0,
'no-await-in-loop': 0,
'prettier/prettier': ['error', { 'trailingComma': 'all', 'singleQuote': true }],
'promise/always-return': 'error',
'promise/no-return-wrap': 'error',
'promise/param-names': 'error',

View file

@ -6,11 +6,13 @@ const port = process.env.PORT || '3000';
const requestHandler = (request, response) => {
// Redirect users to Heroku dashboard
const appName = request.headers.host.split(':')[0].split('.')[0];
response.writeHead(302, { Location: `https://dashboard.heroku.com/apps/${appName}/logs` });
response.writeHead(302, {
Location: `https://dashboard.heroku.com/apps/${appName}/logs`,
});
response.end();
};
http.createServer(requestHandler).listen(port, (err) => {
http.createServer(requestHandler).listen(port, err => {
if (err) {
console.log('Failed to start web server', err);
return;

View file

@ -10,11 +10,15 @@ const envParser = require('../lib/config/env');
// Print table header
console.log('## Configuration Options');
console.log('');
console.log('| Name | Description | Type | Default value | Environment | CLI |');
console.log('|------|-------------|------|---------------|-------------|-----|');
console.log(
'| Name | Description | Type | Default value | Environment | CLI |',
);
console.log(
'|------|-------------|------|---------------|-------------|-----|',
);
const options = definitions.getOptions();
options.forEach((option) => {
options.forEach(option => {
let optionDefault = defaultsParser.getDefault(option);
if (optionDefault !== '') {
optionDefault = `\`${stringify(optionDefault)}\``;
@ -27,6 +31,8 @@ options.forEach((option) => {
if (cliName.length) {
cliName = `\`${cliName}\``;
}
console.log(`| \`${option.name}\` | ${option.description} | ${option.type} | ${optionDefault} | ${envName} | ${cliName} |`);
console.log(
`| \`${option.name}\` | ${option.description} | ${option.type} | ${optionDefault} | ${envName} | ${cliName} |`,
);
});
/* eslint-enable no-console */

View file

@ -13,7 +13,9 @@ Before you submit any code, it's recommended that you raise an issue first if yo
After you have cloned the project, first check that it's running OK locally.
`renovate` supports node versions 6 and above. It is written using async/await so either needs `babel` transpilation for node 6, or a harmony flag for node 7.
First you will need to install dependencies. We use [yarn](https://github.com/yarnpkg/yarn) so run `yarn` instead of `npm install`.
`renovate` supports node versions 6.9 and above. It is written using async/await so needs `babel` transpilation for node 6.
If running in node 6, you need to run a transpiled version of the code. You can do this without an explicit transpilation step by running `yarn run start-babel`.
Examples:
@ -29,10 +31,12 @@ If running on node 7, you can run just like the above, but use the `yarn run sta
## Adding configuration options
We wish to keep backwards-compatibility as often as possible, as well as make the code configurable, so most new functionality should be controllable via configuration options.
Please see [Cofiguration docs](docs/configuration.md) for a list of current options.
Please see [Configuration docs](docs/configuration.md) for a list of current options.
If you wish to add one, add it to `lib/config/definitions.js` and then run `yarn run update-docs`.
## Running tests
You can run `yarn test` locally to test your code. We don't have 100% coverage so new tests are desirable. We also run Continuous Integration using CircleCI.
You can run `yarn test` locally to test your code. We also run Continuous Integration using CircleCI.
We use [Prettier](https://github.com/prettier/prettier) for code formatting. If your code fails `yarn test` due to a `prettier` rule in `eslint` then it can be fixed by running `yarn run eslint-fix`;

View file

@ -88,7 +88,9 @@ async function initRepo(repoName, token, endpoint) {
// Returns an array of file paths in current repo matching the fileName
async function findFilePaths(fileName) {
const res = await ghGot(`search/code?q=repo:${config.repoName}+filename:${fileName}`);
const res = await ghGot(
`search/code?q=repo:${config.repoName}+filename:${fileName}`,
);
const exactMatches = res.body.items.filter(item => item.name === fileName);
// GitHub seems to return files in the root with a leading `/`
@ -102,12 +104,16 @@ async function findFilePaths(fileName) {
async function branchExists(branchName) {
logger.debug(`Checking if branch exists: ${branchName}`);
try {
const res = await ghGot(`repos/${config.repoName}/git/refs/heads/${branchName}`);
const res = await ghGot(
`repos/${config.repoName}/git/refs/heads/${branchName}`,
);
if (res.statusCode === 200) {
logger.debug(JSON.stringify(res.body));
if (Array.isArray(res.body)) {
// This seems to happen if GitHub has partial matches, so we check ref
const matchedBranch = res.body.some(branch => branch.ref === `refs/heads/${branchName}`);
const matchedBranch = res.body.some(
branch => branch.ref === `refs/heads/${branchName}`,
);
if (matchedBranch) {
logger.debug('Branch exists');
} else {
@ -119,12 +125,12 @@ async function branchExists(branchName) {
return res.body.ref === `refs/heads/${branchName}`;
}
// This probably shouldn't happen
logger.debug('Branch doesn\'t exist');
logger.debug("Branch doesn't exist");
return false;
} catch (error) {
if (error.statusCode === 404) {
// If file not found, then return false
logger.debug('Branch doesn\'t exist');
logger.debug("Branch doesn't exist");
return false;
}
// Propagate if it's any other error
@ -135,7 +141,8 @@ async function branchExists(branchName) {
// Returns the Pull Request for a branch. Null if not exists.
async function getBranchPr(branchName) {
logger.debug(`getBranchPr(${branchName})`);
const gotString = `repos/${config.repoName}/pulls?` +
const gotString =
`repos/${config.repoName}/pulls?` +
`state=open&base=${config.defaultBranch}&head=${config.owner}:${branchName}`;
const res = await ghGot(gotString);
if (!res.body.length) {
@ -167,14 +174,17 @@ async function addAssignees(issueNo, assignees) {
async function addReviewers(issueNo, reviewers) {
logger.debug(`Adding reviewers ${reviewers} to #${issueNo}`);
await ghGot.post(`repos/${config.repoName}/pulls/${issueNo}/requested_reviewers`, {
headers: {
accept: 'application/vnd.github.black-cat-preview+json',
await ghGot.post(
`repos/${config.repoName}/pulls/${issueNo}/requested_reviewers`,
{
headers: {
accept: 'application/vnd.github.black-cat-preview+json',
},
body: {
reviewers,
},
},
body: {
reviewers,
},
});
);
}
async function addLabels(issueNo, labels) {
@ -190,7 +200,7 @@ async function findPr(branchName, prTitle, state = 'all') {
logger.debug(`findPr urlString: ${urlString}`);
const res = await ghGot(urlString);
let pr = null;
res.body.forEach((result) => {
res.body.forEach(result => {
if (!prTitle || result.title === prTitle) {
pr = result;
if (pr.state === 'closed') {
@ -208,7 +218,10 @@ async function checkForClosedPr(branchName, prTitle) {
const url = `repos/${config.repoName}/pulls?state=closed&head=${config.owner}:${branchName}`;
const res = await ghGot(url);
// Return true if any of the titles match exactly
return res.body.some(pr => pr.title === prTitle && pr.head.label === `${config.owner}:${branchName}`);
return res.body.some(
pr =>
pr.title === prTitle && pr.head.label === `${config.owner}:${branchName}`,
);
}
// Creates PR and returns PR number
@ -244,7 +257,9 @@ async function getPr(prNo) {
} else {
// Check if only one author of all commits
logger.debug('Checking all commits');
const prCommits = (await ghGot(`repos/${config.repoName}/pulls/${prNo}/commits`)).body;
const prCommits = (await ghGot(
`repos/${config.repoName}/pulls/${prNo}/commits`,
)).body;
const authors = prCommits.reduce((arr, commit) => {
const author = commit.author.login;
if (arr.indexOf(author) === -1) {
@ -283,7 +298,9 @@ async function mergePr(pr) {
// Generic File operations
async function getFile(filePath, branchName = config.defaultBranch) {
const res = await ghGot(`repos/${config.repoName}/contents/${filePath}?ref=${branchName}`);
const res = await ghGot(
`repos/${config.repoName}/contents/${filePath}?ref=${branchName}`,
);
return res.body.content;
}
@ -310,8 +327,11 @@ async function commitFilesToBranch(
branchName,
files,
message,
parentBranch = config.defaultBranch) {
logger.debug(`commitFilesToBranch('${branchName}', files, message, '${parentBranch})'`);
parentBranch = config.defaultBranch,
) {
logger.debug(
`commitFilesToBranch('${branchName}', files, message, '${parentBranch})'`,
);
const parentCommit = await getBranchCommit(parentBranch);
const parentTree = await getCommitTree(parentCommit);
const fileBlobs = [];
@ -372,13 +392,15 @@ async function createBlob(fileContents) {
// Return the commit SHA for a branch
async function getBranchCommit(branchName) {
return (await ghGot(`repos/${config.repoName}/git/refs/heads/${branchName}`)).body.object.sha;
return (await ghGot(`repos/${config.repoName}/git/refs/heads/${branchName}`))
.body.object.sha;
}
// Return the tree SHA for a commit
async function getCommitTree(commit) {
logger.debug(`getCommitTree(${commit})`);
return (await ghGot(`repos/${config.repoName}/git/commits/${commit}`)).body.tree.sha;
return (await ghGot(`repos/${config.repoName}/git/commits/${commit}`)).body
.tree.sha;
}
// Create a tree and return SHA
@ -388,7 +410,7 @@ async function createTree(baseTree, files) {
base_tree: baseTree,
tree: [],
};
files.forEach((file) => {
files.forEach(file => {
body.tree.push({
path: file.name,
mode: '100644',
@ -397,7 +419,8 @@ async function createTree(baseTree, files) {
});
});
logger.debug(body);
return (await ghGot.post(`repos/${config.repoName}/git/trees`, { body })).body.sha;
return (await ghGot.post(`repos/${config.repoName}/git/trees`, { body })).body
.sha;
}
// Create a commit and return commit SHA

View file

@ -80,7 +80,7 @@ async function initRepo(repoName, token, endpoint) {
// Returns an array of file paths in current repo matching the fileName
async function findFilePaths(fileName) {
logger.verbose('Can\'t find multiple package.json files in GitLab');
logger.verbose("Can't find multiple package.json files in GitLab");
return [fileName];
}
@ -97,12 +97,12 @@ async function branchExists(branchName) {
return true;
}
// This probably shouldn't happen
logger.debug('Branch doesn\'t exist');
logger.debug("Branch doesn't exist");
return false;
} catch (error) {
if (error.statusCode === 404) {
// If file not found, then return false
logger.debug('Branch doesn\'t exist');
logger.debug("Branch doesn't exist");
return false;
}
// Propagate if it's any other error
@ -117,7 +117,7 @@ async function getBranchPr(branchName) {
const res = await glGot(urlString);
logger.debug(`Got res with ${res.body.length} results`);
let pr = null;
res.body.forEach((result) => {
res.body.forEach(result => {
if (result.source_branch === branchName) {
pr = result;
}
@ -145,7 +145,7 @@ async function getBranchStatus(branchName) {
}
let status = 'success';
// Return 'success' if all are success
res.body.forEach((check) => {
res.body.forEach(check => {
// If one is failed then don't overwrite that
if (status !== 'failed') {
if (check.status === 'failed') {
@ -187,8 +187,11 @@ async function findPr(branchName, prTitle, state = 'all') {
const urlString = `projects/${config.repoName}/merge_requests?state=${state}`;
const res = await glGot(urlString);
let pr = null;
res.body.forEach((result) => {
if ((!prTitle || result.title === prTitle) && result.source_branch === branchName) {
res.body.forEach(result => {
if (
(!prTitle || result.title === prTitle) &&
result.source_branch === branchName
) {
pr = result;
// GitHub uses number, GitLab uses iid
pr.number = pr.id;
@ -259,17 +262,22 @@ async function updatePr(prNo, title, body) {
}
async function mergePr(pr) {
await glGot.put(`projects/${config.repoName}/merge_requests/${pr.number}/merge`, {
body: {
should_remove_source_branch: true,
await glGot.put(
`projects/${config.repoName}/merge_requests/${pr.number}/merge`,
{
body: {
should_remove_source_branch: true,
},
},
});
);
}
// Generic File operations
async function getFile(filePath, branchName = config.defaultBranch) {
const res = await glGot(`projects/${config.repoName}/repository/files?file_path=${filePath}&ref=${branchName}`);
const res = await glGot(
`projects/${config.repoName}/repository/files?file_path=${filePath}&ref=${branchName}`,
);
return res.body.content;
}
@ -330,8 +338,11 @@ async function commitFilesToBranch(
branchName,
files,
message,
parentBranch = config.defaultBranch) {
logger.debug(`commitFilesToBranch('${branchName}', files, message, '${parentBranch})'`);
parentBranch = config.defaultBranch,
) {
logger.debug(
`commitFilesToBranch('${branchName}', files, message, '${parentBranch})'`,
);
if (branchName !== parentBranch) {
const isBranchExisting = await branchExists(branchName);
if (isBranchExisting) {

View file

@ -12,7 +12,10 @@ module.exports = {
async function getDependency(name) {
const scope = name.split('/')[0];
const regUrl = registryUrl(scope);
const pkgUrl = url.resolve(regUrl, encodeURIComponent(name).replace(/^%40/, '@'));
const pkgUrl = url.resolve(
regUrl,
encodeURIComponent(name).replace(/^%40/, '@'),
);
const authInfo = registryAuthToken(regUrl);
const headers = {};

View file

@ -20,18 +20,22 @@ function getConfig(argv) {
const config = {};
const coersions = {
boolean: val => (val === 'true'),
boolean: val => val === 'true',
list: val => val.split(',').map(el => el.trim()),
string: val => val,
};
let program = new commander.Command().arguments('[repositories...]');
options.forEach((option) => {
options.forEach(option => {
if (option.cli !== false) {
const param = `<${option.type}>`.replace('<boolean>', '[boolean]');
const optionString = `${getCliName(option)} ${param}`;
program = program.option(optionString, option.description, coersions[option.type]);
program = program.option(
optionString,
option.description,
coersions[option.type],
);
}
});
@ -41,19 +45,21 @@ function getConfig(argv) {
console.log(' Examples:');
console.log('');
console.log(' $ renovate --token abc123 singapore/lint-condo');
console.log(' $ renovate --ignore-unstable=false --log-level verbose singapore/lint-condo');
console.log(
' $ renovate --ignore-unstable=false --log-level verbose singapore/lint-condo',
);
console.log(' $ renovate singapore/lint-condo singapore/package-test');
/* eslint-enable no-console */
}
program = program
.on('--help', helpConsole)
.action((repositories) => {
.action(repositories => {
config.repositories = repositories;
})
.parse(argv);
options.forEach((option) => {
options.forEach(option => {
if (option.cli !== false) {
if (program[option.name] !== undefined) {
config[option.name] = program[option.name];

View file

@ -12,14 +12,16 @@ const defaultValues = {
};
function getDefault(option) {
return option.default === undefined ? defaultValues[option.type] : option.default;
return option.default === undefined
? defaultValues[option.type]
: option.default;
}
function getConfig() {
const options = configDefinitions.getOptions();
const config = {};
options.forEach((option) => {
options.forEach(option => {
config[option.name] = getDefault(option);
});

View file

@ -22,12 +22,12 @@ function getConfig(env) {
const config = {};
const coersions = {
boolean: val => (val === 'true'),
boolean: val => val === 'true',
list: val => val.split(',').map(el => el.trim()),
string: val => val,
};
options.forEach((option) => {
options.forEach(option => {
if (option.env !== false) {
const envName = getEnvName(option);
if (env[envName]) {

View file

@ -57,23 +57,33 @@ async function parseConfigs(env, argv) {
if (config.autodiscover) {
if (config.platform === 'github') {
logger.info('Autodiscovering GitHub repositories');
config.repositories = await githubApi.getRepos(config.token, config.endpoint);
config.repositories = await githubApi.getRepos(
config.token,
config.endpoint,
);
} else if (config.platform === 'gitlab') {
logger.info('Autodiscovering GitLab repositories');
config.repositories = await gitlabApi.getRepos(config.token, config.endpoint);
config.repositories = await gitlabApi.getRepos(
config.token,
config.endpoint,
);
}
if (!config.repositories || config.repositories.length === 0) {
// Soft fail (no error thrown) if no accessible repositories
logger.info('The account associated with your token does not have access to any repos');
logger.info(
'The account associated with your token does not have access to any repos',
);
return;
}
} else if (!config.repositories || config.repositories.length === 0) {
// We need at least one repository defined
throw new Error('At least one repository must be configured, or use --autodiscover');
throw new Error(
'At least one repository must be configured, or use --autodiscover',
);
}
// Configure each repository
config.repositories = config.repositories.map((item) => {
config.repositories = config.repositories.map(item => {
// Convert any repository strings to objects
const repo = typeof item === 'string' ? { repository: item } : item;
@ -89,7 +99,7 @@ async function parseConfigs(env, argv) {
}
// Expand packageFile format
repo.packageFiles = repo.packageFiles.map((packageFile) => {
repo.packageFiles = repo.packageFiles.map(packageFile => {
if (typeof packageFile === 'string') {
return { fileName: packageFile };
}
@ -119,8 +129,7 @@ function getRepositories() {
function redact(inputConfig) {
const tokenConfig = {};
if (inputConfig.token) {
tokenConfig.token =
`${inputConfig.token.substr(0, 4)}${new Array(inputConfig.token.length - 3).join('*')}`;
tokenConfig.token = `${inputConfig.token.substr(0, 4)}${new Array(inputConfig.token.length - 3).join('*')}`;
}
const redactedConfig = Object.assign({}, inputConfig, tokenConfig);
return stringify(redactedConfig);

View file

@ -11,12 +11,16 @@ function extractDependencies(packageJson, sections) {
// loop through dependency types
return sections.reduce((allDeps, depType) => {
// loop through each dependency within a type
const depNames = packageJson[depType] ? Object.keys(packageJson[depType]) : [];
return allDeps.concat(depNames.map(depName => ({
depType,
depName,
currentVersion: packageJson[depType][depName],
})));
const depNames = packageJson[depType]
? Object.keys(packageJson[depType])
: [];
return allDeps.concat(
depNames.map(depName => ({
depType,
depName,
currentVersion: packageJson[depType][depName],
})),
);
}, []);
}
@ -44,7 +48,12 @@ function setNewValue(currentFileContent, depType, depName, newVersion) {
if (matchAt(currentFileContent, searchIndex, searchString)) {
logger.debug(`Found match at index ${searchIndex}`);
// Now test if the result matches
const testContent = replaceAt(currentFileContent, searchIndex, searchString, newString);
const testContent = replaceAt(
currentFileContent,
searchIndex,
searchString,
newString,
);
// Compare the parsed JSON structure of old and new
if (_.isEqual(parsedContents, JSON.parse(testContent))) {
newFileContent = testContent;
@ -67,5 +76,9 @@ function matchAt(content, index, match) {
// Replace oldString with newString at location index of content
function replaceAt(content, index, oldString, newString) {
logger.debug(`Replacing ${oldString} with ${newString} at index ${index}`);
return content.substr(0, index) + newString + content.substr(index + oldString.length);
return (
content.substr(0, index) +
newString +
content.substr(index + oldString.length)
);
}

View file

@ -39,30 +39,45 @@ function determineUpgrades(dep, currentVersion, config) {
_(versionList)
// Filter out older versions as we can't upgrade to those
.filter(version => semver.gt(version, changeLogFromVersion))
// Ignore unstable versions, unless the current version is unstable
.reject(version => config.ignoreUnstable &&
stable.is(changeLogFromVersion) && !stable.is(version))
.reject(
version =>
config.ignoreUnstable &&
stable.is(changeLogFromVersion) &&
!stable.is(version),
)
// Ignore future versions, unless the current version is marked as future
.reject(version => config.ignoreFuture &&
!isFuture(versions[changeLogFromVersion]) && isFuture(versions[version]))
.reject(
version =>
config.ignoreFuture &&
!isFuture(versions[changeLogFromVersion]) &&
isFuture(versions[version]),
)
// Ignore versions newer than "latest", unless current version is newer than the "latest"
.reject(version => config.respectLatest &&
isPastLatest(dep, version) && !isPastLatest(dep, changeLogFromVersion))
.reject(
version =>
config.respectLatest &&
isPastLatest(dep, version) &&
!isPastLatest(dep, changeLogFromVersion),
)
// Loop through all possible versions
.forEach((newVersion) => {
.forEach(newVersion => {
// Group by major versions
const newVersionMajor = semver.major(newVersion);
// Only split majors if configured to do so, and no group or 'any' automerge
const separateMajors = config.separateMajorReleases && !config.groupName && config.automerge !== 'any';
const separateMajors =
config.separateMajorReleases &&
!config.groupName &&
config.automerge !== 'any';
const upgradeKey = separateMajors ? newVersionMajor : 'latest';
// Save this, if it's a new major version or greater than the previous greatest
if (!allUpgrades[upgradeKey] ||
semver.gt(newVersion, allUpgrades[upgradeKey].newVersion)) {
const upgradeType = newVersionMajor > semver.major(changeLogFromVersion) ? 'major' : 'minor';
if (
!allUpgrades[upgradeKey] ||
semver.gt(newVersion, allUpgrades[upgradeKey].newVersion)
) {
const upgradeType = newVersionMajor > semver.major(changeLogFromVersion)
? 'major'
: 'minor';
const changeLogToVersion = newVersion;
allUpgrades[upgradeKey] = {
upgradeType,
@ -96,48 +111,53 @@ function determineUpgrades(dep, currentVersion, config) {
const currentSemver = semverParsed[0];
// Loop through all upgrades and convert to ranges
return _(upgrades)
.reject(upgrade => upgrade.upgradeType === 'pin')
.map(upgrade => Object.assign(upgrade, { isRange: true }))
.map((upgrade) => {
const { major, minor } = semverUtils.parse(upgrade.newVersion);
if (currentSemver.operator === '~') {
// Utilise that a.b is the same as ~a.b.0
const minSatisfying = semver.minSatisfying(versionList, `${major}.${minor}`);
// Add a tilde before that version number
return Object.assign(upgrade, { newVersion: `~${minSatisfying}` });
} else if (currentSemver.operator === '^') {
// If version is < 1, then semver treats ^ same as ~
const newRange = major === '0' ? `${major}.${minor}` : `${major}`;
const minSatisfying = semver.minSatisfying(versionList, newRange);
// Add in the caret
return Object.assign(upgrade, { newVersion: `^${minSatisfying}` });
} else if (currentSemver.operator === '<=') {
// Example: <= 1.2.0
return Object.assign(upgrade, { newVersion: `<= ${upgrade.newVersion}` });
} else if (currentSemver.minor === undefined) {
// Example: 1
return Object.assign(upgrade, { newVersion: `${major}` });
} else if (currentSemver.minor === 'x') {
// Example: 1.x
return Object.assign(upgrade, { newVersion: `${major}.x` });
} else if (currentSemver.patch === undefined) {
// Example: 1.2
return Object.assign(upgrade, { newVersion: `${major}.${minor}` });
} else if (currentSemver.patch === 'x') {
// Example: 1.2.x
return Object.assign(upgrade, { newVersion: `${major}.${minor}.x` });
}
logger.warn(`Unsupported semver type: ${currentSemver}`);
return null;
})
.compact()
.value();
.reject(upgrade => upgrade.upgradeType === 'pin')
.map(upgrade => Object.assign(upgrade, { isRange: true }))
.map(upgrade => {
const { major, minor } = semverUtils.parse(upgrade.newVersion);
if (currentSemver.operator === '~') {
// Utilise that a.b is the same as ~a.b.0
const minSatisfying = semver.minSatisfying(
versionList,
`${major}.${minor}`,
);
// Add a tilde before that version number
return Object.assign(upgrade, { newVersion: `~${minSatisfying}` });
} else if (currentSemver.operator === '^') {
// If version is < 1, then semver treats ^ same as ~
const newRange = major === '0' ? `${major}.${minor}` : `${major}`;
const minSatisfying = semver.minSatisfying(versionList, newRange);
// Add in the caret
return Object.assign(upgrade, { newVersion: `^${minSatisfying}` });
} else if (currentSemver.operator === '<=') {
// Example: <= 1.2.0
return Object.assign(upgrade, {
newVersion: `<= ${upgrade.newVersion}`,
});
} else if (currentSemver.minor === undefined) {
// Example: 1
return Object.assign(upgrade, { newVersion: `${major}` });
} else if (currentSemver.minor === 'x') {
// Example: 1.x
return Object.assign(upgrade, { newVersion: `${major}.x` });
} else if (currentSemver.patch === undefined) {
// Example: 1.2
return Object.assign(upgrade, { newVersion: `${major}.${minor}` });
} else if (currentSemver.patch === 'x') {
// Example: 1.2.x
return Object.assign(upgrade, { newVersion: `${major}.${minor}.x` });
}
logger.warn(`Unsupported semver type: ${currentSemver}`);
return null;
})
.compact()
.value();
}
function isRange(input) {
// Pinned versions also return true for semver.validRange
// We need to check first that they're not 'valid' to get only ranges
return (semver.valid(input) === null && semver.validRange(input) !== null);
return semver.valid(input) === null && semver.validRange(input) !== null;
}
function isValidVersion(input) {
@ -145,7 +165,9 @@ function isValidVersion(input) {
}
function isFuture(version) {
return version && version.publishConfig && version.publishConfig.tag === 'future';
return (
version && version.publishConfig && version.publishConfig.tag === 'future'
);
}
function isPastLatest(dep, version) {

View file

@ -23,7 +23,10 @@ async function generateLockFile(newPackageJson, npmrcContent, yarnrcContent) {
fs.writeFileSync(path.join(tmpDir.name, '.yarnrc'), yarnrcContent);
}
logger.debug('Spawning yarn install');
const result = cp.spawnSync('yarn', ['install'], { cwd: tmpDir.name, shell: true });
const result = cp.spawnSync('yarn', ['install'], {
cwd: tmpDir.name,
shell: true,
});
logger.debug(String(result.stdout));
logger.debug(String(result.stderr));
yarnLock = fs.readFileSync(path.join(tmpDir.name, 'yarn.lock'));
@ -44,28 +47,41 @@ async function getLockFile(packageFile, packageContent, api) {
const npmrcContent = await api.getFileContent('.npmrc');
const yarnrcContent = await api.getFileContent('.yarnrc');
// Generate yarn.lock using shell command
const newYarnLockContent =
await module.exports.generateLockFile(packageContent, npmrcContent, yarnrcContent);
const newYarnLockContent = await module.exports.generateLockFile(
packageContent,
npmrcContent,
yarnrcContent,
);
// Return file object
return ({
return {
name: yarnLockFileName,
contents: newYarnLockContent,
});
};
}
async function maintainLockFile(inputConfig) {
logger.debug(`maintainYarnLock(${JSON.stringify(inputConfig)})`);
const packageContent = await inputConfig.api.getFileContent(inputConfig.packageFile);
const yarnLockFileName = path.join(path.dirname(inputConfig.packageFile), 'yarn.lock');
const packageContent = await inputConfig.api.getFileContent(
inputConfig.packageFile,
);
const yarnLockFileName = path.join(
path.dirname(inputConfig.packageFile),
'yarn.lock',
);
logger.debug(`Checking for ${yarnLockFileName}`);
const existingYarnLock = await inputConfig.api.getFileContent(yarnLockFileName);
const existingYarnLock = await inputConfig.api.getFileContent(
yarnLockFileName,
);
logger.silly(`existingYarnLock:\n${existingYarnLock}`);
if (!existingYarnLock) {
return null;
}
logger.debug('Found existing yarn.lock file');
const newYarnLock =
await module.exports.getLockFile(inputConfig.packageFile, packageContent, inputConfig.api);
const newYarnLock = await module.exports.getLockFile(
inputConfig.packageFile,
packageContent,
inputConfig.api,
);
logger.silly(`newYarnLock:\n${newYarnLock.contents}`);
if (existingYarnLock.toString() === newYarnLock.contents.toString()) {
logger.debug('Yarn lock file does not need updating');

View file

@ -39,7 +39,9 @@ async function processRepo(repo) {
} else if (config.platform === 'gitlab') {
api = gitlabApi;
} else {
logger.error(`Unknown platform ${config.platform} for repository ${repo.repository}`);
logger.error(
`Unknown platform ${config.platform} for repository ${repo.repository}`,
);
return;
}
logger.debug(`Processing repository: ${stringify(config)}`);
@ -113,12 +115,19 @@ If the default settings are all suitable for you, simply close this Pull Request
const defaultConfigString = `${stringify(defaultConfig)}\n`;
await api.commitFilesToBranch(
'renovate/configure',
[{
name: 'renovate.json',
contents: defaultConfigString,
}],
'Add renovate.json');
const pr = await api.createPr('renovate/configure', 'Configure Renovate', prBody);
[
{
name: 'renovate.json',
contents: defaultConfigString,
},
],
'Add renovate.json',
);
const pr = await api.createPr(
'renovate/configure',
'Configure Renovate',
prBody,
);
logger.info(`Created ${pr.displayNumber} for configuration`);
}
@ -137,8 +146,13 @@ async function getAllRepoUpgrades(repo) {
let upgrades = [];
for (const packageFile of repo.packageFiles) {
const cascadedConfig = configParser.getCascadedConfig(repo, packageFile);
upgrades = upgrades.concat(await worker.processPackageFile(repo.repository,
packageFile.fileName, cascadedConfig));
upgrades = upgrades.concat(
await worker.processPackageFile(
repo.repository,
packageFile.fileName,
cascadedConfig,
),
);
}
return upgrades;
}

View file

@ -3,9 +3,7 @@ const logger = require('winston');
// Colorize console logs
logger.configure({
level: process.env.LOG_LEVEL || 'info',
transports: [
new (logger.transports.Console)({ colorize: true }),
],
transports: [new logger.transports.Console({ colorize: true })],
});
module.exports = logger;

View file

@ -29,7 +29,9 @@ async function processPackageFile(repoName, packageFile, packageConfig) {
const packageContent = await config.api.getFileJson(packageFile);
// Check for renovate config inside the package.json
if (packageContent.renovate) {
logger.debug(`package.json>renovate config: ${stringify(packageContent.renovate)}`);
logger.debug(
`package.json>renovate config: ${stringify(packageContent.renovate)}`,
);
Object.assign(config, packageContent.renovate, { repoConfigured: true });
}
// Now check if config is disabled
@ -38,7 +40,7 @@ async function processPackageFile(repoName, packageFile, packageConfig) {
return [];
}
const depTypes = config.depTypes.map((depType) => {
const depTypes = config.depTypes.map(depType => {
if (typeof depType === 'string') {
return depType;
}
@ -46,16 +48,22 @@ async function processPackageFile(repoName, packageFile, packageConfig) {
});
// Extract all dependencies from the package.json
let dependencies = await packageJson.extractDependencies(packageContent, depTypes);
let dependencies = await packageJson.extractDependencies(
packageContent,
depTypes,
);
// Filter out ignored dependencies
dependencies =
dependencies.filter(dependency => config.ignoreDeps.indexOf(dependency.depName) === -1);
dependencies = dependencies.filter(
dependency => config.ignoreDeps.indexOf(dependency.depName) === -1,
);
dependencies = assignDepConfigs(config, dependencies);
// Find all upgrades for remaining dependencies
const upgrades = await findUpgrades(dependencies);
// Process all upgrades sequentially
if (config.maintainYarnLock) {
const upgrade = Object.assign({}, config, { upgradeType: 'maintainYarnLock' });
const upgrade = Object.assign({}, config, {
upgradeType: 'maintainYarnLock',
});
upgrade.upgradeType = 'maintainYarnLock';
upgrade.branchName = upgrade.yarnMaintenanceBranchName;
upgrade.prTitle = upgrade.yarnMaintenancePrTitle;
@ -67,17 +75,21 @@ async function processPackageFile(repoName, packageFile, packageConfig) {
// Add custom config for each dep
function assignDepConfigs(inputConfig, deps) {
return deps.map((dep) => {
return deps.map(dep => {
const returnDep = Object.assign({}, dep);
returnDep.config =
Object.assign({}, inputConfig, getDepTypeConfig(inputConfig.depTypes, dep.depType));
returnDep.config = Object.assign(
{},
inputConfig,
getDepTypeConfig(inputConfig.depTypes, dep.depType),
);
let packageRuleApplied = false;
if (returnDep.config.packages) {
// Loop through list looking for match
// Exit after first match
returnDep.config.packages.forEach((packageConfig) => {
returnDep.config.packages.forEach(packageConfig => {
if (!packageRuleApplied) {
const pattern = packageConfig.packagePattern || `^${packageConfig.packageName}$`;
const pattern =
packageConfig.packagePattern || `^${packageConfig.packageName}$`;
const packageRegex = new RegExp(pattern);
if (dep.depName.match(packageRegex)) {
packageRuleApplied = true;
@ -110,7 +122,7 @@ function assignDepConfigs(inputConfig, deps) {
function getDepTypeConfig(depTypes, depTypeName) {
let depTypeConfig = {};
if (depTypes) {
depTypes.forEach((depType) => {
depTypes.forEach(depType => {
if (typeof depType !== 'string' && depType.depType === depTypeName) {
depTypeConfig = depType;
}
@ -124,11 +136,14 @@ async function findUpgrades(dependencies) {
// findDepUpgrades can add more than one upgrade to allUpgrades
async function findDepUpgrades(dep) {
const npmDependency = await npmApi.getDependency(dep.depName);
const upgrades =
await versionsHelper.determineUpgrades(npmDependency, dep.currentVersion, dep.config);
const upgrades = await versionsHelper.determineUpgrades(
npmDependency,
dep.currentVersion,
dep.config,
);
if (upgrades.length > 0) {
logger.verbose(`${dep.depName}: Upgrades = ${JSON.stringify(upgrades)}`);
upgrades.forEach((upgrade) => {
upgrades.forEach(upgrade => {
allUpgrades.push(Object.assign({}, dep, upgrade));
});
} else {
@ -163,7 +178,8 @@ async function processUpgrades(upgrades) {
// Check whether to use a group name
if (flattened.groupName) {
flattened.groupSlug =
flattened.groupSlug || flattened.groupName.toLowerCase().replace(/[^a-z0-9+]+/g, '-');
flattened.groupSlug ||
flattened.groupName.toLowerCase().replace(/[^a-z0-9+]+/g, '-');
flattened.branchName = flattened.groupBranchName;
flattened.commitMessage = flattened.groupCommitMessage;
flattened.prTitle = flattened.groupPrTitle;
@ -190,10 +206,15 @@ async function updateBranch(upgrades) {
logger.verbose(`branchName '${branchName}' length is ${upgrades.length}`);
try {
if (upgrade0.upgradeType !== 'maintainYarnLock' &&
if (
upgrade0.upgradeType !== 'maintainYarnLock' &&
upgrade0.groupName === null &&
!upgrade0.recreateClosed && await upgrade0.api.checkForClosedPr(branchName, prTitle)) {
logger.verbose(`Skipping ${branchName} upgrade as matching closed PR already existed`);
!upgrade0.recreateClosed &&
(await upgrade0.api.checkForClosedPr(branchName, prTitle))
) {
logger.verbose(
`Skipping ${branchName} upgrade as matching closed PR already existed`,
);
return;
}
const branchCreated = await branchWorker.ensureBranch(upgrades);

View file

@ -10,7 +10,7 @@ module.exports = {
async function getParentBranch(branchName, config) {
// Check if branch exists
if (await config.api.branchExists(branchName) === false) {
if ((await config.api.branchExists(branchName)) === false) {
logger.verbose(`Creating new branch ${branchName}`);
return undefined;
}
@ -56,8 +56,13 @@ async function ensureBranch(upgrades) {
const branchName = handlebars.compile(upgrades[0].branchName)(upgrades[0]);
// parentBranch is the branch we will base off
// If undefined, this will mean the defaultBranch
const parentBranch = await module.exports.getParentBranch(branchName, upgrades[0]);
const commitMessage = handlebars.compile(upgrades[0].commitMessage)(upgrades[0]);
const parentBranch = await module.exports.getParentBranch(
branchName,
upgrades[0],
);
const commitMessage = handlebars.compile(upgrades[0].commitMessage)(
upgrades[0],
);
const api = upgrades[0].api;
const packageFiles = {};
const commitFiles = [];
@ -71,14 +76,17 @@ async function ensureBranch(upgrades) {
// See if this is the first time editing this file
if (!packageFiles[upgrade.packageFile]) {
// If we are rebasing then existing content will be from master
packageFiles[upgrade.packageFile] =
await api.getFileContent(upgrade.packageFile, parentBranch);
packageFiles[upgrade.packageFile] = await api.getFileContent(
upgrade.packageFile,
parentBranch,
);
}
const newContent = packageJsonHelper.setNewValue(
packageFiles[upgrade.packageFile],
upgrade.depType,
upgrade.depName,
upgrade.newVersion);
upgrade.newVersion,
);
if (packageFiles[upgrade.packageFile] === newContent) {
logger.debug('packageFile content unchanged');
delete packageFiles[upgrade.packageFile];
@ -89,15 +97,20 @@ async function ensureBranch(upgrades) {
}
}
if (Object.keys(packageFiles).length > 0) {
logger.debug(`${Object.keys(packageFiles).length} package file(s) need updating.`);
logger.debug(
`${Object.keys(packageFiles).length} package file(s) need updating.`,
);
for (const packageFile of Object.keys(packageFiles)) {
logger.debug(`Adding ${packageFile}`);
commitFiles.push({
name: packageFile,
contents: packageFiles[packageFile],
});
const yarnLockFile =
await yarnHelper.getLockFile(packageFile, packageFiles[packageFile], api);
const yarnLockFile = await yarnHelper.getLockFile(
packageFile,
packageFiles[packageFile],
api,
);
if (yarnLockFile) {
// Add new yarn.lock file too
logger.debug(`Adding ${yarnLockFile.name}`);
@ -108,7 +121,12 @@ async function ensureBranch(upgrades) {
if (commitFiles.length) {
logger.debug(`Commit ${commitFiles.length} files to branch ${branchName}`);
// API will know whether to create new branch or not
await api.commitFilesToBranch(branchName, commitFiles, commitMessage, parentBranch);
await api.commitFilesToBranch(
branchName,
commitFiles,
commitMessage,
parentBranch,
);
return true;
}
logger.debug(`No files to commit to branch ${branchName}`);

View file

@ -33,8 +33,11 @@ async function ensurePr(upgradeConfig) {
}
// Get changelog and then generate template strings
config.changelog =
await getChangeLog(config.depName, config.changeLogFromVersion, config.changeLogToVersion);
config.changelog = await getChangeLog(
config.depName,
config.changeLogFromVersion,
config.changeLogToVersion,
);
const prTitle = handlebars.compile(config.prTitle)(config);
const prBody = handlebars.compile(config.prBody)(config);
@ -58,8 +61,10 @@ async function ensurePr(upgradeConfig) {
await config.api.addLabels(pr.number, config.labels);
}
// Don't assign or review if automerging
if (config.automerge === 'none' ||
(config.automerge === 'minor' && config.upgradeType !== 'minor')) {
if (
config.automerge === 'none' ||
(config.automerge === 'minor' && config.upgradeType !== 'minor')
) {
if (config.assignees.length > 0) {
await config.api.addAssignees(pr.number, config.assignees);
}
@ -67,7 +72,9 @@ async function ensurePr(upgradeConfig) {
await config.api.addReviewers(pr.number, config.reviewers);
}
} else {
logger.debug(`Skipping assignees and reviewers as automerge=${config.automerge}`);
logger.debug(
`Skipping assignees and reviewers as automerge=${config.automerge}`,
);
}
logger.info(`Created ${pr.displayNumber}`);
return pr;
@ -79,8 +86,10 @@ async function ensurePr(upgradeConfig) {
async function checkAutoMerge(pr, config) {
logger.debug(`Checking #${pr.number} for automerge`);
if (config.automerge === 'any' ||
(config.automerge === 'minor' && config.upgradeType === 'minor')) {
if (
config.automerge === 'any' ||
(config.automerge === 'minor' && config.upgradeType === 'minor')
) {
logger.verbose('PR is configured for automerge');
logger.debug(JSON.stringify(pr));
// Return if PR not ready for automerge

View file

@ -63,10 +63,13 @@
"chai": "3.5.0",
"eslint": "3.19.0",
"eslint-config-airbnb-base": "11.1.3",
"eslint-config-prettier": "1.7.0",
"eslint-plugin-import": "2.2.0",
"eslint-plugin-prettier": "2.0.1",
"eslint-plugin-promise": "3.5.0",
"mkdirp": "0.5.1",
"np": "2.13.2",
"prettier": "1.2.2",
"rimraf": "2.6.1"
},
"babel": {

View file

@ -84,7 +84,12 @@ describe('api/github', () => {
describe('initRepo', () => {
[
[undefined, ['mytoken'], 'mytoken', undefined],
[undefined, ['mytoken', 'https://my.custom.endpoint/'], 'mytoken', 'https://my.custom.endpoint/'],
[
undefined,
['mytoken', 'https://my.custom.endpoint/'],
'mytoken',
'https://my.custom.endpoint/',
],
['myenvtoken', [], 'myenvtoken', undefined],
].forEach(([envToken, args, token, endpoint], i) => {
it(`should initialise the config for the repo - ${i}`, async () => {
@ -105,7 +110,9 @@ describe('api/github', () => {
} catch (e) {
err = e;
}
expect(err.message).toBe('No token found for GitHub repository some/repo');
expect(err.message).toBe(
'No token found for GitHub repository some/repo',
);
});
it('should squash', async () => {
async function squashInitRepo(...args) {
@ -182,10 +189,13 @@ describe('api/github', () => {
ghGot.mockImplementationOnce(() => ({
body: {
items: [
{ name: 'package.json', path: '/package.json' },
{ name: 'package.json.something-else', path: 'some-dir/package.json.some-thing-else' },
{ name: 'package.json', path: 'src/app/package.json' },
{ name: 'package.json', path: 'src/otherapp/package.json' },
{ name: 'package.json', path: '/package.json' },
{
name: 'package.json.something-else',
path: 'some-dir/package.json.some-thing-else',
},
{ name: 'package.json', path: 'src/app/package.json' },
{ name: 'package.json', path: 'src/otherapp/package.json' },
],
},
}));
@ -211,11 +221,14 @@ describe('api/github', () => {
await initRepo('some/repo', 'token');
ghGot.mockImplementationOnce(() => ({
statusCode: 200,
body: [{
ref: 'refs/heads/notthebranchname',
}, {
ref: 'refs/heads/thebranchname',
}],
body: [
{
ref: 'refs/heads/notthebranchname',
},
{
ref: 'refs/heads/thebranchname',
},
],
}));
const exists = await github.branchExists('thebranchname');
expect(ghGot.mock.calls).toMatchSnapshot();
@ -237,11 +250,14 @@ describe('api/github', () => {
await initRepo('some/repo', 'token');
ghGot.mockImplementationOnce(() => ({
statusCode: 200,
body: [{
ref: 'refs/heads/notthebranchname',
}, {
ref: 'refs/heads/alsonotthebranchname',
}],
body: [
{
ref: 'refs/heads/notthebranchname',
},
{
ref: 'refs/heads/alsonotthebranchname',
},
],
}));
const exists = await github.branchExists('thebranchname');
expect(ghGot.mock.calls).toMatchSnapshot();
@ -258,16 +274,20 @@ describe('api/github', () => {
});
it('should return false if a 404 is returned', async () => {
await initRepo('some/repo', 'token');
ghGot.mockImplementationOnce(() => Promise.reject({
statusCode: 404,
}));
ghGot.mockImplementationOnce(() =>
Promise.reject({
statusCode: 404,
}),
);
const exists = await github.branchExists('thebranchname');
expect(ghGot.mock.calls).toMatchSnapshot();
expect(exists).toBe(false);
});
it('should propagate unknown errors', async () => {
await initRepo('some/repo', 'token');
ghGot.mockImplementationOnce(() => Promise.reject(new Error('Something went wrong')));
ghGot.mockImplementationOnce(() =>
Promise.reject(new Error('Something went wrong')),
);
let err;
try {
await github.branchExists('thebranchname');
@ -291,9 +311,7 @@ describe('api/github', () => {
it('should return the PR object', async () => {
await initRepo('some/repo', 'token');
ghGot.mockImplementationOnce(() => ({
body: [
{ number: 91 },
],
body: [{ number: 91 }],
}));
ghGot.mockImplementationOnce(() => ({
body: {
@ -358,15 +376,13 @@ describe('api/github', () => {
it('should return a PR object', async () => {
await initRepo('some/repo', 'token');
ghGot.mockImplementationOnce(() => ({
body: [
{ title: 'PR Title', state: 'open', number: 42 },
],
body: [{ title: 'PR Title', state: 'open', number: 42 }],
}));
const pr = await github.findPr('master', 'PR Title');
expect(ghGot.mock.calls).toMatchSnapshot();
expect(pr).toMatchSnapshot();
});
it('should return null if no PR\'s are found', async () => {
it("should return null if no PR's are found", async () => {
await initRepo('some/repo', 'token');
ghGot.mockImplementationOnce(() => ({
body: [],
@ -378,9 +394,7 @@ describe('api/github', () => {
it('should set the isClosed attribute of the PR to true if the PR is closed', async () => {
await initRepo('some/repo', 'token');
ghGot.mockImplementationOnce(() => ({
body: [
{ title: 'PR Title', state: 'closed', number: 42 },
],
body: [{ title: 'PR Title', state: 'closed', number: 42 }],
}));
const pr = await github.findPr('master');
expect(ghGot.mock.calls).toMatchSnapshot();
@ -397,9 +411,9 @@ describe('api/github', () => {
await initRepo('some/repo', 'token');
ghGot.mockImplementationOnce(() => ({
body: [
{ title: 'foo', head: { label: 'theowner:some-branch' } },
{ title: 'bar', head: { label: 'theowner:some-other-branch' } },
{ title: 'baz', head: { label: 'theowner:some-branch' } },
{ title: 'foo', head: { label: 'theowner:some-branch' } },
{ title: 'bar', head: { label: 'theowner:some-other-branch' } },
{ title: 'baz', head: { label: 'theowner:some-branch' } },
],
}));
const res = await github.checkForClosedPr(branch, title);
@ -415,7 +429,11 @@ describe('api/github', () => {
number: 123,
},
}));
const pr = await github.createPr('some-branch', 'The Title', 'Hello world');
const pr = await github.createPr(
'some-branch',
'The Title',
'Hello world',
);
expect(pr).toMatchSnapshot();
expect(ghGot.post.mock.calls).toMatchSnapshot();
});
@ -435,7 +453,13 @@ describe('api/github', () => {
});
[
{ number: 1, state: 'closed', base: { sha: '1234' } },
{ number: 1, state: 'open', mergeable_state: 'dirty', base: { sha: '1234' }, commits: 1 },
{
number: 1,
state: 'open',
mergeable_state: 'dirty',
base: { sha: '1234' },
commits: 1,
},
{ number: 1, state: 'open', base: { sha: '5678' }, commits: 1 },
].forEach((body, i) => {
it(`should return a PR object - ${i}`, async () => {
@ -459,11 +483,13 @@ describe('api/github', () => {
},
}));
ghGot.mockImplementationOnce(() => ({
body: [{
author: {
login: 'foo',
body: [
{
author: {
login: 'foo',
},
},
}],
],
}));
const pr = await github.getPr(1234);
expect(pr).toMatchSnapshot();
@ -480,15 +506,18 @@ describe('api/github', () => {
},
}));
ghGot.mockImplementationOnce(() => ({
body: [{
author: {
login: 'foo',
body: [
{
author: {
login: 'foo',
},
},
}, {
author: {
login: 'bar',
{
author: {
login: 'bar',
},
},
}],
],
}));
const pr = await github.getPr(1234);
expect(pr).toMatchSnapshot();
@ -629,11 +658,17 @@ describe('api/github', () => {
ref: 'refs/heads/package.json',
},
}));
const files = [{
name: 'package.json',
contents: 'hello world',
}];
await github.commitFilesToBranch('package.json', files, 'my commit message');
const files = [
{
name: 'package.json',
contents: 'hello world',
},
];
await github.commitFilesToBranch(
'package.json',
files,
'my commit message',
);
expect(ghGot.mock.calls).toMatchSnapshot();
expect(ghGot.post.mock.calls).toMatchSnapshot();
expect(ghGot.patch.mock.calls).toMatchSnapshot();
@ -643,11 +678,17 @@ describe('api/github', () => {
ghGot.mockImplementationOnce(() => ({
statusCode: 404,
}));
const files = [{
name: 'package.json',
contents: 'hello world',
}];
await github.commitFilesToBranch('package.json', files, 'my other commit message');
const files = [
{
name: 'package.json',
contents: 'hello world',
},
];
await github.commitFilesToBranch(
'package.json',
files,
'my other commit message',
);
expect(ghGot.mock.calls).toMatchSnapshot();
expect(ghGot.post.mock.calls).toMatchSnapshot();
expect(ghGot.patch.mock.calls).toMatchSnapshot();

View file

@ -17,18 +17,29 @@ describe('api/npm', () => {
const res = await npm.getDependency('foobar');
expect(res).toMatchObject({ some: 'data' });
const call = got.mock.calls[0];
expect(call).toMatchObject(['https://npm.mycustomregistry.com/foobar', { json: true, headers: {} }]);
expect(call).toMatchObject([
'https://npm.mycustomregistry.com/foobar',
{ json: true, headers: {} },
]);
});
it('should send an authorization header if provided', async () => {
registryUrl.mockImplementation(() => 'https://npm.mycustomregistry.com/');
registryAuthToken.mockImplementation(() => ({ type: 'Basic', token: '1234' }));
registryAuthToken.mockImplementation(() => ({
type: 'Basic',
token: '1234',
}));
got.mockImplementation(() => Promise.resolve({ body: { some: 'data' } }));
const res = await npm.getDependency('foobar');
expect(res).toMatchObject({ some: 'data' });
const call = got.mock.calls[0];
expect(call).toMatchObject(['https://npm.mycustomregistry.com/foobar', { json: true,
headers: {
authorization: 'Basic 1234',
} }]);
expect(call).toMatchObject([
'https://npm.mycustomregistry.com/foobar',
{
json: true,
headers: {
authorization: 'Basic 1234',
},
},
]);
});
});

View file

@ -9,7 +9,9 @@ describe('config/file', () => {
});
it('parses custom config file', () => {
const configFile = path.resolve(__dirname, '../_fixtures/config/file.js');
file.getConfig({ RENOVATE_CONFIG_FILE: configFile }).should.eql(customConfig);
file
.getConfig({ RENOVATE_CONFIG_FILE: configFile })
.should.eql(customConfig);
});
});
});

View file

@ -55,7 +55,9 @@ describe('config/index', () => {
} catch (e) {
err = e;
}
expect(err.message).toBe('At least one repository must be configured, or use --autodiscover');
expect(err.message).toBe(
'At least one repository must be configured, or use --autodiscover',
);
});
it('supports token in CLI options', async () => {
defaultArgv = defaultArgv.concat(['--token=abc']);
@ -66,7 +68,9 @@ describe('config/index', () => {
} catch (e) {
err = e;
}
expect(err.message).toBe('At least one repository must be configured, or use --autodiscover');
expect(err.message).toBe(
'At least one repository must be configured, or use --autodiscover',
);
});
it('autodiscovers github platform', async () => {
const env = {};
@ -87,7 +91,11 @@ describe('config/index', () => {
});
it('autodiscovers gitlab platform', async () => {
const env = {};
defaultArgv = defaultArgv.concat(['--autodiscover', '--platform=gitlab', '--token=abc']);
defaultArgv = defaultArgv.concat([
'--autodiscover',
'--platform=gitlab',
'--token=abc',
]);
glGot.mockImplementationOnce(() => ({
body: [
{

View file

@ -17,7 +17,9 @@ describe('helpers/changelog', () => {
});
it('returns header if generated markdown is valid', async () => {
changelog.markdown.mockReturnValueOnce('dummy');
expect(await getChangeLog('renovate', '1.0.0', '2.0.0')).toBe('### Changelog\n\ndummy');
expect(await getChangeLog('renovate', '1.0.0', '2.0.0')).toBe(
'### Changelog\n\ndummy',
);
});
it('returns empty if error thrown', async () => {
changelog.markdown = jest.fn(() => {

View file

@ -2,10 +2,17 @@ const fs = require('fs');
const path = require('path');
const packageJson = require('../../lib/helpers/package-json');
const defaultTypes = ['dependencies', 'devDependencies', 'optionalDependencies'];
const defaultTypes = [
'dependencies',
'devDependencies',
'optionalDependencies',
];
function readFixture(fixture) {
return fs.readFileSync(path.resolve(__dirname, `../_fixtures/package-json/${fixture}`), 'utf8');
return fs.readFileSync(
path.resolve(__dirname, `../_fixtures/package-json/${fixture}`),
'utf8',
);
}
const input01Content = readFixture('inputs/01.json');
@ -14,20 +21,27 @@ const input02Content = readFixture('inputs/02.json');
describe('helpers/package-json', () => {
describe('.extractDependencies(packageJson, sections)', () => {
it('returns an array of correct length', () => {
const extractedDependencies =
packageJson.extractDependencies(JSON.parse(input01Content), defaultTypes);
const extractedDependencies = packageJson.extractDependencies(
JSON.parse(input01Content),
defaultTypes,
);
extractedDependencies.should.be.instanceof(Array);
extractedDependencies.should.have.length(10);
});
it('each element contains non-null depType, depName, currentVersion', () => {
const extractedDependencies =
packageJson.extractDependencies(JSON.parse(input01Content), defaultTypes);
extractedDependencies.every(dep => dep.depType && dep.depName && dep.currentVersion)
const extractedDependencies = packageJson.extractDependencies(
JSON.parse(input01Content),
defaultTypes,
);
extractedDependencies
.every(dep => dep.depType && dep.depName && dep.currentVersion)
.should.eql(true);
});
it('supports null devDependencies', () => {
const extractedDependencies =
packageJson.extractDependencies(JSON.parse(input02Content), defaultTypes);
const extractedDependencies = packageJson.extractDependencies(
JSON.parse(input02Content),
defaultTypes,
);
extractedDependencies.should.be.instanceof(Array);
extractedDependencies.should.have.length(6);
});
@ -35,25 +49,41 @@ describe('helpers/package-json', () => {
describe('.setNewValue(currentFileContent, depType, depName, newVersion)', () => {
it('replaces a dependency value', () => {
const outputContent = readFixture('outputs/011.json');
const testContent =
packageJson.setNewValue(input01Content, 'dependencies', 'cheerio', '0.22.1');
const testContent = packageJson.setNewValue(
input01Content,
'dependencies',
'cheerio',
'0.22.1',
);
testContent.should.equal(outputContent);
});
it('replaces only the first instance of a value', () => {
const outputContent = readFixture('outputs/012.json');
const testContent =
packageJson.setNewValue(input01Content, 'devDependencies', 'angular-touch', '1.6.1');
const testContent = packageJson.setNewValue(
input01Content,
'devDependencies',
'angular-touch',
'1.6.1',
);
testContent.should.equal(outputContent);
});
it('replaces only the second instance of a value', () => {
const outputContent = readFixture('outputs/013.json');
const testContent =
packageJson.setNewValue(input01Content, 'devDependencies', 'angular-sanitize', '1.6.1');
const testContent = packageJson.setNewValue(
input01Content,
'devDependencies',
'angular-sanitize',
'1.6.1',
);
testContent.should.equal(outputContent);
});
it('handles the case where the desired version is already supported', () => {
const testContent =
packageJson.setNewValue(input01Content, 'devDependencies', 'angular-touch', '1.5.8');
const testContent = packageJson.setNewValue(
input01Content,
'devDependencies',
'angular-touch',
'1.5.8',
);
testContent.should.equal(input01Content);
});
});

View file

@ -10,20 +10,26 @@ describe('helpers/versions', () => {
describe('.determineUpgrades(dep, currentVersion, defaultConfig)', () => {
it('return empty if invalid current version', () => {
versionsHelper.determineUpgrades(qJson, 'invalid', defaultConfig).should.have.length(0);
versionsHelper
.determineUpgrades(qJson, 'invalid', defaultConfig)
.should.have.length(0);
});
it('return empty if null versions', () => {
const testDep = {
name: 'q',
};
versionsHelper.determineUpgrades(testDep, '1.0.0', defaultConfig).should.have.length(0);
versionsHelper
.determineUpgrades(testDep, '1.0.0', defaultConfig)
.should.have.length(0);
});
it('return empty if empty versions', () => {
const testDep = {
name: 'q',
versions: [],
};
versionsHelper.determineUpgrades(testDep, '1.0.0', defaultConfig).should.have.length(0);
versionsHelper
.determineUpgrades(testDep, '1.0.0', defaultConfig)
.should.have.length(0);
});
it('supports minor and major upgrades for tilde ranges', () => {
const upgradeVersions = [
@ -42,22 +48,32 @@ describe('helpers/versions', () => {
changeLogToVersion: '1.4.1',
},
];
versionsHelper.determineUpgrades(qJson, '^0.4.0', defaultConfig).should.eql(upgradeVersions);
versionsHelper
.determineUpgrades(qJson, '^0.4.0', defaultConfig)
.should.eql(upgradeVersions);
});
it('returns only one update if grouping', () => {
defaultConfig.groupName = 'somegroup';
expect(versionsHelper.determineUpgrades(qJson, '^0.4.0', defaultConfig)).toMatchSnapshot();
expect(
versionsHelper.determineUpgrades(qJson, '^0.4.0', defaultConfig),
).toMatchSnapshot();
});
it('returns only one update if automerging any', () => {
defaultConfig.automerge = 'any';
expect(versionsHelper.determineUpgrades(qJson, '^0.4.0', defaultConfig)).toMatchSnapshot();
expect(
versionsHelper.determineUpgrades(qJson, '^0.4.0', defaultConfig),
).toMatchSnapshot();
});
it('returns both updates if automerging minor', () => {
defaultConfig.automerge = 'minor';
expect(versionsHelper.determineUpgrades(qJson, '^0.4.0', defaultConfig)).toMatchSnapshot();
expect(
versionsHelper.determineUpgrades(qJson, '^0.4.0', defaultConfig),
).toMatchSnapshot();
});
it('disables major release separation (major)', () => {
const config = Object.assign({}, defaultConfig, { separateMajorReleases: false });
const config = Object.assign({}, defaultConfig, {
separateMajorReleases: false,
});
const upgradeVersions = [
{
newVersion: '1.4.1',
@ -67,10 +83,14 @@ describe('helpers/versions', () => {
changeLogToVersion: '1.4.1',
},
];
versionsHelper.determineUpgrades(qJson, '^0.4.0', config).should.eql(upgradeVersions);
versionsHelper
.determineUpgrades(qJson, '^0.4.0', config)
.should.eql(upgradeVersions);
});
it('disables major release separation (minor)', () => {
const config = Object.assign({}, defaultConfig, { separateMajorReleases: false });
const config = Object.assign({}, defaultConfig, {
separateMajorReleases: false,
});
const upgradeVersions = [
{
newVersion: '1.4.1',
@ -80,7 +100,9 @@ describe('helpers/versions', () => {
changeLogToVersion: '1.4.1',
},
];
versionsHelper.determineUpgrades(qJson, '1.0.0', config).should.eql(upgradeVersions);
versionsHelper
.determineUpgrades(qJson, '1.0.0', config)
.should.eql(upgradeVersions);
});
it('supports minor and major upgrades for ranged versions', () => {
const pinVersions = [
@ -99,7 +121,9 @@ describe('helpers/versions', () => {
changeLogToVersion: '1.4.1',
},
];
versionsHelper.determineUpgrades(qJson, '~0.4.0', defaultConfig).should.eql(pinVersions);
versionsHelper
.determineUpgrades(qJson, '~0.4.0', defaultConfig)
.should.eql(pinVersions);
});
it('ignores pinning for ranges when other upgrade exists', () => {
const pinVersions = [
@ -111,7 +135,9 @@ describe('helpers/versions', () => {
changeLogToVersion: '1.4.1',
},
];
expect(versionsHelper.determineUpgrades(qJson, '~0.9.0', defaultConfig)).toEqual(pinVersions);
expect(
versionsHelper.determineUpgrades(qJson, '~0.9.0', defaultConfig),
).toEqual(pinVersions);
});
it('upgrades minor ranged versions', () => {
const upgradeVersions = [
@ -123,7 +149,9 @@ describe('helpers/versions', () => {
changeLogToVersion: '1.4.1',
},
];
expect(versionsHelper.determineUpgrades(qJson, '~1.0.0', defaultConfig)).toEqual(upgradeVersions);
expect(
versionsHelper.determineUpgrades(qJson, '~1.0.0', defaultConfig),
).toEqual(upgradeVersions);
});
it('pins minor ranged versions', () => {
const upgradeVersions = [
@ -133,11 +161,15 @@ describe('helpers/versions', () => {
upgradeType: 'pin',
},
];
expect(versionsHelper.determineUpgrades(qJson, '^1.0.0', defaultConfig)).toEqual(upgradeVersions);
expect(
versionsHelper.determineUpgrades(qJson, '^1.0.0', defaultConfig),
).toEqual(upgradeVersions);
});
it('ignores minor ranged versions when not pinning', () => {
const config = Object.assign({}, defaultConfig, { pinVersions: false });
expect(versionsHelper.determineUpgrades(qJson, '^1.0.0', config)).toHaveLength(0);
expect(
versionsHelper.determineUpgrades(qJson, '^1.0.0', config),
).toHaveLength(0);
});
it('upgrades tilde ranges', () => {
const upgradeVersions = [
@ -149,7 +181,9 @@ describe('helpers/versions', () => {
changeLogToVersion: '1.4.1',
},
];
expect(versionsHelper.determineUpgrades(qJson, '~1.3.0', defaultConfig)).toEqual(upgradeVersions);
expect(
versionsHelper.determineUpgrades(qJson, '~1.3.0', defaultConfig),
).toEqual(upgradeVersions);
});
it('upgrades .x minor ranges', () => {
const upgradeVersions = [
@ -161,7 +195,9 @@ describe('helpers/versions', () => {
changeLogToVersion: '1.4.1',
},
];
expect(versionsHelper.determineUpgrades(qJson, '1.3.x', defaultConfig)).toEqual(upgradeVersions);
expect(
versionsHelper.determineUpgrades(qJson, '1.3.x', defaultConfig),
).toEqual(upgradeVersions);
});
it('upgrades tilde ranges without pinning', () => {
const upgradeVersions = [
@ -175,7 +211,9 @@ describe('helpers/versions', () => {
},
];
const config = Object.assign({}, defaultConfig, { pinVersions: false });
expect(versionsHelper.determineUpgrades(qJson, '~1.3.0', config)).toEqual(upgradeVersions);
expect(versionsHelper.determineUpgrades(qJson, '~1.3.0', config)).toEqual(
upgradeVersions,
);
});
it('upgrades .x major ranges without pinning', () => {
const upgradeVersions = [
@ -189,7 +227,9 @@ describe('helpers/versions', () => {
},
];
const config = Object.assign({}, defaultConfig, { pinVersions: false });
expect(versionsHelper.determineUpgrades(qJson, '0.x', config)).toEqual(upgradeVersions);
expect(versionsHelper.determineUpgrades(qJson, '0.x', config)).toEqual(
upgradeVersions,
);
});
it('upgrades .x minor ranges without pinning', () => {
const upgradeVersions = [
@ -203,7 +243,9 @@ describe('helpers/versions', () => {
},
];
const config = Object.assign({}, defaultConfig, { pinVersions: false });
expect(versionsHelper.determineUpgrades(qJson, '1.3.x', config)).toEqual(upgradeVersions);
expect(versionsHelper.determineUpgrades(qJson, '1.3.x', config)).toEqual(
upgradeVersions,
);
});
it('upgrades shorthand major ranges without pinning', () => {
const upgradeVersions = [
@ -217,7 +259,9 @@ describe('helpers/versions', () => {
},
];
const config = Object.assign({}, defaultConfig, { pinVersions: false });
expect(versionsHelper.determineUpgrades(qJson, '0', config)).toEqual(upgradeVersions);
expect(versionsHelper.determineUpgrades(qJson, '0', config)).toEqual(
upgradeVersions,
);
});
it('upgrades shorthand minor ranges without pinning', () => {
const upgradeVersions = [
@ -231,7 +275,9 @@ describe('helpers/versions', () => {
},
];
const config = Object.assign({}, defaultConfig, { pinVersions: false });
expect(versionsHelper.determineUpgrades(qJson, '1.3', config)).toEqual(upgradeVersions);
expect(versionsHelper.determineUpgrades(qJson, '1.3', config)).toEqual(
upgradeVersions,
);
});
it('upgrades multiple tilde ranges without pinning', () => {
const upgradeVersions = [
@ -253,7 +299,9 @@ describe('helpers/versions', () => {
},
];
const config = Object.assign({}, defaultConfig, { pinVersions: false });
expect(versionsHelper.determineUpgrades(qJson, '~0.7.0', config)).toEqual(upgradeVersions);
expect(versionsHelper.determineUpgrades(qJson, '~0.7.0', config)).toEqual(
upgradeVersions,
);
});
it('upgrades multiple caret ranges without pinning', () => {
const upgradeVersions = [
@ -275,15 +323,21 @@ describe('helpers/versions', () => {
},
];
const config = Object.assign({}, defaultConfig, { pinVersions: false });
expect(versionsHelper.determineUpgrades(qJson, '^0.7.0', config)).toEqual(upgradeVersions);
expect(versionsHelper.determineUpgrades(qJson, '^0.7.0', config)).toEqual(
upgradeVersions,
);
});
it('ignores complex ranges when not pinning', () => {
const config = Object.assign({}, defaultConfig, { pinVersions: false });
expect(versionsHelper.determineUpgrades(qJson, '^0.7.0 || ^0.8.0', config)).toHaveLength(0);
expect(
versionsHelper.determineUpgrades(qJson, '^0.7.0 || ^0.8.0', config),
).toHaveLength(0);
});
it('returns nothing for greater than ranges', () => {
const config = Object.assign({}, defaultConfig, { pinVersions: false });
expect(versionsHelper.determineUpgrades(qJson, '>= 0.7.0', config)).toHaveLength(0);
expect(
versionsHelper.determineUpgrades(qJson, '>= 0.7.0', config),
).toHaveLength(0);
});
it('upgrades less than equal ranges without pinning', () => {
const upgradeVersions = [
@ -305,11 +359,15 @@ describe('helpers/versions', () => {
},
];
const config = Object.assign({}, defaultConfig, { pinVersions: false });
expect(versionsHelper.determineUpgrades(qJson, '<= 0.7.2', config)).toEqual(upgradeVersions);
expect(
versionsHelper.determineUpgrades(qJson, '<= 0.7.2', config),
).toEqual(upgradeVersions);
});
it('rejects less than ranges without pinning', () => {
const config = Object.assign({}, defaultConfig, { pinVersions: false });
expect(versionsHelper.determineUpgrades(qJson, '< 0.7.2', config)).toEqual([]);
expect(
versionsHelper.determineUpgrades(qJson, '< 0.7.2', config),
).toEqual([]);
});
it('supports > latest versions if configured', () => {
const config = Object.assign({}, defaultConfig);
@ -323,7 +381,9 @@ describe('helpers/versions', () => {
changeLogToVersion: '2.0.1',
},
];
versionsHelper.determineUpgrades(qJson, '1.4.1', config).should.eql(upgradeVersions);
versionsHelper
.determineUpgrades(qJson, '1.4.1', config)
.should.eql(upgradeVersions);
});
it('supports future versions if configured', () => {
const config = Object.assign({}, defaultConfig);
@ -338,7 +398,9 @@ describe('helpers/versions', () => {
changeLogToVersion: '2.0.3',
},
];
versionsHelper.determineUpgrades(qJson, '1.4.1', config).should.eql(upgradeVersions);
versionsHelper
.determineUpgrades(qJson, '1.4.1', config)
.should.eql(upgradeVersions);
});
it('supports future versions if already future', () => {
const upgradeVersions = [
@ -348,16 +410,24 @@ describe('helpers/versions', () => {
upgradeType: 'pin',
},
];
versionsHelper.determineUpgrades(qJson, '^2.0.0', defaultConfig).should.eql(upgradeVersions);
versionsHelper
.determineUpgrades(qJson, '^2.0.0', defaultConfig)
.should.eql(upgradeVersions);
});
it('should ignore unstable versions if the current version is stable', () => {
versionsHelper.determineUpgrades({
name: 'amazing-package',
versions: {
'1.0.0': {},
'1.1.0-beta': {},
},
}, '1.0.0', defaultConfig).should.eql([]);
versionsHelper
.determineUpgrades(
{
name: 'amazing-package',
versions: {
'1.0.0': {},
'1.1.0-beta': {},
},
},
'1.0.0',
defaultConfig,
)
.should.eql([]);
});
it('should allow unstable versions if the current version is unstable', () => {
const upgradeVersions = [
@ -369,13 +439,19 @@ describe('helpers/versions', () => {
changeLogToVersion: '1.1.0-beta',
},
];
versionsHelper.determineUpgrades({
name: 'amazing-package',
versions: {
'1.0.0-beta': {},
'1.1.0-beta': {},
},
}, '1.0.0-beta', defaultConfig).should.eql(upgradeVersions);
versionsHelper
.determineUpgrades(
{
name: 'amazing-package',
versions: {
'1.0.0-beta': {},
'1.1.0-beta': {},
},
},
'1.0.0-beta',
defaultConfig,
)
.should.eql(upgradeVersions);
});
});
describe('.isRange(input)', () => {
@ -406,8 +482,12 @@ describe('helpers/versions', () => {
});
it('should reject github repositories', () => {
versionsHelper.isValidVersion('singapore/renovate').should.eql(false);
versionsHelper.isValidVersion('singapore/renovate#master').should.eql(false);
versionsHelper.isValidVersion('https://github.com/singapore/renovate.git').should.eql(false);
versionsHelper
.isValidVersion('singapore/renovate#master')
.should.eql(false);
versionsHelper
.isValidVersion('https://github.com/singapore/renovate.git')
.should.eql(false);
});
});
describe('.isPastLatest(dep, version)', () => {

View file

@ -18,8 +18,11 @@ describe('generateLockFile(newPackageJson, npmrcContent, yarnrcContent)', () =>
stderror: '',
}));
it('generates lock files', async () => {
const yarnLock =
await yarnHelper.generateLockFile('package-json-contents', 'npmrc-contents', 'yarnrc-contents');
const yarnLock = await yarnHelper.generateLockFile(
'package-json-contents',
'npmrc-contents',
'yarnrc-contents',
);
expect(tmp.dirSync.mock.calls.length).toEqual(1);
expect(fs.writeFileSync.mock.calls.length).toEqual(3);
expect(fs.readFileSync.mock.calls.length).toEqual(1);
@ -47,7 +50,9 @@ describe('getLockFile(packageJson, config)', () => {
name: 'yarn.lock',
contents: 'New yarn.lock',
};
expect(await yarnHelper.getLockFile('package.json', '', api)).toMatchObject(yarnLockFile);
expect(await yarnHelper.getLockFile('package.json', '', api)).toMatchObject(
yarnLockFile,
);
});
});
@ -69,14 +74,18 @@ describe('maintainLockFile(inputConfig)', () => {
});
it('returns null if contents match', async () => {
config.api.getFileContent.mockReturnValueOnce('oldYarnLockContent');
yarnHelper.getLockFile.mockReturnValueOnce({ contents: 'oldYarnLockContent' });
yarnHelper.getLockFile.mockReturnValueOnce({
contents: 'oldYarnLockContent',
});
const yarnLock = await yarnHelper.maintainLockFile(config);
expect(config.api.getFileContent.mock.calls.length).toBe(2);
expect(yarnLock).toEqual(null);
});
it('returns new yarn lock if contents differ', async () => {
config.api.getFileContent.mockReturnValueOnce('oldYarnLockContent');
yarnHelper.getLockFile.mockReturnValueOnce({ contents: 'newYarnLockContent' });
yarnHelper.getLockFile.mockReturnValueOnce({
contents: 'newYarnLockContent',
});
const yarnLock = await yarnHelper.maintainLockFile(config);
expect(config.api.getFileContent.mock.calls.length).toBe(2);
expect(yarnLock).toEqual({ contents: 'newYarnLockContent' });

View file

@ -136,10 +136,12 @@ describe('worker', () => {
});
it('handles depType config without override', () => {
config.foo = 'bar';
config.depTypes = [{
depType: 'dependencies',
alpha: 'beta',
}];
config.depTypes = [
{
depType: 'dependencies',
alpha: 'beta',
},
];
deps.push({
depName: 'a',
depType: 'dependencies',
@ -149,10 +151,12 @@ describe('worker', () => {
});
it('handles depType config with override', () => {
config.foo = 'bar';
config.depTypes = [{
depType: 'dependencies',
foo: 'beta',
}];
config.depTypes = [
{
depType: 'dependencies',
foo: 'beta',
},
];
deps.push({
depName: 'a',
depType: 'dependencies',
@ -162,10 +166,12 @@ describe('worker', () => {
});
it('handles package config', () => {
config.foo = 'bar';
config.packages = [{
packageName: 'a',
labels: ['renovate'],
}];
config.packages = [
{
packageName: 'a',
labels: ['renovate'],
},
];
deps.push({
depName: 'a',
});
@ -174,14 +180,18 @@ describe('worker', () => {
});
it('package config overrides depType and general config', () => {
config.foo = 'bar';
config.depTypes = [{
depType: 'dependencies',
foo: 'beta',
}];
config.packages = [{
packageName: 'a',
foo: 'gamma',
}];
config.depTypes = [
{
depType: 'dependencies',
foo: 'beta',
},
];
config.packages = [
{
packageName: 'a',
foo: 'gamma',
},
];
deps.push({
depName: 'a',
depType: 'dependencies',
@ -191,14 +201,18 @@ describe('worker', () => {
});
it('nested package config overrides depType and general config', () => {
config.foo = 'bar';
config.depTypes = [{
depType: 'dependencies',
foo: 'beta',
packages: [{
packageName: 'a',
foo: 'gamma',
}],
}];
config.depTypes = [
{
depType: 'dependencies',
foo: 'beta',
packages: [
{
packageName: 'a',
foo: 'gamma',
},
],
},
];
deps.push({
depName: 'a',
depType: 'dependencies',
@ -208,10 +222,12 @@ describe('worker', () => {
});
it('handles regex package pattern', () => {
config.foo = 'bar';
config.packages = [{
packagePattern: 'eslint',
labels: ['eslint'],
}];
config.packages = [
{
packagePattern: 'eslint',
labels: ['eslint'],
},
];
deps.push({
depName: 'eslint',
});
@ -229,10 +245,12 @@ describe('worker', () => {
});
it('handles regex wildcard package pattern', () => {
config.foo = 'bar';
config.packages = [{
packagePattern: '^eslint',
labels: ['eslint'],
}];
config.packages = [
{
packagePattern: '^eslint',
labels: ['eslint'],
},
];
deps.push({
depName: 'eslint',
});
@ -250,10 +268,12 @@ describe('worker', () => {
});
it('handles non-regex package name', () => {
config.foo = 'bar';
config.packages = [{
packageName: 'eslint',
labels: ['eslint'],
}];
config.packages = [
{
packageName: 'eslint',
labels: ['eslint'],
},
];
deps.push({
depName: 'eslint',
});

View file

@ -20,31 +20,41 @@ describe('workers/branch', () => {
});
it('returns undefined if branch does not exist', async () => {
config.api.branchExists.mockReturnValue(false);
expect(await branchWorker.getParentBranch(branchName, config)).toBe(undefined);
expect(await branchWorker.getParentBranch(branchName, config)).toBe(
undefined,
);
});
it('returns branchName if no PR', async () => {
config.api.getBranchPr.mockReturnValue(null);
expect(await branchWorker.getParentBranch(branchName, config)).toBe(branchName);
expect(await branchWorker.getParentBranch(branchName, config)).toBe(
branchName,
);
});
it('returns false if does not need rebaseing', async () => {
config.api.getBranchPr.mockReturnValue({
isUnmergeable: false,
});
expect(await branchWorker.getParentBranch(branchName, config)).toBe(branchName);
expect(await branchWorker.getParentBranch(branchName, config)).toBe(
branchName,
);
});
it('returns false if unmergeable and cannot rebase', async () => {
config.api.getBranchPr.mockReturnValue({
isUnmergeable: true,
canRebase: false,
});
expect(await branchWorker.getParentBranch(branchName, config)).toBe(branchName);
expect(await branchWorker.getParentBranch(branchName, config)).toBe(
branchName,
);
});
it('returns true if unmergeable and can rebase', async () => {
config.api.getBranchPr.mockReturnValue({
isUnmergeable: true,
canRebase: true,
});
expect(await branchWorker.getParentBranch(branchName, config)).toBe(undefined);
expect(await branchWorker.getParentBranch(branchName, config)).toBe(
undefined,
);
});
it('returns false if stale but not configured to rebase', async () => {
config.api.getBranchPr.mockReturnValue({
@ -53,7 +63,9 @@ describe('workers/branch', () => {
canRebase: true,
});
config.rebaseStalePrs = false;
expect(await branchWorker.getParentBranch(branchName, config)).toBe(branchName);
expect(await branchWorker.getParentBranch(branchName, config)).toBe(
branchName,
);
});
it('returns false if stale but cannot rebase', async () => {
config.api.getBranchPr.mockReturnValueOnce({
@ -62,7 +74,9 @@ describe('workers/branch', () => {
canRebase: false,
});
config.rebaseStalePrs = true;
expect(await branchWorker.getParentBranch(branchName, config)).toBe(branchName);
expect(await branchWorker.getParentBranch(branchName, config)).toBe(
branchName,
);
});
it('returns true if stale and can rebase', async () => {
config.api.getBranchPr.mockReturnValueOnce({
@ -71,7 +85,9 @@ describe('workers/branch', () => {
canRebase: true,
});
config.rebaseStalePrs = true;
expect(await branchWorker.getParentBranch(branchName, config)).toBe(undefined);
expect(await branchWorker.getParentBranch(branchName, config)).toBe(
undefined,
);
});
});
describe('ensureBranch(config)', () => {

View file

@ -171,6 +171,10 @@ assertion-error@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c"
ast-types@0.9.8:
version "0.9.8"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.8.tgz#6cb6a40beba31f49f20928e28439fc14a3dab078"
async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
@ -222,7 +226,7 @@ babel-cli@6.24.1:
optionalDependencies:
chokidar "^1.6.1"
babel-code-frame@^6.16.0, babel-code-frame@^6.22.0:
babel-code-frame@6.22.0, babel-code-frame@^6.16.0, babel-code-frame@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
dependencies:
@ -405,6 +409,10 @@ babel-types@^6.18.0, babel-types@^6.24.1:
lodash "^4.2.0"
to-fast-properties "^1.0.1"
babylon@7.0.0-beta.8:
version "7.0.0-beta.8"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.8.tgz#2bdc5ae366041442c27e068cce6f0d7c06ea9949"
babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0:
version "6.17.0"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.0.tgz#37da948878488b9c4e3c4038893fa3314b3fc932"
@ -993,6 +1001,12 @@ eslint-config-airbnb-base@11.1.3:
version "11.1.3"
resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-11.1.3.tgz#0e8db71514fa36b977fbcf977c01edcf863e0cf0"
eslint-config-prettier@1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-1.7.0.tgz#cda3ce22df1e852daa9370f1f3446e8b8a02ce44"
dependencies:
get-stdin "^5.0.1"
eslint-import-resolver-node@^0.2.0:
version "0.2.3"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c"
@ -1023,6 +1037,12 @@ eslint-plugin-import@2.2.0:
minimatch "^3.0.3"
pkg-up "^1.0.0"
eslint-plugin-prettier@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.0.1.tgz#2ae1216cf053dd728360ca8560bf1aabc8af3fa9"
dependencies:
requireindex "~1.1.0"
eslint-plugin-promise@3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz#78fbb6ffe047201627569e85a6c5373af2a68fca"
@ -1107,7 +1127,7 @@ estraverse@~4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2"
esutils@^2.0.2:
esutils@2.0.2, esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
@ -1270,6 +1290,10 @@ flat-cache@^1.2.1:
graceful-fs "^4.1.2"
write "^0.2.1"
flow-parser@0.43.0:
version "0.43.0"
resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.43.0.tgz#e2b8eb1ac83dd53f7b6b04a7c35b6a52c33479b7"
for-in@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@ -1355,6 +1379,10 @@ get-caller-file@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
get-stdin@5.0.1, get-stdin@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
get-stdin@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
@ -1396,7 +1424,7 @@ glob-parent@^2.0.0:
dependencies:
is-glob "^2.0.0"
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1:
glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
dependencies:
@ -2051,6 +2079,15 @@ jest-util@^19.0.2:
leven "^2.0.0"
mkdirp "^0.5.1"
jest-validate@19.0.0:
version "19.0.0"
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-19.0.0.tgz#8c6318a20ecfeaba0ba5378bfbb8277abded4173"
dependencies:
chalk "^1.1.1"
jest-matcher-utils "^19.0.0"
leven "^2.0.0"
pretty-format "^19.0.0"
jest-validate@^19.0.2:
version "19.0.2"
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-19.0.2.tgz#dc534df5f1278d5b63df32b14241d4dbf7244c0c"
@ -2383,7 +2420,7 @@ minimist@0.0.8, minimist@~0.0.1:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
minimist@1.2.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
@ -2742,6 +2779,21 @@ preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
prettier@1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.2.2.tgz#22d17c1132faaaea1f1d4faea31f19f7a1959f3e"
dependencies:
ast-types "0.9.8"
babel-code-frame "6.22.0"
babylon "7.0.0-beta.8"
chalk "1.1.3"
esutils "2.0.2"
flow-parser "0.43.0"
get-stdin "5.0.1"
glob "7.1.1"
jest-validate "19.0.0"
minimist "1.2.0"
pretty-format@^19.0.0:
version "19.0.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-19.0.0.tgz#56530d32acb98a3fa4851c4e2b9d37b420684c84"
@ -2984,6 +3036,10 @@ require-uncached@^1.0.2:
caller-path "^0.1.0"
resolve-from "^1.0.0"
requireindex@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.1.0.tgz#e5404b81557ef75db6e49c5a72004893fe03e162"
resolve-from@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"