savory
Version:
A command-line interface for operating your Codefresh account
114 lines (108 loc) • 5.3 kB
JavaScript
const
fp = require('lodash/fp'),
fs = require('fs'),
os = require('os'),
path = require('path'),
yargs = require('yargs'),
chalk = require('chalk'),
assert = require('assert'),
{ randomString } = require('../lib/util'),
httpClientFactory = require('../lib/api_client');
const
DEFAULT_CONFIGURATION_FILENAME = ".savory",
DEFAULT_CONFIGURATION_PATH = path.join(os.homedir(), DEFAULT_CONFIGURATION_FILENAME),
DEFAULT_API_ENDPOINT_URL = "https://g.codefresh.io/";
const
selfFileName = path.basename(process.argv.slice(1,2).join('')),
validateApiKey = (apiKey)=> /^[0-9a-f]{24}\.[0-9a-f]{32}$/.test(apiKey),
validateApiEndpointUrl = (apiEndpointUrl)=> /^https?:\/\/[^\/]+\/$/.test(apiEndpointUrl),
parseFileConfiguration = (configurationFilePath)=> {
let configurationJson = fp.attempt(()=> JSON.parse(fs.readFileSync(configurationFilePath, 'utf8')));
assert(!fp.isError(configurationJson), `Failed to parse the configuration file at ${configurationFilePath}`);
let activeContext = fp.get('active_context', configurationJson);
assert(activeContext, `The configuration file at ${configurationFilePath} doesn't contain a valid active context`);
assert(fp.has(["context", activeContext], configurationJson), `Context "${activeContext}" doesn't exist in the configuration at ${configurationFilePath}`);
return fp.mapKeys(fp.camelCase, fp.get(["context", activeContext], configurationJson));
};
let argv = yargs
.strict(true)
.version()
.config()
.wrap(100)
.usage(`${chalk.green('Savory')} is a command-line interface for operating your Codefresh account`)
.option('config', {
default: [DEFAULT_CONFIGURATION_PATH].find(fs.existsSync),
describe: "Use a custom configuration file",
config: true,
configParser: parseFileConfiguration
})
.option('api-key', {
describe: "Sets the API key to be used when contacting Codefresh's API",
required: `Please specify an API key, or run "${ chalk.whiteBright([selfFileName].concat('login <your-api-key>').join(' '))}".\nTo obtain an API key, refer to "https://g.codefresh.io/account-admin/tokens"`,
global: true,
coerce: (apiKey)=> {
assert(validateApiKey(apiKey), 'The API key used is invalid');
return apiKey;
}
})
.option('api-endpoint-url', {
describe: "Sets the URL of Codefresh's API",
default: DEFAULT_API_ENDPOINT_URL,
required: true,
global: true,
coerce: (apiEndpointUrl)=> {
assert(validateApiEndpointUrl(apiEndpointUrl), `The API endpoint address (${apiEndpointUrl}) used is invalid`);
return apiEndpointUrl;
}
})
.command(
'login <api-key>',
'Sets a default login context',
(argv)=> {
return argv
.positional('api-key', {
coerce: (apiKey)=> {
assert(validateApiKey(apiKey), 'The API key used is invalid');
return apiKey;
}
})
.example('$0 login 123456789012345678901234.12345678901234567890123456789012');
},
({ apiEndpointUrl, apiKey })=> {
let client = httpClientFactory(apiEndpointUrl, apiKey);
client('user/context')
.then((response)=> {
if(response === "OK"){
let
configurationJson = (function(maybe){ return fp.isError(maybe) ? {} : maybe; })(fp.attempt(()=> JSON.parse(fs.readFileSync(DEFAULT_CONFIGURATION_PATH, 'utf8')))),
context = {
"api_endpoint_url": apiEndpointUrl,
"api_key": apiKey
},
contextName = fp.findKey(fp.equals(context), configurationJson["context"]) || ["login", randomString()].join('_');
fs.writeFileSync(DEFAULT_CONFIGURATION_PATH, JSON.stringify(fp.merge(configurationJson, { "active_context": contextName, "context": { [contextName]: context } }), null, '\t'));
console.log([
chalk.whiteBright(`You've successfully logged-in!`),
"Try running commands such as:\n",
` ${selfFileName} builds ls --status running success`,
` ${selfFileName} images ls --external`,
""
].join('\n'));
} else {
return Promise.reject('The API key used is invalid');
}
})
.catch(console.warn);
}
)
.command(require('./command/builds'))
.command(require('./command/images'))
.command(require('./command/compositions'))
.command(require('./command/triggers'))
.command(require('./command/contexts'))
.command(require('./command/browse'))
.command(require('./command/pipelines'))
.command(require('./command/version'))
.demandCommand(1, 'Please choose one of the commands above')
.argv;