Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,15 @@
*.tgz
node_modules
test/.test_artifacts
intl/MSG.json
intl/de
intl/es
intl/fr
intl/it
intl/ja
intl/ko
intl/pt
intl/ru
intl/zh-Hans
intl/zh-Hant
intl/en/*.json
33 changes: 18 additions & 15 deletions bin/sl-deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,23 @@
var Parser = require('posix-getopt').BasicParser;
var debug = require('debug')('strong-deploy');
var defaults = require('strong-url-defaults');
var getPackageInfo = require('../lib/package').getPackageInfo;
var defaultPackagePath = require('../lib/package').getPackagePath;
var deploy = require('../');
var fs = require('fs');
var g = require('strong-globalize');
var getPackageInfo = require('../lib/package').getPackageInfo;
var maybeTunnel = require('strong-tunnel');
var path = require('path');

function printHelp($0, prn) {
var USAGE = fs.readFileSync(require.resolve('./sl-deploy.txt'), 'utf-8')
.replace(/%MAIN%/g, $0)
.trim();

var USAGE = g.t('sl-deploy.txt')
.replace(/%MAIN%/g, $0).
trim();
prn(USAGE);
}

g.setRootDir(path.resolve(__dirname, '..'));

var argv = process.argv;
var $0 = process.env.CMD ? process.env.CMD : path.basename(argv[1]);
var parser = new Parser([
Expand Down Expand Up @@ -56,7 +58,7 @@ while ((option = parser.getopt()) !== undefined) {
local = true;
break;
default:
console.error('Invalid usage (near option \'%s\'), try `%s --help`.',
g.error('Invalid usage (near option \'%s\'), try {{`%s --help`}}.',
option.optopt,
$0);
process.exit(1);
Expand All @@ -65,7 +67,7 @@ while ((option = parser.getopt()) !== undefined) {

var numArgs = argv.length - parser.optind();
if (numArgs > 2) {
console.error('Invalid usage, try `%s --help`.', $0);
g.error('Invalid usage, try {{`%s --help`}}.', $0);
process.exit(1);
}

Expand All @@ -78,11 +80,12 @@ var packageInfo = getPackageInfo(workingDir);
serviceName = serviceName || (packageInfo ? packageInfo.name : null);

if (!serviceName) {
console.error(
'Unable to detect service name, package.json has no "name" property.\n' +
'Please update your package.json or specify a service name.\n' +
'See `%s --help` for more details.', $0
);
g.error(
'Unable to detect service name, {{package.json}} ' +
'has no "{{name}}" property.\n' +
'Please update your {{package.json}} or specify a service name.\n' +
'See {{`%s --help`}} for more details.', $0
);
process.exit(1);
}

Expand Down Expand Up @@ -118,7 +121,7 @@ if (!local) {
maybeTunnel(baseURL, sshOpts, function(err, url) {
exit.url = url;
if (err) {
console.error('Error setting up tunnel:', err);
g.error('Error setting up tunnel: %s', err);
return exit(err);
}
debug('Connecting to %s via %s', baseURL, url);
Expand All @@ -144,11 +147,11 @@ if (!local) {
function exit(err, service) {
var svc = service ? (service.name || service.id) : serviceName;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am trying to find the globalize docs for this { key}, {key: value} syntax, where are they?

Some tools do:

glb.error('this {$1} is a {$2}, 'statue', 'dog')... basically keys prefixed with a$` are positional args. its more concise for some uses. Does globalize support this? If not, maybe we can suggest it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strong-globalize supports both glb.error('this {0} is a {1}, ['statue', 'dog']) and glb.error('this {statue} is a {dog}, {statue: 'statue', dog: 'dog'}). i don't think we want to advertise the former notation, do we?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not? Its way more concise, and its concision makes it less error prone to use, particularly when converting from code that already uses positional args. Note the error you made at #54 (comment). Its easy to do that kind of thing, and its particularly bad because there are _three_ identical strings that must be identical, or the code is broken, and made worse because unit tests to cover this kind of thing are hard to build. The above is an error case, and we often don't test the exact message output from CLIs, particularly for errors, the tests are hard to build and fragile, but the effect is bugs like the above are easy to miss, and easy to create during what is a rote, bulk translation exercise.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opened the gate in strong=globalize/lint for {0}, {1}, .. placeholder names.

var dt = glb.d(new Date());
"{dateTime} Hello World"
glb.t('{dateTime} Hello World', {dateTime: dt});

"{0} Hello World"
glb.t('{0} Hello World', {0: dt});

"{0} Hello World"
glb.t('{0} Hello World', [dt]);

They are all supported. I think the former gives more context to the human translator. No difference for machines.

if (err) {
console.error('Failed to deploy `%s` as `%s` to `%s` via `%s`',
g.error('Failed to deploy `%s` as `%s` to `%s` via `%s`',
branchOrPack, svc, baseURL, exit.url);
process.exit(1);
} else {
console.log('Deployed `%s` as `%s` to `%s`', branchOrPack, svc, baseURL);
g.log('Deployed `%s` as `%s` to `%s`', branchOrPack, svc, baseURL);
process.exit(0);
}
}
64 changes: 0 additions & 64 deletions bin/sl-deploy.txt

This file was deleted.

50 changes: 50 additions & 0 deletions intl/en/sl-deploy.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
usage: {{%MAIN% [options] [URL [PACK|BRANCH]]}}

Deploy a node application to a StrongLoop process manager

Options:
{{-h,--help}} Print this message and exit.
{{-v,--version}} Print version and exit.
{{-s,--service SVC}} Deploy to service {{SVC}}.
{{-z,--size SIZE}} Set size of cluster to {{SIZE}} before deploy.

Arguments:
{{SIZE}}: A number, n, or the string '{{cpus}}', meaning run a worker per CPU.

{{SVC}}: The name or ID of the service on the process manager.

Defaults to the name of the application specified in the {{package.json}} file.

If a service with that name is not available on the process manager, a new service will be created and the application will be deployed.

{{URL}}: The {{URL}} of the StrongLoop process manager.

Defaults to `{{http://localhost:8701}}`. If a {{URL}} is provided, both the host and port is optional, they default to `{{localhost}}` and 8701, respectively. If the server requires authentication, the credentials must be part of the URL, see examples.

URL may also use the `{{http+ssh://}}` protocol which will connect using {{ssh}} and then tunnel the http requests over that connection. The {{ssh username}} will default to your current user and authentication defaults to using your current {{ssh-agent}}. The {{username}} can be overridden by setting an `{{SSH_USER}}` environment variable. The authentication can be overridden to use an existing private key instead of an agent by setting the `{{SSH_KEY}}` environment variable to the path of the private key to be used. The port used for ssh can be overridden by setting an `{{SSH_PORT}}` environment ariable.

{{PACK}}: Deploy an {{NPM package/tarball}}.

{{BRANCH}}: Deploy a {{git}} branch.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git did, so npm does need protection

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure


Default behaviour is to deploy to `{{http://localhost:8701}}`. An {{npm}} package from the parent directory is deployed, if one is found for the current application version, otherwise the {{git}} branch `{{deploy}}` is deployed.

Note that if {{PACK}} or {{BRANCH}} is specified, {{URL}} *must* be specified as well.

Examples:

Deploy the default {{npm}} package or {{git}} branch to {{localhost}}:

{{%MAIN%}}

Deploy the default {{npm}} package or {{git}} branch to a remote host:

{{%MAIN% http://prod1.example.com}}

Deploy to a remote host, on a non-standard port, using authentication:

{{%MAIN% http://user:pass@prod1.example.com:8765}}

Deploy '{{production}}' branch to {{localhost}}:

{{%MAIN% http://localhost production}}
7 changes: 4 additions & 3 deletions lib/deploy-endpoint.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

var MeshClient = require('strong-mesh-models').Client;
var debug = require('debug')('strong-deploy');
var g = require('strong-globalize');

exports.get = getDeployEndpoint;

function getDeployEndpoint(url, serviceName, clusterSize, callback) {
var client = new MeshClient(url);
client.checkRemoteApiSemver(function(err) {
if (err) {
console.error('Failed to connect to %s: %s',
g.error('Failed to connect to %s: %s',
url, err.message || err);
return callback(err);
}
Expand All @@ -22,11 +23,11 @@ function serviceFindOrCreate(client, serviceName, clusterSize, callback) {
if (err) {
debug('client.serviceFindOrCreate(%s, 1): %s', serviceName, err);
if (err.statusCode === 401) {
console.error(
g.error(
'Cannot access remote. If authentication is required,' +
' credentials should be given in the URL.');
} else {
console.error('Error connecting to server:', err);
g.error('Error connecting to server: %s', err);
}
return callback(err);
}
Expand Down
16 changes: 9 additions & 7 deletions lib/git.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ var async = require('async');
var childProcess = require('child_process');
var debug = require('debug')('strong-deploy:git');
var getDeployEndpoint = require('./deploy-endpoint').get;
var g = require('strong-globalize');
var shell = require('shelljs');
var util = require('util');
var urlParse = require('url').parse;
var urlFormat = require('url').format;

function getCurrentBranch(workingDir) {
if (!shell.pushd(workingDir)) {
return Error(util.format('Directory %s does not exist', workingDir));
return g.Error('Directory %s does not exist', workingDir);
}
var output = shell.exec('git symbolic-ref --short HEAD', {silent: true});
shell.popd();
if (output.code !== 0) {
return Error('This directory does not contain a valid git repository');
return g.Error(
'This directory does not contain a valid {{git}} repository');
}
return output.output.trim();
}
Expand All @@ -28,9 +30,9 @@ function isValidBranch(workingDir, branchName, callback) {
debug('stderr: ' + stderr);
if (err) {
debug(err);
console.error('Branch `%s` is not available in this repository',
g.error('Branch `%s` is not available in this repository',
branchName);
err = Error('invalid branch');
err = g.Error('invalid branch');
}
callback(err);
});
Expand All @@ -46,9 +48,9 @@ function isValidGitURL(workingDir, url, callback) {
if (err) {
debug(err);
if (urlFormat(urlParse(url)) !== url) {
console.error('URL `%s` is not valid', url);
g.error('{{URL}} `%s` is not valid', url);
}
err = Error('invalid url');
err = g.Error('invalid url');
}
callback(err);
});
Expand All @@ -73,7 +75,7 @@ function doGitPush(workingDir, gitURL, branch, callback) {
child.once('exit', function(code) {
if (!callback) return;

if (code !== 0) return callback(Error('git push failed'));
if (code !== 0) return callback(g.Error('{{git push}} failed'));
callback();
callback = null;
});
Expand Down
17 changes: 9 additions & 8 deletions lib/post-json.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var concat = require('concat-stream');
var debug = require('debug')('strong-deploy');
var getDeployEndpoint = require('./deploy-endpoint').get;
var g = require('strong-globalize');
var http = require('http');
var path = require('path');
var shell = require('shelljs');
Expand All @@ -22,23 +23,23 @@ function _performLocalDeployment(service, baseURL, what, callback) {

var postURL = url.parse(baseURL);
if (postURL.protocol !== 'http:') {
console.error('Invalid URL `%s`. Only http:// URLs are supported.',
g.error('Invalid {{URL}} `%s`. Only {{http:// URLs}} are supported.',
baseURL
);
return callback(Error('Invalid URL'));
return callback(g.Error('Invalid {{URL}}'));
}

if (postURL.hostname) {
if (postURL.hostname !== 'localhost' && postURL.hostname !== '127.0.0.1') {
console.error('Invalid URL `%s`. Only localhost URLs are supported.',
g.error('Invalid {{URL}} `%s`. Only {{localhost}} URLs are supported.',
baseURL);
return callback(Error('Invalid URL'));
return callback(g.Error('Invalid {{URL}}'));
}
}

if (!shell.test('-d', what)) {
console.error('Cannot deploy `%s`: not an npm package directory', what);
return callback(Error('Invalid path, not a directory'));
g.error('Cannot deploy `%s`: not an {{npm}} package directory', what);
return callback(g.Error('Invalid path, not a directory'));
}

var postOptions = {
Expand All @@ -64,14 +65,14 @@ function _performLocalDeployment(service, baseURL, what, callback) {
return callback(null, service);
}
console.error('%s', msg);
callback(Error('HTTP error ' + res.statusCode));
callback(g.Error('{{HTTP}} error %s', res.statusCode));
}));
});

req.end(JSON.stringify(postBody));

req.on('error', function(err) {
console.error('Deploy `%s` to `%s` failed: %s',
g.error('Deploy `%s` to `%s` failed: %s',
what,
baseURL,
err.message
Expand Down
Loading