const _ = require('lodash');
const path = require('path');
const jira = require(path.resolve(__dirname,'jira.js'));
const semver = require('semver');
const exec = require('child_process').exec;
const semverMax = require('semver-max');
/** @class git */
/**
* Given array, will review each value and verify value is valid semantically versioned tag.
* @param tags
* @returns {Array}
*/
function filterAllTags(tags){
let results = _.map(tags,(tag)=>{
if (semver.valid(tag)){
return tag;
}
})
return _.compact(results);
}
/**
* Windows doesn't have awk, grep, etc - So we have to perform version collections into array through other means.
* @param rawTagStr
* @returns {Array}
*/
function windowsGetNextVersion(rawTagStr) {
let cursor = rawTagStr.split("\n");
let versions = [];
_.each(cursor,(ver)=>{
let staged = ver.slice(51);
// Annontated tags as a stringhave a ^{} that we need to remove..
if (staged.indexOf("^{}")>0) {
versions.push(staged.replace("^{}",""));
} else {
versions.push(staged);
}
});
return versions;
}
/**
* Without cloning repository, get ALL tags through ls-remote, awk and grep command line executions. Tag is compared to
* target environment [version_seed] to ensure found tag is greater. Returns evaluated highest version.
* @param instance
* @param callback
*/
function evaluateHighestRepoTag (instance,callback){
console.log('Retrieving all remote tags from', instance.build_settings.repo_url);
// If jobrunner not executing on winblows.
if (process.platform !== 'win32'){
exec(`git ls-remote --tags "${instance.build_settings.repo_url}" | awk '{print $2}' | grep -v '{}' | awk -F"/" '{print $3}' | sort -n -t. -k1,1 -k2,2 -k3,3`, (err,stdout,stderr)=>{
if (err) callback(err);
if (stderr !== "") callback(stderr);
let tags = stdout.split("\n");
tags = filterAllTags(tags);
let highestInRepository;
if (tags.length == 0 || _.isNil(tags)){
console.log('No tags found in repository, setting default version of build to version_seed found in target environment settings.');
highestInRepository = instance.build_settings.version_seed;
} else {
highestInRepository = tags.reduce(semverMax);
}
console.log('Found',tags.length, 'tags in repository - Evaluated highest version in repository as:',highestInRepository);
// If tag version found in repository is greater than version_seed in settings.json then return value
// Else return higher value found in version_seed.
if (semver.gt(highestInRepository,instance.build_settings.version_seed)){
callback(null,highestInRepository);
} else {
callback(null,instance.build_settings.version_seed);
}
})
} else {
exec(`git ls-remote --tags "${instance.build_settings.repo_url}"`, (err,stdout,stderr)=>{
if (err) callback(err);
if (stderr !== "") callback(stderr);
let tags = windowsGetNextVersion(stdout);
// Strip off 52 characters;
//let tags = stdout.split("\n");
tags = filterAllTags(tags);
let highestInRepository;
if (tags.length == 0 || _.isNil(tags)){
console.log('No tags found in repository, setting default version of build to version_seed found in target environment settings.');
highestInRepository = instance.build_settings.version_seed;
} else {
highestInRepository = tags.reduce(semverMax);
}
console.log('Found',tags.length, 'tags in repository - Evaluated highest version in repository as:',highestInRepository);
// If tag version found in repository is greater than version_seed in settings.json then return value
// Else return higher value found in version_seed.
if (semver.gt(highestInRepository,instance.build_settings.version_seed)){
callback(null,highestInRepository);
} else {
callback(null,instance.build_settings.version_seed);
}
})
}
}
/**
* Get commit sha of [instance.latest_tag] found in repository, and if not possible assign [instance.latest_tag_sha] to
* current commit sha, which simply means no jira ids will be found for some given unknown, and don't really care reason
* right now....
* @param instance
* @return {Promise}
*/
function getLatestTagCommitSha(instance){
return new Promise((resolve)=>{
console.log('Retrieving commit sha for tag:', instance.latest_tag);
exec(`git ls-remote ${instance.build_settings.repo_url} | grep "${instance.latest_tag}" | cut -b 1-40`,(err,stdout,stderr)=>{
if (err) instance.latest_tag_sha = instance.current_sha;
if (stderr) instance.latest_tag_sha = instance.current_sha;
let results = stdout.toString().replace(/(\r\n|\n|\r)/gm,"##LF##");
let foundShas = _.compact(results.split("##LF##")); //Compact to remove any possible empty array items.
instance.latest_tag_sha = foundShas[foundShas.length-1];
resolve(null);
})
})
}
/**
* Gets commit sha of respository without clone repository locally.
* @param instance
* @return {Promise}
*/
function getCurrentHeadSha(instance){
return new Promise((resolve,reject)=>{
exec(`git ls-remote ${instance.build_settings.repo_url} ${instance.arguments.branch} | cut -c1-40`,(err,stdout,stderr)=>{
let sha = stdout.toString().replace(/(\r\n|\n|\r)/gm,"")
console.log('Commit sha of', instance.arguments.branch, ':',sha);
if (err) reject (err);
if (stderr) reject(stderr);
resolve(sha); //Replace all line endings, (Windows, mac, linux)
})
})
}
/**
* Evaulates current highest version tag, and commit sha of branch provided by cli argument -b
* @param instance
* @return {Promise}
*/
exports.getRepoInformation = function (instance) {
return new Promise ((resolve,reject)=>{
evaluateHighestRepoTag(instance,(err,version)=>{
if (err) reject(err);
instance.latest_tag = version;
getCurrentHeadSha(instance)
.then((sha)=>{
instance.current_sha = sha;
getLatestTagCommitSha(instance)
.then(()=>{
resolve(null);
})
})
})
})
}
/** Increments {instance.latest_tag} by corresponding versioning type [prepatch] [patch] [minor]
* @memberOf git
* @param instance
* @return {Promise}
*/
exports.nextVersionTag = function(instance) {
return new Promise((resolve)=>{
if (!semver.valid(instance.latest_tag)) {
console.log('Version tag invalid');
process.exit(1);
} else {
if (instance.arguments.release === false || instance.arguments.release === "false" || _.isNil(instance.arguments.release)){
let next = semver.inc(instance.latest_tag,`${instance.build_settings.versioning}`);
console.log('Next version:', next);
instance.next_tag = next;
resolve(null);
} else {
let next = semver.inc(instance.latest_tag,`${instance.build_settings.versioning}`);
console.log('Next version:', next);
instance.next_tag = next;
resolve(null);
}
}
})
}