Monday, 3 April 2017

Is there a better way to run CLI commands with Node.js?

I just wrote a script to release a build of one of the products I'm working on. The script does the job, but I don't really like the code itself, looks like spaghetti code and callback hell combined.

Is there a cleaner way to do this? I'd like to be able to run commands in series, log the outputs (stdout.on('data')) and when the task is finished. (easier for further debug and when waiting for the task to be done, reassuring to know what's happening on the background)

Maybe using Promises would help clean the mess a bit, but still, I feel like there should be a cleaner way to deal with multiple commands.


Some explanation about what the code does:

  1. Create a tag with the commit you want and the tag version you want, i.e: git tag 1.2.5.
  2. Build the release file with gulp build.
  3. Create a folder doc/<tag>.
  4. Convert doc/doc_reader.odt to doc/<tag>/documentation.pdf. (Open it and export as PDF)
  5. Copy build/reader.js and doc/changelog.txt in the created folder.
  6. Zip the 3 files.
  7. Commit everything with commit message: Release 1.2.11 (for example)
  8. Push.
  9. Create a new release on GitHub using the commit you just pushed and the same tag.

Here is the code, as an example. (ES5, Node 4.6.0+)

var mkdirp = require('mkdirp');
var fs = require('fs-extra');
var path = require('path');
var spawn = require('child_process').spawn;
var zip = new require('node-zip')();

var package = require('../package.json');
var version = package.version;
var releaseDirectory = 'doc'
var gitTagProcess = spawn('git', ['tag', version]);
var gulpBuildProcess = spawn('gulp', ['build']);

console.log(`Running "git tag ${version}"...`);
gitTagProcess.stdout.on('data', function (chunk) {
  console.log(chunk.toString('utf8'));
});

gitTagProcess.on('close', function () {
  console.log('Tag created.')

  console.log('Running "gulp build"...');
  gulpBuildProcess.stdout.on('data', function (chunk) {
    console.log(chunk.toString('utf8'));
  });

  gulpBuildProcess.on('close', function () {
    console.log('"gulp build" done.')

    console.log(`Creating "${releaseDirectory}/${version}" directory.`)
    mkdirp(`${releaseDirectory}/${version}`, function () {
      console.log('Directory created.');
      var docFile = `${releaseDirectory}/doc_reader.md`;
      console.log(`Converting ${docFile} to pdf ...`);
      var docBuildProcess = spawn('npm', ['run', 'build:doc']);

      docBuildProcess.stdout.on('data', function (chunk) {
        console.log(chunk.toString('utf8'));
      });

      docBuildProcess.on('close', function () {
        console.log('Doc created.');

        console.log('Copying changelog.txt ...');
        fs.copySync('doc/changelog.txt', `doc/${version}/changelog.txt`);
        console.log('changelog.txt copied.');

        console.log(`Copying "build/reader.js" to "doc/reader-${version}.js" and "doc/reader.js" ...`);
        fs.copySync('build/reader.js', `doc/${version}/reader.js`);
        fs.copySync('build/reader.js', `doc/${version}/reader-${version}.js`);
        console.log('reader.js copied.');

        console.log('Zipping all files ...');
        zip.file('changelog.txt', fs.readFileSync(`doc/${version}/changelog.txt`));
        zip.file('doc_reader.pdf', fs.readFileSync(`doc/${version}/doc_reader.pdf`));
        zip.file('reader.js', fs.readFileSync(`doc/${version}/reader.js`));
        zip.file(`reader-${version}.js`, fs.readFileSync(`doc/${version}/reader-${version}.js`));

        var data = zip.generate({ base64: false, compression: 'DEFLATE' });
        var zipFilename = `doc/${version}/HTML5Reader_${version}.zip`;
        fs.writeFileSync(zipFilename, data, 'binary'); // it's important to use *binary* encode
        console.log(`${zipFilename} created.`);

        console.log(`\nRelease ${version} done. Please add generated files and commit using:`);
        console.log(`\n\tgit add * && git commit -m "Release ${version}"`);
        console.log(`\n\nDon't forget to push and create a new release on GitHub at https://github.com/$domain/$product/releases/new?tag=${version}`);
      });
    });
  });
});



via Vadorequest

No comments:

Post a Comment