Support multiple repositories
Also closes #3 commit 725de26fe331470f9fe3d17bad4c365ff8772443 Author: Rhys Arkins <rhys@keylocation.sg> Date: Tue Jan 10 13:32:07 2017 +0100 Improve console messages commit 28ec77634b86ddb7ed8410053d671bad59133058 Author: Rhys Arkins <rhys@keylocation.sg> Date: Tue Jan 10 12:25:26 2017 +0100 Refactor github helper commit 5cd2cf8eb7049868b0d1bc0d225a6cc490ec3317 Author: Rhys Arkins <rhys@keylocation.sg> Date: Tue Jan 10 11:20:27 2017 +0100 Support multiple repos commit 52e531c13078e448cecb651b94ce76e24df3d60d Author: Rhys Arkins <rhys@keylocation.sg> Date: Tue Jan 10 11:19:24 2017 +0100 Hardcode base branch
This commit is contained in:
Родитель
67d774dcd3
Коммит
d021a36905
|
@ -1,9 +1,12 @@
|
|||
{
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"better-console": "1.0.0",
|
||||
"colors": "1.1.2",
|
||||
"gh-got": "5.0.0",
|
||||
"got": "6.6.3",
|
||||
"lodash": "4.17.4",
|
||||
"manakin": "0.4.6",
|
||||
"mkdirp": "0.5.1",
|
||||
"nodegit": "0.16.0",
|
||||
"rimraf": "2.5.4",
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
module.exports = {
|
||||
verbose: false,
|
||||
baseBranch: 'master',
|
||||
templates: {
|
||||
branchName: (params) => {
|
||||
return `renovate/${params.depName}-${params.newVersionMajor}.x`;
|
||||
|
|
|
@ -1,102 +1,150 @@
|
|||
const ghGot = require('gh-got');
|
||||
const console = require('better-console');
|
||||
|
||||
var config = {};
|
||||
|
||||
module.exports = {
|
||||
// Initialize GitHub by getting base branch SHA
|
||||
init: function(setConfig, repoName, packageFile) {
|
||||
config = setConfig;
|
||||
config.repoName = repoName;
|
||||
config.packageFile = packageFile;
|
||||
config.userName = repoName.split('/')[0];
|
||||
init: init,
|
||||
// Package File
|
||||
getPackageFile: getPackageFile,
|
||||
getPackageFileContents: getPackageFileContents,
|
||||
writePackageFile: writePackageFile,
|
||||
// Branch
|
||||
createBranch: createBranch,
|
||||
// PR
|
||||
checkForClosedPr: checkForClosedPr,
|
||||
createPr: createPr,
|
||||
getPr: getPr,
|
||||
updatePr: updatePr,
|
||||
};
|
||||
|
||||
return ghGot(`repos/${config.repoName}/git/refs/head`, {token: config.token}).then(res => {
|
||||
// First, get the SHA for base branch
|
||||
// Initialize GitHub by getting base branch and SHA
|
||||
function init(setConfig, repoName, packageFile) {
|
||||
config = setConfig;
|
||||
config.repoName = repoName;
|
||||
config.packageFile = packageFile;
|
||||
|
||||
return ghGot(`repos/${config.repoName}`, { token: config.token })
|
||||
.then(res => {
|
||||
config.owner = res.body.owner.login;
|
||||
config.defaultBranch = res.body.default_branch;
|
||||
})
|
||||
.then(() => {
|
||||
return ghGot(`repos/${config.repoName}/git/refs/head`, { token: config.token })
|
||||
.then(res => {
|
||||
// Get the SHA for base branch
|
||||
res.body.forEach(function(branch) {
|
||||
// Loop through all branches because the base branch may not be the first
|
||||
if (branch.ref === `refs/heads/${config.baseBranch}`) {
|
||||
if (branch.ref === `refs/heads/${config.defaultBranch}`) {
|
||||
// This is the SHA we will create new branches from
|
||||
config.baseSHA = branch.object.sha;
|
||||
}
|
||||
});
|
||||
}).catch(function(err) {
|
||||
console.log('init error: ' + err);
|
||||
});
|
||||
},
|
||||
createBranch: function(branchName) {
|
||||
return ghGot.post(`repos/${config.repoName}/git/refs`, {
|
||||
token: config.token,
|
||||
body: {
|
||||
ref: `refs/heads/${branchName}`,
|
||||
sha: config.baseSHA,
|
||||
},
|
||||
}).catch(function(err) {
|
||||
console.error('GitHub init error: ' + err);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
// Package File
|
||||
|
||||
function getPackageFile(branchName) {
|
||||
return getFile(config.packageFile, branchName);
|
||||
}
|
||||
|
||||
function getPackageFileContents() {
|
||||
return getFileContents(config.packageFile);
|
||||
}
|
||||
|
||||
function writePackageFile(branchName, oldFileSHA, fileContents, message) {
|
||||
return writeFile(branchName, oldFileSHA, config.packageFile, fileContents, message);
|
||||
}
|
||||
|
||||
// Branch
|
||||
|
||||
function createBranch(branchName) {
|
||||
return ghGot.post(`repos/${config.repoName}/git/refs`, {
|
||||
token: config.token,
|
||||
body: {
|
||||
ref: `refs/heads/${branchName}`,
|
||||
sha: config.baseSHA,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Pull Request
|
||||
|
||||
function checkForClosedPr(branchName, prTitle) {
|
||||
return ghGot(`repos/${config.repoName}/pulls?state=closed&head=${config.owner}:${branchName}`, {
|
||||
token: config.token
|
||||
}).then(res => {
|
||||
return res.body.some((pr) => {
|
||||
return pr.title === prTitle && pr.head.label === `${config.owner}:${branchName}`;
|
||||
});
|
||||
},
|
||||
createPr: function(branchName, title, body) {
|
||||
return ghGot.post(`repos/${config.repoName}/pulls`, {
|
||||
token: config.token,
|
||||
body: {
|
||||
title: title,
|
||||
head: branchName,
|
||||
base: config.baseBranch,
|
||||
body: body,
|
||||
}
|
||||
}).then(res => {
|
||||
return res.body;
|
||||
});
|
||||
},
|
||||
checkForClosedPr(branchName, prTitle) {
|
||||
return ghGot(`repos/${config.repoName}/pulls?state=closed&head=${config.userName}:${branchName}`, {
|
||||
token: config.token
|
||||
}).then(res => {
|
||||
return res.body.some((pr) => {
|
||||
return pr.title === prTitle && pr.head.label === `${config.userName}:${branchName}`;
|
||||
});
|
||||
}).catch((err) => {
|
||||
console.error('Error checking if PR already existed');
|
||||
});
|
||||
},
|
||||
getFile: getFile,
|
||||
getFileContents: function(filePath, branchName) {
|
||||
return getFile(filePath, branchName).then(res => {
|
||||
return JSON.parse(new Buffer(res.body.content, 'base64').toString());
|
||||
});
|
||||
},
|
||||
getPr: function(branchName) {
|
||||
return ghGot(`repos/${config.repoName}/pulls?state=open&base=${config.baseBranch}&head=${config.userName}:${branchName}`, {
|
||||
token: config.token,
|
||||
}).then(res => {
|
||||
if (res.body.length) {
|
||||
return res.body[0];
|
||||
}
|
||||
return null;
|
||||
});
|
||||
},
|
||||
writeFile: function(branchName, oldFileSHA, filePath, fileContents, message) {
|
||||
return ghGot.put(`repos/${config.repoName}/contents/${filePath}`, {
|
||||
token: config.token,
|
||||
body: {
|
||||
branch: branchName,
|
||||
sha: oldFileSHA,
|
||||
message: message,
|
||||
content: new Buffer(fileContents).toString('base64')
|
||||
}
|
||||
});
|
||||
},
|
||||
updatePr: function(prNo, title, body) {
|
||||
return ghGot.patch(`repos/${config.repoName}/pulls/${prNo}`, {
|
||||
token: config.token,
|
||||
body: {
|
||||
title: title,
|
||||
body: body,
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
}).catch((err) => {
|
||||
console.error('Error checking if PR already existed');
|
||||
});
|
||||
}
|
||||
|
||||
function createPr(branchName, title, body) {
|
||||
return ghGot.post(`repos/${config.repoName}/pulls`, {
|
||||
token: config.token,
|
||||
body: {
|
||||
title: title,
|
||||
head: branchName,
|
||||
base: config.defaultBranch,
|
||||
body: body,
|
||||
}
|
||||
}).then(res => {
|
||||
return res.body;
|
||||
});
|
||||
}
|
||||
|
||||
function getPr(branchName) {
|
||||
return ghGot(`repos/${config.repoName}/pulls?state=open&base=${config.defaultBranch}&head=${config.owner}:${branchName}`, {
|
||||
token: config.token,
|
||||
}).then(res => {
|
||||
if (res.body.length) {
|
||||
return res.body[0];
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
function updatePr(prNo, title, body) {
|
||||
return ghGot.patch(`repos/${config.repoName}/pulls/${prNo}`, {
|
||||
token: config.token,
|
||||
body: {
|
||||
title: title,
|
||||
body: body,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Generic File operations
|
||||
|
||||
function getFile(filePath, branchName) {
|
||||
branchName = branchName || config.baseBranch;
|
||||
branchName = branchName || config.defaultBranch;
|
||||
return ghGot(`repos/${config.repoName}/contents/${filePath}?ref=${branchName}`, {
|
||||
token: config.token,
|
||||
});
|
||||
}
|
||||
|
||||
function getFileContents(filePath, branchName) {
|
||||
return getFile(filePath, branchName).then(res => {
|
||||
return JSON.parse(new Buffer(res.body.content, 'base64').toString());
|
||||
});
|
||||
}
|
||||
|
||||
function writeFile(branchName, oldFileSHA, filePath, fileContents, message) {
|
||||
return ghGot.put(`repos/${config.repoName}/contents/${filePath}`, {
|
||||
token: config.token,
|
||||
body: {
|
||||
branch: branchName,
|
||||
sha: oldFileSHA,
|
||||
message: message,
|
||||
content: new Buffer(fileContents).toString('base64')
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ function getDependencyUpgrades(depName, currentVersion) {
|
|||
return getDependency(depName)
|
||||
.then(res => {
|
||||
if (!res.body['versions']) {
|
||||
console.log(depName + ' versions is null');
|
||||
console.error(depName + ' versions is null');
|
||||
}
|
||||
const allUpgrades = {};
|
||||
if (isRange(currentVersion)) {
|
||||
|
|
103
src/index.js
103
src/index.js
|
@ -1,3 +1,6 @@
|
|||
// Set colours for console globally
|
||||
require('manakin').global;
|
||||
|
||||
const semver = require('semver');
|
||||
const stable = require('semver-stable');
|
||||
|
||||
|
@ -9,18 +12,29 @@ const config = initConfig();
|
|||
validateArguments();
|
||||
npm.init(config);
|
||||
|
||||
const repoName = Object.keys(config.repositories)[0];
|
||||
const packageFile = config.repositories[repoName] || 'package.json';
|
||||
|
||||
initGitHub()
|
||||
.then(getPackageFileContents)
|
||||
.then(determineUpgrades)
|
||||
.then(processUpgradesSequentially)
|
||||
config.repositories.reduce((repoPromise, repo) => {
|
||||
return repoPromise.then(() => {
|
||||
const repoName = repo.name;
|
||||
return repo.packageFiles.reduce((packageFilePromise, packageFile) => {
|
||||
return packageFilePromise.then(() => {
|
||||
return initGitHub(repoName, packageFile)
|
||||
.then(getPackageFileContents)
|
||||
.then(determineUpgrades)
|
||||
.then(processUpgradesSequentially)
|
||||
.then(() => {
|
||||
console.success(`Repo ${repoName} ${packageFile} done`);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('renovate caught error: ' + err);
|
||||
});
|
||||
});
|
||||
}, repoPromise);
|
||||
});
|
||||
}, Promise.resolve())
|
||||
.then(() => {
|
||||
console.log('Done');
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('renovate caught error: ' + err);
|
||||
if (config.repositories.length < 1) {
|
||||
console.success('All repos done');
|
||||
}
|
||||
});
|
||||
|
||||
function initConfig() {
|
||||
|
@ -39,17 +53,28 @@ function initConfig() {
|
|||
const repoName = process.argv[2];
|
||||
const packageFile = process.argv[3] || 'package.json';
|
||||
if (repoName) {
|
||||
cliConfig.repositories = {};
|
||||
cliConfig.repositories[repoName] = packageFile;
|
||||
cliConfig.repositories = [
|
||||
{
|
||||
name: repoName,
|
||||
packageFiles: [packageFile],
|
||||
},
|
||||
];
|
||||
}
|
||||
const combinedConfig = Object.assign(defaultConfig, customConfig, cliConfig);
|
||||
if (Array.isArray(combinedConfig.repositories)) {
|
||||
const newRepositories = {};
|
||||
combinedConfig.repositories.forEach(repo => {
|
||||
newRepositories[repo] = 'package.json';
|
||||
});
|
||||
combinedConfig.repositories = newRepositories;
|
||||
}
|
||||
// First, convert any strings to objects
|
||||
combinedConfig.repositories.forEach(function(repo, index) {
|
||||
if (typeof repo === 'string') {
|
||||
combinedConfig.repositories[index] = {
|
||||
name: repo,
|
||||
};
|
||||
}
|
||||
});
|
||||
// Add 'package.json' if missing
|
||||
combinedConfig.repositories.forEach(function(repo, index) {
|
||||
if (!repo.packageFiles || !repo.packageFiles.length) {
|
||||
repo.packageFiles = ['package.json'];
|
||||
}
|
||||
});
|
||||
if (combinedConfig.verbose) {
|
||||
console.log('config = ' + JSON.stringify(combinedConfig));
|
||||
}
|
||||
|
@ -63,33 +88,31 @@ function validateArguments() {
|
|||
process.exit(1);
|
||||
}
|
||||
// We also need a repository
|
||||
if (typeof Object.keys(config.repositories).length === 0) {
|
||||
console.error('Error: A repository must be configured');
|
||||
if (!config.repositories || config.repositories.length === 0) {
|
||||
console.error('Error: At least one repository must be configured');
|
||||
}
|
||||
}
|
||||
|
||||
function initGitHub() {
|
||||
if (config.verbose) {
|
||||
console.log('Initializing GitHub');
|
||||
}
|
||||
function initGitHub(repoName, packageFile) {
|
||||
console.info('Initializing GitHub repo ' + repoName + ', ' + packageFile);
|
||||
return github.init(config, repoName, packageFile);
|
||||
}
|
||||
|
||||
function getPackageFileContents() {
|
||||
console.log('Getting package file contents');
|
||||
return github.getFileContents(config.packageFile);
|
||||
console.info('Getting package file contents');
|
||||
return github.getPackageFileContents();
|
||||
}
|
||||
|
||||
function determineUpgrades(packageFileContents) {
|
||||
console.log('Determining required upgrades');
|
||||
console.info('Determining required upgrades');
|
||||
return npm.getAllDependencyUpgrades(packageFileContents);
|
||||
}
|
||||
|
||||
function processUpgradesSequentially(upgrades) {
|
||||
if (Object.keys(upgrades).length) {
|
||||
console.log('Processing upgrades');
|
||||
console.info('Processing upgrades');
|
||||
} else {
|
||||
console.log('No upgrades to process');
|
||||
console.info('No upgrades to process');
|
||||
}
|
||||
if (config.verbose) {
|
||||
console.log('All upgrades: ' + JSON.stringify(upgrades));
|
||||
|
@ -123,7 +146,9 @@ function updateDependency({ upgradeType, depType, depName, currentVersion, newVe
|
|||
// This allows users to close an unwanted upgrade PR and not worry about seeing it raised again
|
||||
return github.checkForClosedPr(branchName, prTitle).then((prExisted) => {
|
||||
if (prExisted) {
|
||||
console.log(`${depName}: Skipping due to existing PR found.`);
|
||||
if (config.verbose) {
|
||||
console.log(`${depName}: Skipping due to existing PR found.`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -131,7 +156,7 @@ function updateDependency({ upgradeType, depType, depName, currentVersion, newVe
|
|||
.then(ensureCommit)
|
||||
.then(ensurePr)
|
||||
.catch(error => {
|
||||
console.log('Error updating dependency depName: ' + error);
|
||||
console.error(`Error updating dependency ${depName}: ${error}`);
|
||||
// Don't throw here - we don't want to stop the other renovations
|
||||
});
|
||||
});
|
||||
|
@ -142,8 +167,8 @@ function updateDependency({ upgradeType, depType, depName, currentVersion, newVe
|
|||
// Check in case it's because the branch already existed
|
||||
if (error.response.body.message !== 'Reference already exists') {
|
||||
// In this case it means we really do have a problem and can't continue
|
||||
console.log('Error creating branch: ' + branchName);
|
||||
console.log('Response body: ' + error.response.body);
|
||||
console.error('Error creating branch: ' + branchName);
|
||||
console.error('Response body: ' + error.response.body);
|
||||
throw error;
|
||||
}
|
||||
// Otherwise we swallow this error and continue
|
||||
|
@ -151,7 +176,7 @@ function updateDependency({ upgradeType, depType, depName, currentVersion, newVe
|
|||
}
|
||||
function ensureCommit() {
|
||||
// Retrieve the package.json from this renovate branch
|
||||
return github.getFile(config.packageFile, branchName).then(res => {
|
||||
return github.getPackageFile(branchName).then(res => {
|
||||
const currentSHA = res.body.sha;
|
||||
const currentFileContent = new Buffer(res.body.content, 'base64').toString();
|
||||
const currentJson = JSON.parse(currentFileContent);
|
||||
|
@ -161,7 +186,7 @@ function updateDependency({ upgradeType, depType, depName, currentVersion, newVe
|
|||
console.log(`${depName}: Updating to ${newVersion} in branch ${branchName}`);
|
||||
}
|
||||
const newPackageContents = packageJson.setNewValue(currentFileContent, depType, depName, newVersion);
|
||||
return github.writeFile(branchName, currentSHA, packageFile, newPackageContents, commitMessage);
|
||||
return github.writePackageFile(branchName, currentSHA, newPackageContents, commitMessage);
|
||||
} else {
|
||||
if (config.verbose) {
|
||||
console.log(`${depName}: branch ${branchName} is already up-to-date`);
|
||||
|
@ -178,12 +203,12 @@ function updateDependency({ upgradeType, depType, depName, currentVersion, newVe
|
|||
console.log(`${depName}: PR #${pr.number} already up-to-date`);
|
||||
}
|
||||
} else {
|
||||
console.log(`${depName}: Updating PR #${pr.number}`);
|
||||
console.info(`${depName}: Updating PR #${pr.number}`);
|
||||
return github.updatePr(pr.number, prTitle, prBody);
|
||||
}
|
||||
} else {
|
||||
return github.createPr(branchName, prTitle, prBody).then((pr) => {
|
||||
console.log(`${depName}: Created PR #${pr.number}`);
|
||||
console.info(`${depName}: Created PR #${pr.number}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче