3

I'm trying to automate a process I go through every time I test my apps and sites on the server. I'm currently running on nodejitsu. When I've tested something and it works on my local machine, the next thing I do is...

  1. Open my package.json file
  2. Delete the domains field and change the name and subdomain to staging. (It might also make sense to change the version number)
  3. Then I jitsu deploy
  4. Confirm any prompts (like approve an increment of the version number)
  5. Once the app starts I check out how my apps working on the server, make changes and so on

After I'm done, and my apps ready to go I undo my changes in my package.json file. I'd like to automate this process. I had the idea of doing so with a tiny node.js file. Here it is so far...

/*
 * Use this file to deploy an app to the staging server on nodejitsu
 */
var bash = require('child_process').spawn('bash');
var colors = require('colors');
var fs = require('fs');

// stdout setup
bash.stdout.on('data', function (data) {
  console.log('stdout: ' + data);
});
bash.stdout.on('error', function (err) {
  console.log('stdout error: '.red, err);
});

// on bash exit
bash.on('exit', function (code) {
  console.log('Exiting... ', code);
});

// grab package.json
var package = '';
fs.readFile('package.json', {encoding: 'utf-8'}, function (err, data) { // grab the package.json file contents
  if (err) throw err;
  package = JSON.parse(data);
  fs.rename('package.json', 'rename-me-before-deploying.json'); // rename the package.json file
  package.name = 'stajing'; // alter json
  package.subdomain = 'stajing'; // alter json
  package.domains = []; // alter json
  fs.writeFile('package.json', JSON.stringify(package, null, 2), function(err) { // write the new package to package.json
    if (err) throw err;
    bash.stdin.write('jitsu deploy\n'); // Deploy to staging app on nodejitsu.
    setTimeout(function () { // this needs to be replaced
      bash.stdin.write('yes\n');
    }, 5000);
    console.log("All done : )");
    // bash.stdin.end(); // close out
  });
});

I have a few issues here. I'm pretty sure all I need to know to complete it, is the event that fires when nodejitsu prompts me to increment the version number prompt: Is this ok?: (yes) so that I can confirm, if that happens, and the event that fires when the whole process finishes so that I can revert the changes to my package.json file, leaving my app deployed to a staging environment and my files essentially untouched.

Costa Michailidis
  • 7,691
  • 15
  • 72
  • 124
  • 2
    The `undefined` seems to be from the `'exit'` event as `colors` [doesn't appear to define `orange`](https://www.npmjs.org/package/colors#colors-and-styles-). – Jonathan Lonowski Apr 17 '14 at 21:25
  • You rock!!!!!!! (exclamation points courtesy Stackoverflow's minimum character count for comments) – Costa Michailidis Apr 17 '14 at 21:29
  • 2
    what exactly is your question? btw, why in the world do you have to manipulate your package.json? you should not to have to do it. there are different possibilities to handle environment specific configurations. – greelgorke Apr 23 '14 at 08:46
  • I ended up posting another question (here: http://stackoverflow.com/q/23209413/1027004) and ultimately I needed to make this: https://gist.github.com/CostaMichailidis/11181252 – Costa Michailidis Apr 23 '14 at 12:01
  • I agree that you shouldn't need to manipulate the package.json file, but I couldn't figure out another way of testing my app on the server as it would be for production. I can test locally, but once I deploy, it goes live (regardless of NODE_ENV as far as I can tell). So, I set up a single separate "app" with a single drone to test my sites/apps. – Costa Michailidis Apr 23 '14 at 13:29
  • what exactly is in your package.json that prevents you from testing? – greelgorke Apr 25 '14 at 07:46
  • The name, subdomain and domains array are read by jitsu and it deploys to my production server(drone). I can test locally no problem, but if I want to test on my server, I have to deploy, so I change those fields and deploy to a drone(server) dedicated to testing. – Costa Michailidis Apr 25 '14 at 15:16

1 Answers1

2

I'm not setup here to run jitsu deploy. However, here is some code that illustrates how you can deal with the prompts:

var command = require('child_process').spawn('./command.js');
require('colors');

var stdout = "";
var prompt_re = /Is it okay \(yes\)\?.*?$/m;
command.stdout.on('data', function (data) {
    console.log("stdout data: ".green + data);
    stdout += data;
    if (prompt_re.test(stdout)) {
        command.stdin.write("yes\n");
        // Flush the current buffer.
        stdout = "";
    }
});

command.stdout.on('error', function (err) {
    console.log('stdout error: '.red, err);
});

var exit_msg = 'Exited with code... ';
command.on('exit', function (code) {
    if (code != 0) {
        console.log(exit_msg.red, code);
        process.exit(1); // Or whatever you want to handle errors.
    }

    console.log(exit_msg.green, code);
    // The code you want to execute once your command is done goes here.
});

Some explanations:

  1. The code above buffers the data it gets from command.stdout into as string stored in the stdout variable and tests against that because if there's a lot of output there's no guarantee that the prompt will arrive in a single data event. (It could, for instance, come in one event that contains a bunch of data + the string Is it and then the next data event could contain the rest of the prompt.)

  2. The regular expression prompt_re contains '.*?$' because the command I use to simulate getting a prompt uses escape codes for colors and I could not be bothered to match against the exact codes that are output.

  3. This code assumes that the command will stop right away after outputting a prompt and waits there. This seems to be a safe assumption.

  4. It also assumes that the prompt text cannot appear as something which is not a prompt. Whether this is safe depends on your specific scenario.

The ./command.js file I used to simulate the command being run is:

#!/usr/bin/env node

var prompt = require("prompt");

function ask(cb) {
    prompt.get(["Is it okay (yes)?"], function (err, result) {
        console.log("asked");
        cb();
    });
}

setTimeout(function () {
    ask(function () {
        setTimeout(function () {
            ask(function () { process.exit(0); });
        }, 1000);
    });
}, 5000);

It waits 5s, prompts once, waits 1s, prompts a second time and exits.

Louis
  • 146,715
  • 28
  • 274
  • 320