git-off

git off handles large files in git repos
git clone https://noulin.net/git/git-off.git
Log | Files | Refs | README

add-change.js (8170B)


      1 var ChangeCreator = require('./change-creator').ChangeCreator;
      2 
      3 /**
      4  * The CLI class to add a changelog entry.
      5  */
      6 function AddChangeCli() {
      7     this._changeCreator = new ChangeCreator();
      8     this._maxRetries = 2;
      9     this._retryCount = 0;
     10 }
     11 
     12 AddChangeCli.prototype = {
     13     /**
     14      * Prints a string to stdout.
     15      * @param {string} message - text to print.
     16      */
     17     print: function print(message) {
     18         process.stdout.write(message);
     19     },
     20 
     21     /**
     22      * Prints the CLI intro message.
     23      */
     24     showIntro: function showIntro() {
     25         var intro = '\n';
     26         intro += 'This utility will walk you through creating a changelog entry.\n\n';
     27         intro += 'A changelog entry requires:\n';
     28         intro += '\t- type: Type should be one of: feature, bugfix.\n';
     29         intro += '\t- category: This can be a service identifier (e.g. "s3"), or something like: Paginator.\n';
     30         intro += '\t- description: A brief description of the change.\n';
     31         intro += '\t    You can also include a github style reference such as "#111".\n\n'
     32         intro += 'Please run this script before submitting a pull request.\n\n';
     33         intro += 'Press ^C at any time to quit.\n';
     34         this.print(intro);
     35     },
     36 
     37     /**
     38      * Gets a string from stdin and returns a promise resolved with the string.
     39      * Note: stdin is read when the user presses 'Enter'.
     40      * Returns a promise that is resolved with the trimmed user input.
     41      */
     42     retrieveInputAsync: function retrieveInput() {
     43         return new Promise(function(resolve, reject) {
     44             function getData() {
     45                 var chunk = process.stdin.read();
     46                 if (chunk !== null) {
     47                     // Remove self from stdin and call callback
     48                     process.stdin.removeListener('readable', getData);
     49                     resolve(chunk.trim());
     50                 }
     51             }
     52             process.stdin.setEncoding('utf8');
     53             // start listening for input
     54             process.stdin.on('readable', getData);
     55         });
     56     },
     57 
     58     /**
     59      * Prompts the user to enter a type.
     60      * Will also process the user input.
     61      * Returns a promise.
     62      */
     63     promptType: function promptType() {
     64         var changeCreator = this._changeCreator;
     65         var existingType = changeCreator.getChangeType();
     66         this.print('\nValid types are "feature" or "bugfix"\n');
     67         this.print('type: ' + (existingType ? '(' + existingType + ') ' : ''));
     68         return this.retrieveInputAsync()
     69             .then(this.processType.bind(this));
     70     },
     71 
     72     /**
     73      * Prompts the user to enter a category.
     74      * Will also process the user input.
     75      * Returns a promise.
     76      */
     77     promptCategory: function promptCategory() {
     78         var changeCreator = this._changeCreator;
     79         var existingCategory = changeCreator.getChangeCategory();
     80         this.print('\nCategory can be a service identifier or something like: Paginator\n');
     81         this.print('category: ' + (existingCategory ? '(' + existingCategory + ') ' : ''));
     82         return this.retrieveInputAsync()
     83             .then(this.processCategory.bind(this));
     84     },
     85 
     86     /**
     87      * Prompts the user to enter a description.
     88      * Will also process the user input.
     89      * Returns a promise.
     90      */
     91     promptDescription: function promptDescription() {
     92         var changeCreator = this._changeCreator;
     93         var existingDescription = changeCreator.getChangeDescription();
     94         this.print('\nA brief description of your change.\n');
     95         this.print('description: ' + (existingDescription ? '(' + existingDescription + ') ' : ''));
     96         return this.retrieveInputAsync()
     97             .then(this.processDescription.bind(this));
     98     },
     99 
    100     /**
    101      * Handles processing of `type` based on user input.
    102      * If validation of `type` fails, the prompt will be shown again up to 3 times.
    103      * Returns a promise.
    104      */
    105     processType: function processType(type) {
    106         var changeCreator = this._changeCreator;
    107         var type = type.toLowerCase();
    108         // validate
    109         try {
    110             if (type) {
    111                 changeCreator.setChangeType(type);
    112             }
    113             changeCreator.validateChangeType(type);
    114         } catch (err) {
    115             // Log the error
    116             this.print(err.message + '\n');
    117             // re-prompt if we still have retries
    118             if (this._retryCount < this._maxRetries) {
    119                 this._retryCount++;
    120                 return this.promptType();
    121             }
    122             //otherwise, just exit
    123             return Promise.reject();
    124         }
    125         // reset retry count
    126         this._retryCount = 0;
    127         return Promise.resolve();
    128     },
    129 
    130     /**
    131      * Handles processing of `category` based on user input.
    132      * If validation of `category` fails, the prompt will be shown again up to 3 times.
    133      * Returns a promise.
    134      */
    135     processCategory: function processCategory(category) {
    136         var changeCreator = this._changeCreator;
    137         // validate
    138         try {
    139             if (category) {
    140                 changeCreator.setChangeCategory(category);
    141             }
    142             changeCreator.validateChangeCategory(category);
    143         } catch (err) {
    144             // Log the error
    145             this.print(err.message + '\n');
    146             // re-prompt if we still have retries
    147             if (this._retryCount < this._maxRetries) {
    148                 this._retryCount++;
    149                 return this.promptCategory();
    150             }
    151             //otherwise, just exit
    152             return Promise.reject();
    153         }
    154         // reset retry count
    155         this._retryCount = 0;
    156         return Promise.resolve();
    157     },
    158 
    159     /**
    160      * Handles processing of `description` based on user input.
    161      * If validation of `description` fails, the prompt will be shown again up to 3 times.
    162      * Returns a promise.
    163      */
    164     processDescription: function processDescription(description) {
    165         var changeCreator = this._changeCreator;
    166         // validate
    167         try {
    168             if (description) {
    169                 changeCreator.setChangeDescription(description);
    170             }
    171             changeCreator.validateChangeDescription(description);
    172         } catch (err) {
    173             // Log the error
    174             this.print(err.message + '\n');
    175             // re-prompt if we still have retries
    176             if (this._retryCount < this._maxRetries) {
    177                 this._retryCount++;
    178                 return this.promptDescription();
    179             }
    180             //otherwise, just exit
    181             return Promise.reject();
    182         }
    183         // reset retry count
    184         this._retryCount = 0;
    185         return Promise.resolve();
    186     },
    187 
    188     /**
    189      * Prompts the user for all inputs.
    190      * Returns a promise.
    191      */
    192     promptInputs: function promptInputs() {
    193         var self = this;
    194         return this.promptType()
    195             .then(this.promptCategory.bind(this))
    196             .then(this.promptDescription.bind(this))
    197             .catch(function(err) {
    198                 self.print(err.message);
    199             });
    200     },
    201 
    202     /**
    203      * Writes the changelog entry to a JSON file.
    204      * Returns a promise that is resolved with the output filename.
    205      */
    206     writeChangeEntry: function writeChangeEntry() {
    207         var self = this;
    208         return new Promise(function(resolve, reject) {
    209             var changeCreator = self._changeCreator;
    210             changeCreator.writeChanges(function(err, data) {
    211                 if (err) {
    212                     return reject(err);
    213                 }
    214                 self.print('\nFile created at ' + data.file + '\n');
    215                 return resolve(data);
    216             });
    217         });
    218     }
    219 };
    220 
    221 // Run the CLI program
    222 var cli = new AddChangeCli();
    223 cli.showIntro();
    224 cli.promptInputs()
    225     .then(cli.writeChangeEntry.bind(cli))
    226     .then(function() {
    227         // CLI done with its work, exit successfully.
    228         setTimeout(function() {
    229             process.exit(0)
    230         }, 0);
    231     })
    232     .catch(function(err) {
    233         cli.print(err.message);
    234         cli.print('\nExiting...\n');
    235         setTimeout(function() {
    236             // CLI failed, exit with an error
    237             process.exit(1);
    238         }, 0);
    239     });