@appsonair/codepush-cli
Version:
Management CLI for the Appsonair CodePush service
1,031 lines (1,030 loc) • 55.9 kB
JavaScript
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.createCommand = exports.showHelp = void 0;
const yargs = require("yargs");
const cli = require("../script/types/cli");
const chalk = require("chalk");
const backslash = require("backslash");
const parseDuration = require("parse-duration");
const packageJson = require("../../package.json");
const ROLLOUT_PERCENTAGE_REGEX = /^(100|[1-9][0-9]|[1-9])%?$/;
const USAGE_PREFIX = "Usage: appsonair-codepush";
// Command categories are: access-key, app, release, deployment, deployment-key, login, logout, register
let isValidCommandCategory = false;
// Commands are the verb following the command category (e.g.: "add" in "app add").
let isValidCommand = false;
let wasHelpShown = false;
function showHelp(showRootDescription) {
if (!wasHelpShown) {
if (showRootDescription) {
console.log(chalk.cyan(" _ ____ ____ ____") +
chalk.green(" ___ _ _ ") +
chalk.cyan(" _ ____ ____ ") +
chalk.green(" ____ ___ ____ _____") +
chalk.cyan(" ____ _ _ ____ _ _ "));
console.log(chalk.cyan(" / \\ | _ \\| _ \\ //") +
chalk.green(" / _ \\| \\ | |") +
chalk.cyan(" / \\ |_ _| _ \\ ") +
chalk.green(" / ___| / _ \\ | _ \\ | ____|") +
chalk.cyan("| _ \\ | | | | // | | | | "));
console.log(chalk.cyan(" / _ \\ | |_) | |_) ||___ ") +
chalk.green("| | | || \\| |") +
chalk.cyan(" / _ \\ || | |_) |") +
chalk.green("| | | | | || | | || _| ") +
chalk.cyan("| |_) || | | |||___ | |_| | "));
console.log(chalk.cyan(" / ___ \\| __/| __/ \\") +
chalk.green("| |_| || . |") +
chalk.cyan(" / ___ \\ ||_| __/ ") +
chalk.green("| |___ | |_| || |_| || |___ ") +
chalk.cyan("| __/ | |_| | \\| | | | "));
console.log(chalk.cyan("/_/ \\_\\_| |_| ___//") +
chalk.green(" \\___/|_|\\_\\|") +
chalk.cyan("/_/ \\_\\|___|_|\\_|") +
chalk.green(" \\____| \\___/ |____/ |_____|") +
chalk.cyan("|_| \\___/ ___//|_| |_| ")
+ " CLI v" + packageJson.version);
console.log(chalk.cyan("=================================================================================================================="));
console.log("");
console.log("AppsOnAirCodePush is a service that enables you to deploy mobile app updates directly to your users' devices.\n");
}
yargs.showHelp();
wasHelpShown = true;
}
}
exports.showHelp = showHelp;
function accessKeyAdd(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " access-key " + commandName + " <accessKeyName>")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly one non-option arguments
.example("access-key " + commandName + ' "VSTS Integration"', 'Creates a new access key with the name "VSTS Integration", which expires in 60 days')
.example("access-key " + commandName + ' "One time key" --ttl 5m', 'Creates a new access key with the name "One time key", which expires in 5 minutes')
.option("ttl", {
default: "60d",
demand: false,
description: "Duration string which specifies the amount of time that the access key should remain valid for (e.g 5m, 60d, 1y)",
type: "string",
});
addCommonConfiguration(yargs);
}
function accessKeyPatch(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " access-key " + commandName + " <accessKeyName>")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly one non-option arguments
.example("access-key " + commandName + ' "Key for build server" --name "Key for CI machine"', 'Renames the access key named "Key for build server" to "Key for CI machine"')
.example("access-key " + commandName + ' "Key for build server" --ttl 7d', 'Updates the access key named "Key for build server" to expire in 7 days')
.option("name", {
default: null,
demand: false,
description: "Display name for the access key",
type: "string",
})
.option("ttl", {
default: null,
demand: false,
description: "Duration string which specifies the amount of time that the access key should remain valid for (e.g 5m, 60d, 1y)",
type: "string",
});
addCommonConfiguration(yargs);
}
function accessKeyList(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " access-key " + commandName + " [options]")
.demand(/*count*/ 0, /*max*/ 0)
.example("access-key " + commandName, "Lists your access keys in tabular format")
.example("access-key " + commandName + " --format json", "Lists your access keys in JSON format")
.option("format", {
default: "table",
demand: false,
description: 'Output format to display your access keys with ("json" or "table")',
type: "string",
});
addCommonConfiguration(yargs);
}
function accessKeyRemove(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " access-key " + commandName + " <accessKeyName>")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly one non-option arguments
.example("access-key " + commandName + ' "VSTS Integration"', 'Removes the "VSTS Integration" access key');
addCommonConfiguration(yargs);
}
function addCommonConfiguration(yargs) {
yargs
.wrap(/*columnLimit*/ null)
.string("_") // Interpret non-hyphenated arguments as strings (e.g. an app version of '1.10').
.fail((msg) => showHelp()); // Suppress the default error message.
}
function appList(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " app " + commandName + " [options]")
.demand(/*count*/ 0, /*max*/ 0)
.example("app " + commandName, "List your apps in tabular format")
.example("app " + commandName + " --format json", "List your apps in JSON format")
.option("format", {
default: "table",
demand: false,
description: 'Output format to display your apps with ("json" or "table")',
type: "string",
});
addCommonConfiguration(yargs);
}
function appRemove(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " app " + commandName + " <appName>")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly one non-option arguments
.example("app " + commandName + " MyApp", 'Removes app "MyApp"');
addCommonConfiguration(yargs);
}
function listCollaborators(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " collaborator " + commandName + " <appName> [options]")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly one non-option arguments
.example("collaborator " + commandName + " MyApp", 'Lists the collaborators for app "MyApp" in tabular format')
.example("collaborator " + commandName + " MyApp --format json", 'Lists the collaborators for app "MyApp" in JSON format')
.option("format", {
default: "table",
demand: false,
description: 'Output format to display collaborators with ("json" or "table")',
type: "string",
});
addCommonConfiguration(yargs);
}
function removeCollaborator(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " collaborator " + commandName + " <appName> <email>")
.demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments
.example("collaborator " + commandName + " MyApp foo@bar.com", 'Removes foo@bar.com as a collaborator from app "MyApp"');
addCommonConfiguration(yargs);
}
function sessionList(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " session " + commandName + " [options]")
.demand(/*count*/ 0, /*max*/ 0)
.example("session " + commandName, "Lists your sessions in tabular format")
.example("session " + commandName + " --format json", "Lists your login sessions in JSON format")
.option("format", {
default: "table",
demand: false,
description: 'Output format to display your login sessions with ("json" or "table")',
type: "string",
});
addCommonConfiguration(yargs);
}
function sessionRemove(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " session " + commandName + " <machineName>")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly one non-option arguments
.example("session " + commandName + ' "John\'s PC"', 'Removes the existing login session from "John\'s PC"');
addCommonConfiguration(yargs);
}
function deploymentHistoryClear(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " deployment " + commandName + " <appName> <deploymentName>")
.demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments
.example("deployment " + commandName + " MyApp MyDeployment", 'Clears the release history associated with deployment "MyDeployment" from app "MyApp"');
addCommonConfiguration(yargs);
}
function deploymentList(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " deployment " + commandName + " <appName> [options]")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly one non-option arguments
.example("deployment " + commandName + " MyApp", 'Lists the deployments for app "MyApp" in tabular format')
.example("deployment " + commandName + " MyApp --format json", 'Lists the deployments for app "MyApp" in JSON format')
.option("format", {
default: "table",
demand: false,
description: 'Output format to display your deployments with ("json" or "table")',
type: "string",
})
.option("displayKeys", {
alias: "k",
default: false,
demand: false,
description: "Specifies whether to display the deployment keys",
type: "boolean",
});
addCommonConfiguration(yargs);
}
function deploymentRemove(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " deployment " + commandName + " <appName> <deploymentName>")
.demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments
.example("deployment " + commandName + " MyApp MyDeployment", 'Removes deployment "MyDeployment" from app "MyApp"');
addCommonConfiguration(yargs);
}
function deploymentHistory(commandName, yargs) {
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " deployment " + commandName + " <appName> [options]")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly two non-option arguments
.example("deployment " + commandName + " MyApp", 'Displays the release history for deployment "Production" from app "MyApp" in tabular format')
.example("deployment " + commandName + " MyApp --format json", 'Displays the release history for deployment "Production" from app "MyApp" in JSON format')
.option("format", {
default: "table",
demand: false,
description: 'Output format to display the release history with ("json" or "table")',
type: "string",
})
.option("displayAuthor", {
alias: "a",
default: false,
demand: false,
description: "Specifies whether to display the release author",
type: "boolean",
});
addCommonConfiguration(yargs);
}
yargs
.usage(USAGE_PREFIX + " <command>")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly one non-option argument.
// .command("access-key", "View and manage the access keys associated with your account", (yargs: yargs.Argv) => {
// isValidCommandCategory = true;
// yargs
// .usage(USAGE_PREFIX + " access-key <command>")
// .demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments.
// .command("add", "Create a new access key associated with your account", (yargs: yargs.Argv) => accessKeyAdd("add", yargs))
// .command("patch", "Update the name and/or TTL of an existing access key", (yargs: yargs.Argv) => accessKeyPatch("patch", yargs))
// .command("remove", "Remove an existing access key", (yargs: yargs.Argv) => accessKeyRemove("remove", yargs))
// .command("rm", "Remove an existing access key", (yargs: yargs.Argv) => accessKeyRemove("rm", yargs))
// .command("list", "List the access keys associated with your account", (yargs: yargs.Argv) => accessKeyList("list", yargs))
// .command("ls", "List the access keys associated with your account", (yargs: yargs.Argv) => accessKeyList("ls", yargs))
// .check((argv: any, aliases: { [aliases: string]: string }): any => isValidCommand); // Report unrecognized, non-hyphenated command category.
// addCommonConfiguration(yargs);
// })
.command("app", "View and manage your AppsOnAirCodePush apps", (yargs) => {
isValidCommandCategory = true;
yargs
.usage(USAGE_PREFIX + " app <command>")
.demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments.
// .command("add", "Add a new app to your account", (yargs: yargs.Argv): void => {
// isValidCommand = true;
// yargs
// .usage(USAGE_PREFIX + " app add <appName>")
// .demand(/*count*/ 1, /*max*/ 1) // Require exactly one non-option arguments
// .example("app add MyApp", 'Adds app "MyApp"');
// addCommonConfiguration(yargs);
// })
// .command("remove", "Remove an app from your account", (yargs: yargs.Argv) => appRemove("remove", yargs))
// .command("rm", "Remove an app from your account", (yargs: yargs.Argv) => appRemove("rm", yargs))
// .command("rename", "Rename an existing app", (yargs: yargs.Argv) => {
// isValidCommand = true;
// yargs
// .usage(USAGE_PREFIX + " app rename <currentAppName> <newAppName>")
// .demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments
// .example("app rename CurrentName NewName", 'Renames app "CurrentName" to "NewName"');
// addCommonConfiguration(yargs);
// })
.command("list", "Lists the apps associated with your account", (yargs) => appList("list", yargs))
.command("ls", "Lists the apps associated with your account", (yargs) => appList("ls", yargs))
// .command("transfer", "Transfer the ownership of an app to another account", (yargs: yargs.Argv) => {
// isValidCommand = true;
// yargs
// .usage(USAGE_PREFIX + " app transfer <appName> <email>")
// .demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments
// .example("app transfer MyApp foo@bar.com", 'Transfers the ownership of app "MyApp" to an account with email "foo@bar.com"');
// addCommonConfiguration(yargs);
// })
.check((argv, aliases) => isValidCommand); // Report unrecognized, non-hyphenated command category.
addCommonConfiguration(yargs);
})
.command("collaborator", "View and manage app collaborators", (yargs) => {
isValidCommandCategory = true;
yargs
.usage(USAGE_PREFIX + " collaborator <command>")
.demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments.
// .command("add", "Add a new collaborator to an app", (yargs: yargs.Argv): void => {
// isValidCommand = true;
// yargs
// .usage(USAGE_PREFIX + " collaborator add <appName> <email>")
// .demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments
// .example("collaborator add MyApp foo@bar.com", 'Adds foo@bar.com as a collaborator to app "MyApp"');
// addCommonConfiguration(yargs);
// })
// .command("remove", "Remove a collaborator from an app", (yargs: yargs.Argv) => removeCollaborator("remove", yargs))
// .command("rm", "Remove a collaborator from an app", (yargs: yargs.Argv) => removeCollaborator("rm", yargs))
.command("list", "List the collaborators for an app", (yargs) => listCollaborators("list", yargs))
.command("ls", "List the collaborators for an app", (yargs) => listCollaborators("ls", yargs))
.check((argv, aliases) => isValidCommand); // Report unrecognized, non-hyphenated command category.
addCommonConfiguration(yargs);
})
.command("debug", "View the AppsOnAirCodePush debug logs for a running app", (yargs) => {
isValidCommandCategory = true;
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " debug <platform>")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly one non-option arguments
.example("debug android", "View the AppsOnAirCodePush debug logs for an Android emulator or device")
.example("debug ios", "View the AppsOnAirCodePush debug logs for the iOS simulator");
addCommonConfiguration(yargs);
})
.command("deployment", "View and manage your app deployments", (yargs) => {
isValidCommandCategory = true;
yargs
.usage(USAGE_PREFIX + " deployment <command>")
.demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments.
// .command("add", "Add a new deployment to an app", (yargs: yargs.Argv): void => {
// isValidCommand = true;
// yargs
// .usage(USAGE_PREFIX + " deployment add <appName> <deploymentName>")
// .demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments
// .example("deployment add MyApp MyDeployment", 'Adds deployment "MyDeployment" to app "MyApp"')
// .example("deployment add MyApp MyDeployment -k abc123", 'Adds deployment key "abc123"')
// .option("key", {
// alias: "k",
// demand: false,
// description: "Specify deployment key",
// type: "string",
// });
// addCommonConfiguration(yargs);
// })
// .command("clear", "Clear the release history associated with a deployment", (yargs: yargs.Argv) =>
// deploymentHistoryClear("clear", yargs)
// )
// .command("remove", "Remove a deployment from an app", (yargs: yargs.Argv) => deploymentRemove("remove", yargs))
// .command("rm", "Remove a deployment from an app", (yargs: yargs.Argv) => deploymentRemove("rm", yargs))
// .command("rename", "Rename an existing deployment", (yargs: yargs.Argv) => {
// isValidCommand = true;
// yargs
// .usage(USAGE_PREFIX + " deployment rename <appName> <currentDeploymentName> <newDeploymentName>")
// .demand(/*count*/ 3, /*max*/ 3) // Require exactly three non-option arguments
// .example(
// "deployment rename MyApp CurrentDeploymentName NewDeploymentName",
// 'Renames deployment "CurrentDeploymentName" to "NewDeploymentName"'
// );
// addCommonConfiguration(yargs);
// })
.command("list", "List the deployments associated with an app", (yargs) => deploymentList("list", yargs))
.command("ls", "List the deployments associated with an app", (yargs) => deploymentList("ls", yargs))
.command("history", "Display the release history for a deployment", (yargs) => deploymentHistory("history", yargs))
.command("h", "Display the release history for a deployment", (yargs) => deploymentHistory("h", yargs))
.check((argv, aliases) => isValidCommand); // Report unrecognized, non-hyphenated command category.
addCommonConfiguration(yargs);
})
// .command("link", "Link an additional authentication provider (e.g. GitHub) to an existing AppsOnAirCodePush account", (yargs: yargs.Argv) => {
// isValidCommandCategory = true;
// isValidCommand = true;
// yargs
// .usage(USAGE_PREFIX + " link")
// .demand(/*count*/ 0, /*max*/ 1) //set 'max' to one to allow usage of serverUrl undocument parameter for testing
// .example("link", "Links an account on the AppsOnAirCodePush server")
// .check((argv: any, aliases: { [aliases: string]: string }): any => isValidCommand); // Report unrecognized, non-hyphenated command category.
// addCommonConfiguration(yargs);
// })
.command("login", "Authenticate with the AppsOnAirCodePush server in order to begin managing your apps", (yargs) => {
isValidCommandCategory = true;
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " login [options]")
.demand(/*count*/ 0, /*max*/ 1) //set 'max' to one to allow usage of serverUrl undocument parameter for testing
.example("login", "Logs in to the AppsOnAirCodePush server")
.example("login --accessKey mykey", 'Logs in on behalf of the user who owns and created the access key "mykey"')
.option("accessKey", {
alias: "key",
default: null,
demand: false,
description: "Access key to authenticate against the AppsOnAirCodePush server with, instead of providing your username and password credentials",
type: "string",
})
.check((argv, aliases) => isValidCommand); // Report unrecognized, non-hyphenated command category.
addCommonConfiguration(yargs);
})
.command("logout", "Log out of the current session", (yargs) => {
isValidCommandCategory = true;
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " logout")
.demand(/*count*/ 0, /*max*/ 0)
.example("logout", "Logs out and ends your current session");
addCommonConfiguration(yargs);
})
.command("patch", "Update the metadata for an existing release", (yargs) => {
yargs
.usage(USAGE_PREFIX + " patch <appName> [options]")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly two non-option arguments
.example('patch MyApp Production --des "Updated description" -r 50%', 'Updates the description of the latest release for "MyApp" app\'s "Production" deployment and updates the rollout value to 50%')
.example('patch MyApp Production -l v3 --des "Updated description for v3"', 'Updates the description of the release with label v3 for "MyApp" app\'s "Production" deployment')
.option("label", {
alias: "l",
default: null,
demand: false,
description: "Label of the release to update. Defaults to the latest release within the specified deployment",
type: "string",
})
.option("description", {
alias: "des",
default: null,
demand: false,
description: "Description of the changes made to the app with this release",
type: "string",
})
.option("disabled", {
alias: "x",
default: null,
demand: false,
description: "Specifies whether this release should be immediately downloadable",
type: "boolean",
})
.option("mandatory", {
alias: "m",
default: null,
demand: false,
description: "Specifies whether this release should be considered mandatory",
type: "boolean",
})
.option("rollout", {
alias: "r",
default: null,
demand: false,
description: "Percentage of users this release should be immediately available to. This attribute can only be increased from the current value.",
type: "string",
})
.option("targetBinaryVersion", {
alias: "t",
default: null,
demand: false,
description: "Semver expression that specifies the binary app version(s) this release is targeting (e.g. 1.1.0, ~1.2.3).",
type: "string",
})
.check((argv, aliases) => {
return isValidRollout(argv);
});
addCommonConfiguration(yargs);
})
// .command("promote", "Promote the latest release from one app deployment to another", (yargs: yargs.Argv) => {
// yargs
// .usage(USAGE_PREFIX + " promote <appName> <sourceDeploymentName> <destDeploymentName> [options]")
// .demand(/*count*/ 3, /*max*/ 3) // Require exactly three non-option arguments
// .example(
// "promote MyApp Staging Production",
// 'Promotes the latest release within the "Staging" deployment of "MyApp" to "Production"'
// )
// .example(
// 'promote MyApp Staging Production --des "Production rollout" -r 25',
// 'Promotes the latest release within the "Staging" deployment of "MyApp" to "Production", with an updated description, and targeting only 25% of the users'
// )
// .option("description", {
// alias: "des",
// default: null,
// demand: false,
// description:
// "Description of the changes made to the app with this release. If omitted, the description from the release being promoted will be used.",
// type: "string",
// })
// .option("label", {
// alias: "l",
// default: null,
// demand: false,
// description: "Label of the source release that will be taken. If omitted, the latest release being promoted will be used.",
// type: "string",
// })
// .option("disabled", {
// alias: "x",
// default: null,
// demand: false,
// description:
// "Specifies whether this release should be immediately downloadable. If omitted, the disabled attribute from the release being promoted will be used.",
// type: "boolean",
// })
// .option("mandatory", {
// alias: "m",
// default: null,
// demand: false,
// description:
// "Specifies whether this release should be considered mandatory. If omitted, the mandatory property from the release being promoted will be used.",
// type: "boolean",
// })
// .option("noDuplicateReleaseError", {
// default: false,
// demand: false,
// description:
// "When this flag is set, promoting a package that is identical to the latest release on the target deployment will produce a warning instead of an error",
// type: "boolean",
// })
// .option("rollout", {
// alias: "r",
// default: "100%",
// demand: false,
// description: "Percentage of users this update should be immediately available to",
// type: "string",
// })
// .option("targetBinaryVersion", {
// alias: "t",
// default: null,
// demand: false,
// description:
// "Semver expression that specifies the binary app version(s) this release is targeting (e.g. 1.1.0, ~1.2.3). If omitted, the target binary version property from the release being promoted will be used.",
// type: "string",
// })
// .check((argv: any, aliases: { [aliases: string]: string }): any => {
// return isValidRollout(argv);
// });
// addCommonConfiguration(yargs);
// })
.command("register", "Register a new AppsOnAirCodePush account", (yargs) => {
isValidCommandCategory = true;
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " register")
.demand(/*count*/ 0, /*max*/ 1) //set 'max' to one to allow usage of serverUrl undocument parameter for testing
.example("register", "Registers a new AppsOnAirCodePush account")
.check((argv, aliases) => isValidCommand); // Report unrecognized, non-hyphenated command category.
addCommonConfiguration(yargs);
})
.command("release", "Release an update to an app deployment", (yargs) => {
yargs
.usage(USAGE_PREFIX + " release <appName> <updateContentsPath> <targetBinaryVersion> [options]")
.demand(/*count*/ 3, /*max*/ 3) // Require exactly three non-option arguments.
.example('release MyApp app.js "*"', 'Releases the "app.js" file to the "MyApp" app\'s "Production" deployment, targeting any binary version using the "*" wildcard range syntax.')
.example("release MyApp ./platforms/ios/www 1.0.3 -d Production", 'Releases the "./platforms/ios/www" folder and all its contents to the "MyApp" app\'s "Production" deployment, targeting only the 1.0.3 binary version')
.example("release MyApp ./platforms/ios/www 1.0.3 -d Production -r 20", 'Releases the "./platforms/ios/www" folder and all its contents to the "MyApp" app\'s "Production" deployment, targeting the 1.0.3 binary version and rolling out to about 20% of the users')
.option("deploymentName", {
alias: "d",
default: "Production",
demand: false,
description: "Deployment to release the update to",
type: "string",
})
.option("description", {
alias: "des",
default: null,
demand: false,
description: "Description of the changes made to the app in this release",
type: "string",
})
.option("disabled", {
alias: "x",
default: false,
demand: false,
description: "Specifies whether this release should be immediately downloadable",
type: "boolean",
})
.option("mandatory", {
alias: "m",
default: false,
demand: false,
description: "Specifies whether this release should be considered mandatory",
type: "boolean",
})
.option("noDuplicateReleaseError", {
default: false,
demand: false,
description: "When this flag is set, releasing a package that is identical to the latest release will produce a warning instead of an error",
type: "boolean",
})
.option("rollout", {
alias: "r",
default: "100%",
demand: false,
description: "Percentage of users this release should be available to",
type: "string",
})
.check((argv, aliases) => {
return checkValidReleaseOptions(argv);
});
addCommonConfiguration(yargs);
})
.command("release-react", "Release a React Native update to an app deployment", (yargs) => {
yargs
.usage(USAGE_PREFIX + " release-react <appName> [options]")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly two non-option arguments
.example("release-react MyApp", 'Releases the React Native iOS project in the current working directory to the "MyApp" app\'s "Production" deployment')
.example("release-react MyApp", 'Releases the React Native Android project in the current working directory to the "MyApp" app\'s "Production" deployment')
// .example(
// "release-react MyApp windows --dev",
// 'Releases the development bundle of the React Native Windows project in the current working directory to the "MyApp" app\'s "Production" deployment'
// )
.option("bundleName", {
alias: "b",
default: null,
demand: false,
description: 'Name of the generated JS bundle file. If unspecified, the standard bundle name will be used, depending on the specified platform: "main.jsbundle" (iOS) or "index.android.bundle" (Android).',
type: "string",
})
.option("deploymentName", {
alias: "d",
default: "Production",
demand: false,
description: "Deployment to release the update to",
type: "string",
})
.option("description", {
alias: "des",
default: null,
demand: false,
description: "Description of the changes made to the app with this release",
type: "string",
})
.option("development", {
alias: "dev",
default: false,
demand: false,
description: "Specifies whether to generate a dev or release build",
type: "boolean",
})
.option("disabled", {
alias: "x",
default: false,
demand: false,
description: "Specifies whether this release should be immediately downloadable",
type: "boolean",
})
.option("entryFile", {
alias: "e",
default: null,
demand: false,
description: 'Path to the app\'s entry Javascript file. If omitted, "index.<platform>.js" and then "index.js" will be used (if they exist)',
type: "string",
})
.option("gradleFile", {
alias: "g",
default: null,
demand: false,
description: "Path to the gradle file which specifies the binary version you want to target this release at (android only).",
})
.option("mandatory", {
alias: "m",
default: false,
demand: false,
description: "Specifies whether this release should be considered mandatory",
type: "boolean",
})
.option("noDuplicateReleaseError", {
default: false,
demand: false,
description: "When this flag is set, releasing a package that is identical to the latest release will produce a warning instead of an error",
type: "boolean",
})
.option("plistFile", {
alias: "p",
default: null,
demand: false,
description: "Path to the plist file which specifies the binary version you want to target this release at (iOS only).",
})
.option("plistFilePrefix", {
alias: "pre",
default: null,
demand: false,
description: "Prefix to append to the file name when attempting to find your app's Info.plist file (iOS only).",
})
.option("rollout", {
alias: "r",
default: "100%",
demand: false,
description: "Percentage of users this release should be immediately available to",
type: "string",
})
.option("sourcemapOutput", {
alias: "s",
default: null,
demand: false,
description: "Path to where the sourcemap for the resulting bundle should be written. If omitted, a sourcemap will not be generated.",
type: "string",
})
.option("targetBinaryVersion", {
alias: "t",
default: null,
demand: false,
description: 'Semver expression that specifies the binary app version(s) this release is targeting (e.g. 1.1.0, ~1.2.3). If omitted, the release will target the exact version specified in the "Info.plist" (iOS) or "build.gradle" (Android).',
type: "string",
})
.option("outputDir", {
alias: "o",
default: null,
demand: false,
description: "Path to where the bundle and sourcemap should be written. If omitted, a bundle and sourcemap will not be written.",
type: "string",
})
.option("useHermes", {
alias: "h",
default: false,
demand: false,
description: "Enable hermes and bypass automatic checks",
type: "boolean",
})
.option("podFile", {
alias: "pod",
default: null,
demand: false,
description: "Path to the cocopods config file (iOS only).",
type: "string",
})
.option("extraHermesFlags", {
alias: "hf",
default: [],
demand: false,
description: "Flags that get passed to Hermes, JavaScript to bytecode compiler. Can be specified multiple times.",
type: "array",
})
.option("privateKeyPath", {
alias: "k",
default: null,
demand: false,
description: "Path to private key used for code signing.",
type: "string",
})
.option("xcodeProjectFile", {
alias: "xp",
default: null,
demand: false,
description: "Path to the Xcode project or project.pbxproj file",
type: "string",
})
.option("xcodeTargetName", {
alias: "xt",
default: undefined,
demand: false,
description: "Name of target (PBXNativeTarget) which specifies the binary version you want to target this release at (iOS only)",
type: "string",
})
.option("buildConfigurationName", {
alias: "c",
default: undefined,
demand: false,
description: "Name of build configuration which specifies the binary version you want to target this release at. For example, 'Debug' or 'Release' (iOS only)",
type: "string",
})
.check((argv, aliases) => {
return checkValidReleaseOptions(argv);
});
addCommonConfiguration(yargs);
})
.command("rollback", "Rollback the latest release for an app deployment", (yargs) => {
yargs
.usage(USAGE_PREFIX + " rollback <appName> [options]")
.demand(/*count*/ 1, /*max*/ 1) // Require exactly two non-option arguments
.example("rollback MyApp Production", 'Performs a rollback on the "Production" deployment of "MyApp"')
.example("rollback MyApp Production --targetRelease v4", 'Performs a rollback on the "Production" deployment of "MyApp" to the v4 release')
.option("targetRelease", {
alias: "r",
default: null,
demand: false,
description: "Label of the release to roll the specified deployment back to (e.g. v4). If omitted, the deployment will roll back to the previous release.",
type: "string",
});
addCommonConfiguration(yargs);
})
// .command("session", "View and manage the current login sessions associated with your account", (yargs: yargs.Argv) => {
// isValidCommandCategory = true;
// yargs
// .usage(USAGE_PREFIX + " session <command>")
// .demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments.
// .command("remove", "Remove an existing login session", (yargs: yargs.Argv) => sessionRemove("remove", yargs))
// .command("rm", "Remove an existing login session", (yargs: yargs.Argv) => sessionRemove("rm", yargs))
// .command("list", "List the current login sessions associated with your account", (yargs: yargs.Argv) =>
// sessionList("list", yargs)
// )
// .command("ls", "List the current login sessions associated with your account", (yargs: yargs.Argv) => sessionList("ls", yargs))
// .check((argv: any, aliases: { [aliases: string]: string }): any => isValidCommand); // Report unrecognized, non-hyphenated command category.
// addCommonConfiguration(yargs);
// })
.command("whoami", "Display the account info for the current login session", (yargs) => {
isValidCommandCategory = true;
isValidCommand = true;
yargs
.usage(USAGE_PREFIX + " whoami")
.demand(/*count*/ 0, /*max*/ 0)
.example("whoami", "Display the account info for the current login session");
addCommonConfiguration(yargs);
})
.alias("v", "version")
.version(packageJson.version)
.wrap(/*columnLimit*/ null)
.fail((msg) => showHelp(/*showRootDescription*/ true)).argv; // Suppress the default error message.
function createCommand() {
let cmd;
const argv = yargs.parseSync();
if (!wasHelpShown && argv._ && argv._.length > 0) {
// Create a command object
const arg0 = argv._[0];
const arg1 = argv._[1];
const arg2 = argv._[2];
const arg3 = argv._[3];
const arg4 = argv._[4];
switch (arg0) {
case "access-key":
switch (arg1) {
case "add":
if (arg2) {
cmd = { type: cli.CommandType.accessKeyAdd };
const accessKeyAddCmd = cmd;
accessKeyAddCmd.name = arg2;
const ttlOption = argv["ttl"];
if (isDefined(ttlOption)) {
accessKeyAddCmd.ttl = parseDurationMilliseconds(ttlOption);
}
}
break;
case "patch":
if (arg2) {
cmd = { type: cli.CommandType.accessKeyPatch };
const accessKeyPatchCmd = cmd;
accessKeyPatchCmd.oldName = arg2;
const newNameOption = argv["name"];
const ttlOption = argv["ttl"];
if (isDefined(newNameOption)) {
accessKeyPatchCmd.newName = newNameOption;
}
if (isDefined(ttlOption)) {
accessKeyPatchCmd.ttl = parseDurationMilliseconds(ttlOption);
}
}
break;
case "list":
case "ls":
cmd = { type: cli.CommandType.accessKeyList };
cmd.format = argv["format"];
break;
case "remove":
case "rm":
if (arg2) {
cmd = { type: cli.CommandType.accessKeyRemove };
cmd.accessKey = arg2;
}
break;
}
break;
case "app":
switch (arg1) {
case "add":
if (arg2) {
cmd = { type: cli.CommandType.appAdd };
cmd.appName = arg2;
}
break;
case "list":
case "ls":
cmd = { type: cli.CommandType.appList };
cmd.format = argv["format"];
break;
case "remove":
case "rm":
if (arg2) {
cmd = { type: cli.CommandType.appRemove };
cmd.appName = arg2;
}
break;
case "rename":
if (arg2 && arg3) {
cmd = { type: cli.CommandType.appRename };
const appRenameCommand = cmd;
appRenameCommand.currentAppName = arg2;
appRenameCommand.newAppName = arg3;
}
break;
case "transfer":
if (arg2 && arg3) {
cmd = { type: cli.CommandType.appTransfer };
const appTransferCommand = cmd;
appTransferCommand.appName = arg2;
appTransferCommand.email = arg3;
}
break;
}
break;
case "collaborator":
switch (arg1) {
case "add":
if (arg2 && arg3) {
cmd = { type: cli.CommandType.collaboratorAdd };
cmd.appName = arg2;
cmd.email = arg3;
}
break;
case "list":
case "ls":
if (arg2) {
cmd = { type: cli.CommandType.collaboratorList };
cmd.appName = arg2;
cmd.format = argv["format"];
}
break;
case "remove":
case "rm":
if (arg2 && arg3) {
cmd = { type: cli.CommandType.collaboratorRemove };
cmd.appName = arg2;
cmd.email = arg3;
}
break;
}
break;
case "debug":
cmd = {
type: cli.CommandType.debug,
platform: arg1,
};
break;
case "deployment":
switch (arg1) {
case "add":
if (arg2 && arg3) {
cmd = { type: cli.CommandType.deploymentAdd };
const deploymentAddCommand = cmd;
deploymentAddCommand.appName = arg2;
deploymentAddCommand.deploymentName = arg3;
if (argv["key"]) {
deploymentAddCommand.key = argv["key"];
}
}
break;
case "clear":
if (arg2 && arg3) {
cmd = { type: cli.CommandType.deploymentHistoryClear };
const deploymentHistoryClearCommand = cmd;
deploymentHistoryClearCommand.appName = arg2;
deploymentHistoryClearCommand.deploymentName = arg3;
}
break;
case "list":
case "ls":
if (arg2) {
cmd = { type: cli.CommandType.deploymentList };
const deploymentListCommand = cmd;
deploymentListCommand.appName = arg2;
deploymentListCommand.format = argv["format"];
deploymentListCommand.displayKeys = argv["displayKeys"];
}
break;
case "remove":
case "rm":
if (arg2 && arg3) {
cmd = { type: cli.CommandType.deploymentRemove };
const deploymentRemoveCommand = cmd;
deploymentRemoveCommand.appName = arg2;
deploymentRemoveCommand.deploymentName = arg3;
}
break;
case "rename":
if (arg2 && arg3 && arg4) {
cmd = { type: cli.CommandType.deploymentRename };
const deploymentRenameCommand = cmd;
deploymentRenameCommand.appName = arg2;
deploymentRenameCommand.currentDeploymentName = arg3;
deploymentRenameCommand.newDeploymentName = arg4;
}
break;
case "history":
case "h":
if (arg2) {
cmd = { type: cli.CommandType.deploymentHistory };
const deploymentHistoryCommand = cmd;
deploymentHistoryCommand.appName = arg2;
deploymentHistoryCommand.deploymentName = 'Production';
deploymentHistoryCommand.format = argv["format"];
deploymentHistoryCommand.displayAuthor = argv["displayAuthor"];
}
break;
}
break;
case "link":
cmd = {
type: cli.CommandType.link,
serverUrl: getServerUrl(arg1),
};
break;
case "login":
cmd = { type: cli.CommandType.login };
const loginCommand = cmd;
loginCommand.serverUrl = getServerUrl(arg1);
loginCommand.accessKey = argv["accessKey"];
break;
case "logout":
cmd = { type: cli.CommandType.logout };
break;
case "patch":
if (arg1) {
cmd = { type: cli.CommandType.patch };
const patchCommand = cmd;
patchCommand.appName = arg1;
patchCommand.deploymentName = 'Production';
patchCommand.label = argv["label"];
// Description must be set to null to indicate that it is not being patched.
patchCommand.description = argv["description"] ? backslash(argv["description"]) : null;
patchCommand.disabled = argv["disabled"];
patchCommand.mandatory = argv["mandatory"];
patchCommand.rollout = getRolloutValue(argv["rollout"]);
patchCommand.appStoreVersion = argv["targetBinaryVersion"];
}
break;
case "promote":
if (arg1 && arg2 && arg3) {
cmd = { type: cli.CommandType.promote };
const deploymentPromoteCommand = cmd;
deploymentPromoteCommand.appName = arg1;
deploymentPromoteCommand.sourceDeploymentName = arg2;
deploymentPromoteCommand.destDeploymentName = arg3;
deploymentPromoteCommand.description = argv["description"] ? backslash(argv["description"]) : "";