util.js
  1  var fs = require('fs');
  2  var changelog, latest, nextReleaseFiles;
  3  
  4  var changelogFile = process.cwd() + '/CHANGELOG.md';
  5  var changesDir = process.cwd() + '/.changes/';
  6  var nextReleaseDir = changesDir + 'next-release/';
  7  var insertMarker = '<!--ENTRYINSERT-->';
  8  var versionMarker = ['<!--LATEST=', '-->'];
  9  var startContent = '# Changelog for AWS SDK for JavaScript\n' +
 10  	versionMarker.join('0.0.0') + '\n' + insertMarker;
 11  
 12  var versionRegStr = '(\\d+)\\.(\\d+)\\.(\\d+)';
 13  var versionReg = new RegExp('^' + versionRegStr + '$');
 14  var versionMarkerReg = new RegExp(versionMarker.join(versionRegStr));
 15  var versionJsonFileReg = new RegExp('^' + versionRegStr + '\\.json$');
 16  
 17  function fsSyncFromRoot(operation, fileOrDir) {
 18  	try {
 19  		var result = fs[operation + 'Sync'](fileOrDir);
 20  	} catch(err) {
 21  		if (err.code === 'ENOENT') {
 22  			err.message += '. Make sure to run from sdk root directory'
 23  		}
 24  		throw err;
 25  	}
 26  	return result;
 27  }
 28  
 29  function readChangelog() {
 30  	changelog = fsSyncFromRoot('readFile', changelogFile).toString();
 31  	return changelog;
 32  }
 33  
 34  function getLatestVersion() {
 35  	if (!changelog) readChangelog();
 36  	var match = changelog.match(versionMarkerReg);
 37  	latest = {
 38  		major: parseInt(match[1],10),
 39  		minor: parseInt(match[2],10),
 40  		patch: parseInt(match[3],10)
 41  	};
 42  	return latest;
 43  }
 44  
 45  function checkAndNormalizeVersion(version) {
 46  	if (!latest) getLatestVersion();
 47  	var match = version.match(versionReg);
 48  	if (match) {
 49  		// convert to num for comparison and for normalizing leading zeros
 50  		var major = parseInt(match[1], 10);
 51  		var minor = parseInt(match[2], 10);
 52  		var patch = parseInt(match[3], 10);
 53  		if (major < latest.major ||
 54  			major == latest.major && minor < latest.minor ||
 55  			major == latest.major && minor == latest.minor && patch <= latest.patch) {
 56  			throw new Error('Version must be greater than latest version');
 57  		}
 58  		return major + '.' + minor + '.' + patch;
 59  	} else {
 60  		throw new Error('Provided input version is in wrong format');
 61  	}
 62  }
 63  
 64  function bumpMajor() {
 65  	if (!latest) getLatestVersion();
 66  	return (latest.major + 1) + '.0.0';
 67  }
 68  
 69  function bumpMinor() {
 70  	if (!latest) getLatestVersion();
 71  	return latest.major + '.' + (latest.minor + 1) + '.0';
 72  }
 73  
 74  function bumpPatch() {
 75  	if (!latest) getLatestVersion();
 76  	return latest.major + '.' + latest.minor + '.' + (latest.patch + 1);
 77  }
 78  
 79  function listVersions() {
 80  	var changeFiles = fsSyncFromRoot('readdir', changesDir);
 81  	return changeFiles
 82  		.map(function(file) { return file.match(versionJsonFileReg); })
 83  		.filter(function(version) { return !!version; })
 84  		.sort(function(v1, v2) {
 85  			var diff;
 86  			for (var i = 1; i <= 3; i++) {
 87  				diff = v1[i] - v2[i];
 88  				if (diff !== 0) {
 89  					return diff;
 90  				}
 91  			}
 92  			return 0;
 93  		})
 94  		.map(function(version) { return version.slice(1).join('.'); });
 95  }
 96  
 97  function listNextReleaseFiles() {
 98  	nextReleaseFiles = fsSyncFromRoot('readdir', nextReleaseDir)
 99  		.map(function(file) { return nextReleaseDir + file });
100  	if (!nextReleaseFiles.length) throw new Error('No changes to be released');
101  	return nextReleaseFiles;
102  }
103  
104  function startNewChangelog() {
105  	changelog = startContent;
106  	return changelog;
107  }
108  
109  function checkChangeFormat(change) {
110  	if (!change.type || !change.category || !change.description ||
111  		typeof change.type !== 'string' ||
112  		typeof change.category !== 'string' ||
113  		typeof change.description !== 'string') {
114  		var err = new Error('JSON not in correct format');
115  		err.code = 'InvalidFormat';
116  		throw err;
117  	}
118  }
119  
120  function readChangesFromJSON(filepath) {
121  	var changes = JSON.parse(fsSyncFromRoot('readFile', filepath));
122  	if (!Array.isArray(changes)) changes = [changes];
123  	if (!changes.length) throw new Error(filepath + ' contains no changes');
124  	try {
125  		changes.forEach(checkChangeFormat);
126  	} catch (err) {
127  		if (err.code === 'InvalidFormat') {
128  			err.message += ' in ' + filepath;
129  		}
130  		throw err;
131  	}
132  	return changes;
133  }
134  
135  // This will not to write to file
136  // writeToChangelog must be called after
137  function addVersionJSONToChangelog(version, changes) {
138  	if (!changelog) readChangelog();
139  	var entry = '\n\n## ' + version;
140  
141  	changes.forEach(function(change) {
142  		entry += '\n* ' + change.type + ': ' + change.category + ': ' +
143  			change.description;
144  	});
145  
146  	var logParts = changelog.split(insertMarker);
147  	logParts[0] = logParts[0]
148  		.replace(versionMarkerReg, versionMarker.join(version)) + insertMarker;
149  	changelog = logParts.join(entry);
150  }
151  
152  // This will not to write to file
153  // writeToChangelog must be called after
154  function readVersionJSONAndAddToChangelog(version) {
155  	var changes = readChangesFromJSON(changesDir + version + '.json');
156  	addVersionJSONToChangelog(version, changes);
157  }
158  
159  function writeToChangelog() {
160  	if (!changelog) throw new Error('Nothing to write');
161  	fs.writeFileSync(changelogFile, changelog);
162  	console.log('Successfully updated CHANGELOG');
163  }
164  
165  function writeToVersionJSON(version, json) {
166  	var content = JSON.stringify(json, null, 4);
167  	fs.writeFileSync(changesDir + version + '.json', content);
168  	console.log('Successfully added ' + version + '.json to ' + changesDir);
169  }
170  
171  function clearNextReleaseDir() {
172  	if (!nextReleaseFiles) listNextReleaseFiles();
173  	nextReleaseFiles.forEach(function(filepath) {
174  		fsSyncFromRoot('unlink', filepath);
175  	});
176  	console.log(nextReleaseDir + ' has been cleared');
177  }
178  
179  module.exports = {
180  	readChangelog: readChangelog,
181  	getLatestVersion: getLatestVersion,
182  	checkAndNormalizeVersion: checkAndNormalizeVersion,
183  	bumpMajor: bumpMajor,
184  	bumpMinor: bumpMinor,
185  	bumpPatch: bumpPatch,
186  	listVersions: listVersions,
187  	listNextReleaseFiles: listNextReleaseFiles,
188  	startNewChangelog: startNewChangelog,
189  	readChangesFromJSON: readChangesFromJSON,
190  	addVersionJSONToChangelog: addVersionJSONToChangelog,
191  	readVersionJSONAndAddToChangelog: readVersionJSONAndAddToChangelog,
192  	writeToChangelog: writeToChangelog,
193  	writeToVersionJSON: writeToVersionJSON,
194  	clearNextReleaseDir: clearNextReleaseDir
195  };