-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1059 from chrisradek/script/add-change
Adds add-change CLI to allow easy creation of changelog entry JSON files.
- Loading branch information
Showing
5 changed files
with
611 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# AWS SDK for JavaScript Changelog Scripts | ||
|
||
These scripts create and update the changelog to summarize what has changed in | ||
each version of the AWS SDK for JavaScript. | ||
|
||
Here is a sample of what an entry in the changelog looks like: | ||
|
||
## 2.4.5 | ||
* bugfix: Waiters: Some description of the bugfix ([Issue #9542]()) | ||
* feature: S3: Some descripton of the new feature | ||
* API: RDS: Some description | ||
* API: DynamoDB: Some description | ||
|
||
Here is an overview of the scripts that create and update the changelog: | ||
|
||
### create-changelog | ||
|
||
This script can be used to create or recreate the changelog based on JSON files | ||
in the `.changes/` directory in the root directory of the SDK. This does not | ||
need to be run on a regular basis but is useful if the changelog accidentallly | ||
gets deleted or corrupted. A `.changes/` directory in the root directory will | ||
need to be created before running this script, if it does not already exist. To | ||
run this script, type the following command from the root SDK directory in the | ||
command line: | ||
``` | ||
./scripts/changelog/create-changelog | ||
``` | ||
The JSON files in the `.changes/` directory must be named with a version number | ||
(e.g. `2.4.5.json`) and its contents should be an array of objects. Each object | ||
represents one change in that version of the SDK, and should contain `"type"`, | ||
`"category"`, and `"description"` properties with string values. Incorrectly | ||
formatted filenames will be skipped over, and incorrectly formatted JSON within | ||
files with correctly formatted names will cause an error to be thrown and halt | ||
the execution of this script. The changelog file is not written to until the | ||
end, so if execution is halted, no files will have changed and no cleanup is | ||
required. The JSON files in `.changes/` are created in the `release` script. | ||
|
||
### release | ||
|
||
This script should be run for each release. It creates a new entry in the | ||
changelog based on JSON files in the `next-release/` directory in the | ||
`.changes/` directory in the root of the SDK. In addition, it will create a | ||
JSON file for the new version in the `.changes/` directory so that the entry | ||
can be recreated when the `create-changelog` script is run. The `.changes/` and | ||
`next-release/` directories will need to be created before running this script, | ||
if they do not already exist. To run this script, type the following command | ||
from the root SDK directory in the command line: | ||
``` | ||
./scripts/changelog/release | ||
``` | ||
Optionally, you can provide an argument to specify the version number of the | ||
new release. Accepted values are `major`, `minor`, `patch`, or a version number | ||
that is greater than the latest version (e.g. `2.4.6`). An error will be thrown | ||
if the specified version is not greater than the latest version, and execution | ||
will be halted. The former 3 choices specifies the type of version bump. For | ||
example, running | ||
``` | ||
./scripts/changelog/release minor | ||
``` | ||
will bump up the minor version from the latest version. If the latest version | ||
is `2.4.5`, then this would set the new version to `2.5.0`. If no argument is | ||
provided, then the script defaults to bumping the patch number. | ||
|
||
The JSON files in the `next-release/` directory can either contain a single | ||
object or an array of objects. Each object represents one change in the new | ||
version, and should contain `"type"`, `"category"`, and `"description"` | ||
properties with string values. Incorrectly formatted JSON will cause an error | ||
to be thrown and halt execution of this script. If execution is halted due to | ||
this error, no changes will have been made to any files yet at this point, so | ||
no cleanup will be required. | ||
|
||
The script merges all changes in `next-release/` to a new JSON file with the | ||
version number as its name, and files in `next-release/` are deleted. A new | ||
entry is then created in the changelog. If for any reason execution is halted | ||
after `next-release/` is cleared but before changes are written to the | ||
changelog, you can either just run the `create-changelog` script or you can | ||
move the new version JSON file into `next-release/` and re-run the `release` | ||
script (the name of the file does not matter). | ||
|
||
### add-change cli | ||
|
||
This script creates a changelog entry. The script prompts you to | ||
specify a `type` (e.g. bugfix or feature), a `category` (e.g. a service name | ||
or something like: Paginator), and a short `description` describing the change. | ||
|
||
Type the following command from the root SDK directory in the command line to | ||
run this script, using versions of node.js that support promises (0.12.x and higher): | ||
``` | ||
node ./scripts/changelog/add-change.js | ||
``` | ||
|
||
This script will place a JSON file representing your change in the following location: | ||
``` | ||
$SDK_ROOT/.changes/next-release/ | ||
``` | ||
|
||
Please run this script and include the JSON file when submitting a pull request. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
var ChangeCreator = require('./change-creator').ChangeCreator; | ||
|
||
/** | ||
* The CLI class to add a changelog entry. | ||
*/ | ||
function AddChangeCli() { | ||
this._changeCreator = new ChangeCreator(); | ||
this._maxRetries = 2; | ||
this._retryCount = 0; | ||
} | ||
|
||
AddChangeCli.prototype = { | ||
/** | ||
* Prints a string to stdout. | ||
* @param {string} message - text to print. | ||
*/ | ||
print: function print(message) { | ||
process.stdout.write(message); | ||
}, | ||
|
||
/** | ||
* Prints the CLI intro message. | ||
*/ | ||
showIntro: function showIntro() { | ||
var intro = '\n'; | ||
intro += 'This utility will walk you through creating a changelog entry.\n\n'; | ||
intro += 'A changelog entry requires:\n'; | ||
intro += '\t- type: Type should be one of: feature, bugfix.\n'; | ||
intro += '\t- category: This can be a service identifier (e.g. "s3"), or something like: Paginator.\n'; | ||
intro += '\t- description: A brief description of the change.\n'; | ||
intro += '\t You can also include a github style reference such as "#111".\n\n' | ||
intro += 'Please run this script before submitting a pull request.\n\n'; | ||
intro += 'Press ^C at any time to quit.\n'; | ||
this.print(intro); | ||
}, | ||
|
||
/** | ||
* Gets a string from stdin and returns a promise resolved with the string. | ||
* Note: stdin is read when the user presses 'Enter'. | ||
* Returns a promise that is resolved with the trimmed user input. | ||
*/ | ||
retrieveInputAsync: function retrieveInput() { | ||
return new Promise(function(resolve, reject) { | ||
function getData() { | ||
var chunk = process.stdin.read(); | ||
if (chunk !== null) { | ||
// Remove self from stdin and call callback | ||
process.stdin.removeListener('readable', getData); | ||
resolve(chunk.trim()); | ||
} | ||
} | ||
process.stdin.setEncoding('utf8'); | ||
// start listening for input | ||
process.stdin.on('readable', getData); | ||
}); | ||
}, | ||
|
||
/** | ||
* Prompts the user to enter a type. | ||
* Will also process the user input. | ||
* Returns a promise. | ||
*/ | ||
promptType: function promptType() { | ||
var changeCreator = this._changeCreator; | ||
var existingType = changeCreator.getChangeType(); | ||
this.print('\nValid types are "feature" or "bugfix"\n'); | ||
this.print('type: ' + (existingType ? '(' + existingType + ') ' : '')); | ||
return this.retrieveInputAsync() | ||
.then(this.processType.bind(this)); | ||
}, | ||
|
||
/** | ||
* Prompts the user to enter a category. | ||
* Will also process the user input. | ||
* Returns a promise. | ||
*/ | ||
promptCategory: function promptCategory() { | ||
var changeCreator = this._changeCreator; | ||
var existingCategory = changeCreator.getChangeCategory(); | ||
this.print('\nCategory can be a service identifier or something like: Paginator\n'); | ||
this.print('category: ' + (existingCategory ? '(' + existingCategory + ') ' : '')); | ||
return this.retrieveInputAsync() | ||
.then(this.processCategory.bind(this)); | ||
}, | ||
|
||
/** | ||
* Prompts the user to enter a description. | ||
* Will also process the user input. | ||
* Returns a promise. | ||
*/ | ||
promptDescription: function promptDescription() { | ||
var changeCreator = this._changeCreator; | ||
var existingDescription = changeCreator.getChangeDescription(); | ||
this.print('\nA brief description of your change.\n'); | ||
this.print('description: ' + (existingDescription ? '(' + existingDescription + ') ' : '')); | ||
return this.retrieveInputAsync() | ||
.then(this.processDescription.bind(this)); | ||
}, | ||
|
||
/** | ||
* Handles processing of `type` based on user input. | ||
* If validation of `type` fails, the prompt will be shown again up to 3 times. | ||
* Returns a promise. | ||
*/ | ||
processType: function processType(type) { | ||
var changeCreator = this._changeCreator; | ||
var type = type.toLowerCase(); | ||
// validate | ||
try { | ||
if (type) { | ||
changeCreator.setChangeType(type); | ||
} | ||
changeCreator.validateChangeType(type); | ||
} catch (err) { | ||
// Log the error | ||
this.print(err.message + '\n'); | ||
// re-prompt if we still have retries | ||
if (this._retryCount < this._maxRetries) { | ||
this._retryCount++; | ||
return this.promptType(); | ||
} | ||
//otherwise, just exit | ||
return Promise.reject(); | ||
} | ||
// reset retry count | ||
this._retryCount = 0; | ||
return Promise.resolve(); | ||
}, | ||
|
||
/** | ||
* Handles processing of `category` based on user input. | ||
* If validation of `category` fails, the prompt will be shown again up to 3 times. | ||
* Returns a promise. | ||
*/ | ||
processCategory: function processCategory(category) { | ||
var changeCreator = this._changeCreator; | ||
// validate | ||
try { | ||
if (category) { | ||
changeCreator.setChangeCategory(category); | ||
} | ||
changeCreator.validateChangeCategory(category); | ||
} catch (err) { | ||
// Log the error | ||
this.print(err.message + '\n'); | ||
// re-prompt if we still have retries | ||
if (this._retryCount < this._maxRetries) { | ||
this._retryCount++; | ||
return this.promptCategory(); | ||
} | ||
//otherwise, just exit | ||
return Promise.reject(); | ||
} | ||
// reset retry count | ||
this._retryCount = 0; | ||
return Promise.resolve(); | ||
}, | ||
|
||
/** | ||
* Handles processing of `description` based on user input. | ||
* If validation of `description` fails, the prompt will be shown again up to 3 times. | ||
* Returns a promise. | ||
*/ | ||
processDescription: function processDescription(description) { | ||
var changeCreator = this._changeCreator; | ||
// validate | ||
try { | ||
if (description) { | ||
changeCreator.setChangeDescription(description); | ||
} | ||
changeCreator.validateChangeDescription(description); | ||
} catch (err) { | ||
// Log the error | ||
this.print(err.message + '\n'); | ||
// re-prompt if we still have retries | ||
if (this._retryCount < this._maxRetries) { | ||
this._retryCount++; | ||
return this.promptDescription(); | ||
} | ||
//otherwise, just exit | ||
return Promise.reject(); | ||
} | ||
// reset retry count | ||
this._retryCount = 0; | ||
return Promise.resolve(); | ||
}, | ||
|
||
/** | ||
* Prompts the user for all inputs. | ||
* Returns a promise. | ||
*/ | ||
promptInputs: function promptInputs() { | ||
var self = this; | ||
return this.promptType() | ||
.then(this.promptCategory.bind(this)) | ||
.then(this.promptDescription.bind(this)) | ||
.catch(function(err) { | ||
self.print(err.message); | ||
}); | ||
}, | ||
|
||
/** | ||
* Writes the changelog entry to a JSON file. | ||
* Returns a promise that is resolved with the output filename. | ||
*/ | ||
writeChangeEntry: function writeChangeEntry() { | ||
var self = this; | ||
return new Promise(function(resolve, reject) { | ||
var changeCreator = self._changeCreator; | ||
changeCreator.writeChanges(function(err, data) { | ||
if (err) { | ||
return reject(err); | ||
} | ||
self.print('\nFile created at ' + data.file + '\n'); | ||
return resolve(data); | ||
}); | ||
}); | ||
} | ||
}; | ||
|
||
// Run the CLI program | ||
var cli = new AddChangeCli(); | ||
cli.showIntro(); | ||
cli.promptInputs() | ||
.then(cli.writeChangeEntry.bind(cli)) | ||
.then(function() { | ||
// CLI done with its work, exit successfully. | ||
setTimeout(function() { | ||
process.exit(0) | ||
}, 0); | ||
}) | ||
.catch(function(err) { | ||
cli.print(err.message); | ||
cli.print('\nExiting...\n'); | ||
setTimeout(function() { | ||
// CLI failed, exit with an error | ||
process.exit(1); | ||
}, 0); | ||
}); |
Oops, something went wrong.