Skip to content
Snippets Groups Projects
Commit 01f399d4 authored by ewnd9's avatar ewnd9 Committed by Rhys Arkins
Browse files

Initial commit

parent 44101364
No related branches found
No related tags found
No related merge requests found
{
"private": true,
"dependencies": {
"got": "^6.6.3",
"mkdirp": "^0.5.1",
"nodegit": "^0.16.0",
"rimraf": "^2.5.4",
"semver": "^5.3.0"
}
}
'use strict';
const Git = require('nodegit');
const got = require('got');
const semver = require('semver');
const fs = require('fs');
const mkdirp = require('mkdirp');
const rimraf = require('rimraf');
const authorName = 'firstName lastName'; // commit credentials
const authorEmail = 'admin@example.com'; // commit credentials
const sshPublicKeyPath = `${process.env.HOME}/.ssh/id_rsa.pub`;
const sshPrivateKeyPath = `${process.env.HOME}/.ssh/id_rsa`;
if (!module.parent) {
// https://github.com/settings/tokens/new
const token = process.argv[2];
const repoName = process.argv[3];
if (!token || !repoName) {
console.error(`Usage: node index.js <token> <repo>`);
process.exit(1);
}
updateRepo({ token, repoName })
.catch(err => console.log(err.stack || err));
}
function updateRepo({ token, repoName }) {
const repoPath = `tmp/${repoName}`;
mkdirp.sync(repoPath);
let repo;
let headCommit;
return Git
.Clone(`git@github.com:${repoName}.git`, repoPath, {
fetchOpts: {
callbacks: {
credentials: getCredentials,
certificateCheck: () => 1
}
}
})
.then(_repo => {
repo = _repo;
return repo.fetch('origin', {
callbacks: {
credentials: getCredentials
}
});
})
.then(() => {
return repo.getHeadCommit();
})
.then(commit => {
headCommit = commit;
return readFile(headCommit, 'package.json');
})
.then(blob => {
const pkg = JSON.parse(blob);
return iterateDependencies(pkg, 'dependencies')
.then(() => iterateDependencies(pkg, 'devDependencies'));
})
.then(() => {
rimraf.sync(repoPath);
});
function iterateDependencies(pkg, depType) {
const deps = pkg[depType];
return Object.keys(deps).reduce((total, depName) => {
return total.then(() => {
const currentVersion = deps[depName].replace(/[^\d.]/g, '');
if (!semver.valid(currentVersion)) {
return;
}
// supports scoped packages, e.g. @user/package
return got(`https://registry.npmjs.org/${depName.replace('/', '%2F')}`, { json: true })
.then(res => {
const latestAvailable = res.body['dist-tags'].latest;
if (semver.gt(latestAvailable, currentVersion)) {
return updateDependency(depType, depName, latestAvailable)
}
});
});
}, Promise.resolve());
}
function updateDependency(depType, depName, nextVersion) {
const branchName = `upgrade/${depName}`;
// try to checkout remote branche
try {
nativeCall(`git checkout ${branchName}`);
} catch (e) {
nativeCall(`git checkout -b ${branchName}`);
}
return updateBranch(branchName, depType, depName, nextVersion)
.then(() => nativeCall(`git checkout master`));
}
function updateBranch(branchName, depType, depName, nextVersion) {
let commit;
return repo.getBranchCommit(branchName)
.then(_commit => {
commit = _commit;
return readFile(commit, 'package.json');
})
.then(blob => {
const pkg = JSON.parse(String(blob));
if (pkg[depType][depName] === nextVersion) {
return;
}
pkg[depType][depName] = nextVersion;
fs.writeFileSync(`${repoPath}/package.json`, JSON.stringify(pkg, null, 2) + '\n');
return commitAndPush(commit, depName, nextVersion, branchName);
});
}
function commitAndPush(commit, depName, nextVersion, branchName) {
const updateMessage = `Update ${depName} to version ${nextVersion}`;
console.log(updateMessage);
let index;
return repo
.refreshIndex()
.then(indexResult => {
index = indexResult;
return index.addByPath('package.json');
})
.then(() => index.write())
.then(() => index.writeTree())
.then(oid => {
let author;
if (authorName && authorEmail) {
const date = new Date();
author = Git.Signature.create(
authorName,
authorEmail,
Math.floor(date.getTime() / 1000),
-date.getTimezoneOffset()
);
} else {
author = repo.defaultSignature();
}
return repo.createCommit('HEAD', author, author, updateMessage, oid, [commit]);
})
.then(() => Git.Remote.lookup(repo, 'origin'))
.then(origin => {
return origin.push(
[`refs/heads/${branchName}:refs/heads/${branchName}`], {
callbacks: {
credentials: getCredentials
}
}
);
})
.then(() => {
return createPullRequest(branchName, `Update ${depName}`);
});
}
function createPullRequest(branchName, updateMessage) {
const head = `${branchName}`;
const options = {
method: 'POST',
json: true,
headers: {
Authorization: `token ${token}`
},
body: JSON.stringify({
title: updateMessage,
body: '',
head,
base: 'master'
})
};
return got(`https://api.github.com/repos/${repoName}/pulls`, options)
.then(
null,
err => {
let logError = true;
try {
if (err.response.body.errors.find(e => e.message.indexOf('A pull request already exists') === 0)) {
logError = false;
}
} catch (e) {
}
if (logError) {
console.log(err);
}
}
);
}
function readFile(commit, filename) {
return commit
.getEntry('package.json')
.then(entry => entry.getBlob())
.then(blob => String(blob));
}
function getCredentials(url, userName) {
// https://github.com/nodegit/nodegit/issues/1133#issuecomment-261779939
return Git.Cred.sshKeyNew(
userName,
sshPublicKeyPath,
sshPrivateKeyPath,
''
);
}
function nativeCall(cmd) {
return require('child_process').execSync(cmd, { cwd: repoPath, stdio: [null, null, null] });
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment