mirror of
https://github.com/cderche/greenlock-storage-s3
synced 2025-02-22 06:08:04 +00:00
213 lines
5.9 KiB
JavaScript
213 lines
5.9 KiB
JavaScript
var fs = require('fs');
|
|
var path = require('path');
|
|
var crypto = require('crypto');
|
|
/**
|
|
* Configuration Options:
|
|
* - write file location
|
|
* - read file location
|
|
*/
|
|
|
|
function checkProperty(obj, prop) {
|
|
return Object.prototype.hasOwnProperty.call(obj, prop);
|
|
}
|
|
|
|
/**
|
|
* Generates a 'random' hex value.
|
|
* More 'random' than Math.random without depending on a GUID module.
|
|
*/
|
|
function generateRandomIdentifier() {
|
|
return crypto.randomBytes(4).toString('hex');
|
|
}
|
|
|
|
var CHANGES_DIR = path.join(process.cwd(), '.changes');
|
|
|
|
/**
|
|
* A map of valid change types.
|
|
* Can be referenced outside of this module.
|
|
*/
|
|
var VALID_TYPES = Object.create(null);
|
|
VALID_TYPES['bugfix'] = true;
|
|
VALID_TYPES['feature'] = true;
|
|
|
|
|
|
/**
|
|
* Handles creating a change log entry JSON file.
|
|
*/
|
|
function ChangeCreator(config) {
|
|
this._config = config || {};
|
|
this._type = '';
|
|
this._category = '';
|
|
this._description = '';
|
|
}
|
|
|
|
ChangeCreator.prototype = {
|
|
getChangeType: function getChangeType() {
|
|
return this._type;
|
|
},
|
|
|
|
setChangeType: function setChangeType(type) {
|
|
this._type = type;
|
|
},
|
|
|
|
getChangeCategory: function getChangeCategory() {
|
|
return this._category;
|
|
},
|
|
|
|
setChangeCategory: function setChangeCategory(category) {
|
|
this._category = category;
|
|
},
|
|
|
|
getChangeDescription: function getChangeDescription() {
|
|
return this._description;
|
|
},
|
|
|
|
setChangeDescription: function setChangeDescription(description) {
|
|
this._description = description;
|
|
},
|
|
|
|
/**
|
|
* Validates the entire change entry.
|
|
*/
|
|
validateChange: function validateChange() {
|
|
var type = this.getChangeType();
|
|
var category = this.getChangeCategory();
|
|
var description = this.getChangeDescription();
|
|
|
|
var missingFields = [];
|
|
this.validateChangeType(type);
|
|
this.validateChangeCategory(category);
|
|
this.validateChangeDescription(description);
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Validates a change entry type.
|
|
*/
|
|
validateChangeType: function validateChangeType(type) {
|
|
var type = type || this._type;
|
|
|
|
if (!type) {
|
|
throw new Error('ValidationError: Missing `type` field.');
|
|
}
|
|
|
|
if (VALID_TYPES[type]) {
|
|
return this;
|
|
}
|
|
|
|
var validTypes = Object.keys(VALID_TYPES).join(',');
|
|
|
|
throw new Error('ValidationError: `type` set as "' + type + '" but must be one of [' + validTypes + '].');
|
|
},
|
|
|
|
/**
|
|
* Validates a change entry category.
|
|
*/
|
|
validateChangeCategory: function validateChangeCategory(category) {
|
|
var category = category || this._category;
|
|
|
|
if (!category) {
|
|
throw new Error('ValidationError: Missing `category` field.');
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Validates a change entry description.
|
|
*/
|
|
validateChangeDescription: function validateChangeDescription(description) {
|
|
var description = description || this._description;
|
|
|
|
if (!description) {
|
|
throw new Error('ValidationError: Missing `description` field.');
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Creates the output directory if it doesn't exist.
|
|
*/
|
|
createOutputDirectory: function createOutputDirectory(outPath) {
|
|
var pathObj = path.parse(outPath);
|
|
var sep = path.sep;
|
|
var directoryStructure = pathObj.dir.split(sep) || [];
|
|
for (var i = 0; i < directoryStructure.length; i++) {
|
|
var pathToCheck = directoryStructure.slice(0, i + 1).join(sep);
|
|
if (!pathToCheck) {
|
|
continue;
|
|
}
|
|
try {
|
|
var stats = fs.statSync(pathToCheck);
|
|
} catch (err) {
|
|
if (err.code === 'ENOENT') {
|
|
// Directory doesn't exist, so create it
|
|
fs.mkdirSync(pathToCheck);
|
|
} else {
|
|
throw err;
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Returns a path to the future change entry file.
|
|
*/
|
|
determineWriteLocation: function determineWriteLocation() {
|
|
/* Order for determining write location:
|
|
1) Check configuration for `outFile` location.
|
|
2) Check configuration for `inFile` location.
|
|
3) Create a new file using default location.
|
|
*/
|
|
var config = this._config || {};
|
|
if (checkProperty(config, 'outFile') && config['outFile']) {
|
|
return config['outFile'];
|
|
}
|
|
if (checkProperty(config, 'inFile') && config['inFile']) {
|
|
return config['inFile'];
|
|
}
|
|
// Determine default location
|
|
var newFileName = this._type + '-' + this._category + '-' + generateRandomIdentifier() + '.json';
|
|
return path.join(process.cwd(), '.changes', 'next-release', newFileName);
|
|
},
|
|
|
|
/**
|
|
* Writes a change entry as a JSON file.
|
|
*/
|
|
writeChanges: function writeChanges(callback) {
|
|
var hasCallback = typeof callback === 'function';
|
|
var fileLocation = this.determineWriteLocation();
|
|
|
|
try {
|
|
// Will throw an error if the change is not valid
|
|
this.validateChange().createOutputDirectory(fileLocation);
|
|
var change = {
|
|
type: this.getChangeType(),
|
|
category: this.getChangeCategory(),
|
|
description: this.getChangeDescription()
|
|
}
|
|
fs.writeFileSync(fileLocation, JSON.stringify(change, null, 2));
|
|
var data = {
|
|
file: fileLocation
|
|
};
|
|
if (hasCallback) {
|
|
return callback(null, data);
|
|
} else {
|
|
return data;
|
|
}
|
|
} catch (err) {
|
|
if (hasCallback) {
|
|
return callback(err, null);
|
|
} else {
|
|
throw err;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
ChangeCreator: ChangeCreator,
|
|
VALID_TYPES: VALID_TYPES
|
|
}; |