182 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			182 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | 'use strict'; | ||
|  | 
 | ||
|  | var fs = require('fs'); | ||
|  | var path = require('path'); | ||
|  | var shell = require('shelljs'); | ||
|  | var semver = require('semver'); | ||
|  | var _ = require('lodash'); | ||
|  | 
 | ||
|  | var currentPackage, previousVersions, gitRepoInfo; | ||
|  | 
 | ||
|  | 
 | ||
|  | /** | ||
|  |  * Load information about this project from the package.json | ||
|  |  * @return {Object} The package information | ||
|  |  */ | ||
|  | var getPackage = function() { | ||
|  |   // Search up the folder hierarchy for the first package.json
 | ||
|  |   var packageFolder = path.resolve('.'); | ||
|  |   while (!fs.existsSync(path.join(packageFolder, 'package.json'))) { | ||
|  |     var parent = path.dirname(packageFolder); | ||
|  |     if (parent === packageFolder) { break; } | ||
|  |     packageFolder = parent; | ||
|  |   } | ||
|  |   return JSON.parse(fs.readFileSync(path.join(packageFolder,'package.json'), 'UTF-8')); | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | /** | ||
|  |  * Parse the github URL for useful information | ||
|  |  * @return {Object} An object containing the github owner and repository name | ||
|  |  */ | ||
|  | var getGitRepoInfo = function() { | ||
|  |   var GITURL_REGEX = /^https:\/\/github.com\/([^\/]+)\/(.+).git$/; | ||
|  |   var match = GITURL_REGEX.exec(currentPackage.repository.url); | ||
|  |   var git = { | ||
|  |     owner: match[1], | ||
|  |     repo: match[2] | ||
|  |   }; | ||
|  |   return git; | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /** | ||
|  |  * Extract the code name from the tagged commit's message - it should contain the text of the form: | ||
|  |  * "codename(some-code-name)" | ||
|  |  * @param  {String} tagName Name of the tag to look in for the codename | ||
|  |  * @return {String}         The codename if found, otherwise null/undefined | ||
|  |  */ | ||
|  | var getCodeName = function(tagName) { | ||
|  |   var gitCatOutput = shell.exec('git cat-file -p ' + tagName, {silent:true}).output; | ||
|  |   var tagMessage = gitCatOutput.match(/^.*codename.*$/mg)[0]; | ||
|  |   var codeName = tagMessage && tagMessage.match(/codename\((.*)\)/)[1]; | ||
|  |   if (!codeName) { | ||
|  |     throw new Error("Could not extract release code name. The message of tag " + tagName + | ||
|  |       " must match '*codename(some release name)*'"); | ||
|  |   } | ||
|  |   return codeName; | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | /** | ||
|  |  * Compute a build segment for the version, from the Jenkins build number and current commit SHA | ||
|  |  * @return {String} The build segment of the version | ||
|  |  */ | ||
|  | function getBuild() { | ||
|  |   var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', ''); | ||
|  |   return 'sha.' + hash; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /** | ||
|  |  * If the current commit is tagged as a version get that version | ||
|  |  * @return {SemVer} The version or null | ||
|  |  */ | ||
|  | var getTaggedVersion = function() { | ||
|  |   var gitTagResult = shell.exec('git describe --exact-match', {silent:true}); | ||
|  | 
 | ||
|  |   if (gitTagResult.code === 0) { | ||
|  |     var tag = gitTagResult.output.trim(); | ||
|  |     var version = semver.parse(tag); | ||
|  | 
 | ||
|  |     if (version && semver.satisfies(version, currentPackage.version)) { | ||
|  |       version.codeName = getCodeName(tag); | ||
|  |       version.full = version.version; | ||
|  |       version.branch = 'v' + currentPackage.branchPattern.replace('*', 'x'); | ||
|  |       return version; | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   return null; | ||
|  | }; | ||
|  | 
 | ||
|  | /** | ||
|  |  * Get a collection of all the previous versions sorted by semantic version | ||
|  |  * @return {Array.<SemVer>} The collection of previous versions | ||
|  |  */ | ||
|  | var getPreviousVersions =  function() { | ||
|  |   // always use the remote tags as the local clone might
 | ||
|  |   // not contain all commits when cloned with git clone --depth=...
 | ||
|  |   // Needed e.g. for Travis
 | ||
|  |   var repo_url = currentPackage.repository.url; | ||
|  |   var tagResults = shell.exec('git ls-remote --tags ' + repo_url, | ||
|  |                               {silent: true}); | ||
|  |   if (tagResults.code === 0) { | ||
|  |     return _(tagResults.output.match(/v[0-9].*[0-9]$/mg)) | ||
|  |       .map(function(tag) { | ||
|  |         var version = semver.parse(tag); | ||
|  |         return version; | ||
|  |       }) | ||
|  |       .filter() | ||
|  |       .map(function(version) { | ||
|  |         // angular.js didn't follow semantic version until 1.20rc1
 | ||
|  |         if ((version.major === 1 && version.minor === 0 && version.prerelease.length > 0) || (version.major === 1 && version.minor === 2 && version.prerelease[0] === 'rc1')) { | ||
|  |           version.version = [version.major, version.minor, version.patch].join('.') + version.prerelease.join(''); | ||
|  |           version.raw = 'v' + version.version; | ||
|  |         } | ||
|  |         version.docsUrl = 'http://code.angularjs.org/' + version.version + '/docs'; | ||
|  |         // Versions before 1.0.2 had a different docs folder name
 | ||
|  |         if (version.major < 1 || (version.major === 1 && version.minor === 0 && version.patch < 2)) { | ||
|  |           version.docsUrl += '-' + version.version; | ||
|  |           version.isOldDocsUrl = true; | ||
|  |         } | ||
|  |         return version; | ||
|  |       }) | ||
|  |       .sort(semver.compare) | ||
|  |       .value(); | ||
|  |   } else { | ||
|  |     return []; | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | /** | ||
|  |  * Get the unstable snapshot version | ||
|  |  * @return {SemVer} The snapshot version | ||
|  |  */ | ||
|  | var getSnapshotVersion = function() { | ||
|  |   var version = _(previousVersions) | ||
|  |     .filter(function(tag) { | ||
|  |       return semver.satisfies(tag, currentPackage.version); | ||
|  |     }) | ||
|  |     .last(); | ||
|  | 
 | ||
|  |   if (!version) { | ||
|  |     // a snapshot version before the first tag on the branch
 | ||
|  |     version = semver(currentPackage.branchPattern.replace('*','0-alpha.1')); | ||
|  |   } | ||
|  | 
 | ||
|  |   // We need to clone to ensure that we are not modifying another version
 | ||
|  |   version = semver(version.raw); | ||
|  | 
 | ||
|  |   var jenkinsBuild = process.env.TRAVIS_BUILD_NUMBER || process.env.BUILD_NUMBER; | ||
|  |   if (!version.prerelease || !version.prerelease.length) { | ||
|  |     // last release was a non beta release. Increment the patch level to
 | ||
|  |     // indicate the next release that we will be doing.
 | ||
|  |     // E.g. last release was 1.3.0, then the snapshot will be
 | ||
|  |     // 1.3.1-build.1, which is lesser than 1.3.1 accorind the semver!
 | ||
|  | 
 | ||
|  |     // If the last release was a beta release we don't update the
 | ||
|  |     // beta number by purpose, as otherwise the semver comparison
 | ||
|  |     // does not work any more when the next beta is released.
 | ||
|  |     // E.g. don't generate 1.3.0-beta.2.build.1
 | ||
|  |     // as this is bigger than 1.3.0-beta.2 according to semver
 | ||
|  |     version.patch++; | ||
|  |   } | ||
|  |   version.prerelease = jenkinsBuild ? ['build', jenkinsBuild] : ['local']; | ||
|  |   version.build = getBuild(); | ||
|  |   version.codeName = 'snapshot'; | ||
|  |   version.isSnapshot = true; | ||
|  |   version.format(); | ||
|  |   version.full = version.version + '+' + version.build; | ||
|  |   version.branch = 'master'; | ||
|  | 
 | ||
|  |   return version; | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | exports.currentPackage = currentPackage = getPackage(); | ||
|  | exports.gitRepoInfo = gitRepoInfo = getGitRepoInfo(); | ||
|  | exports.previousVersions = previousVersions = getPreviousVersions(); | ||
|  | exports.currentVersion = getTaggedVersion() || getSnapshotVersion(); |