diff --git a/cli/README.md b/cli/README.md index 0ae06279..e46817c1 100644 --- a/cli/README.md +++ b/cli/README.md @@ -172,8 +172,8 @@ code-push deployment add Just like with apps, you can remove and rename deployments as well, using the following commands respectively: ``` -code-push deployment rename code-push deployment rm +code-push deployment rename ``` If at any time you'd like to view the list of deployments that a specific app includes, you can simply run the following command: @@ -425,3 +425,13 @@ Additionally, the history displays the install metrics for each release. You can By default, the history doesn't display the author of each release, but if you are collaborating on an app with other developers, and want to view who released each update, you can pass the additional `--displayAuthor` (or `-a`) flag to the history command. *NOTE: The history command can also be run using the "h" alias* + +## Clearing release history + +You can clear the release history associated with a deployment using the following command: + +``` +code-push deployment clear +``` + +After running this command, client devices configured to receive updates from this deployment using its associated deployment key will no longer receive those updates that have been cleared. This command is irreversible, and therefore should not be used in a production deployment. diff --git a/cli/definitions/cli.ts b/cli/definitions/cli.ts index 9636a1a9..ccaebd70 100644 --- a/cli/definitions/cli.ts +++ b/cli/definitions/cli.ts @@ -12,6 +12,7 @@ collaboratorRemove, deploymentAdd, deploymentHistory, + deploymentHistoryClear, deploymentList, deploymentMetrics, deploymentRemove, @@ -83,6 +84,11 @@ export interface IDeploymentAddCommand extends ICommand { deploymentName: string; } +export interface IDeploymentHistoryClearCommand extends ICommand { + appName: string; + deploymentName: string; +} + export interface IDeploymentHistoryCommand extends ICommand { appName: string; deploymentName: string; diff --git a/cli/script/command-executor.ts b/cli/script/command-executor.ts index 844bb410..ac09b926 100644 --- a/cli/script/command-executor.ts +++ b/cli/script/command-executor.ts @@ -274,6 +274,20 @@ function deploymentAdd(command: cli.IDeploymentAddCommand): Promise { }); } +function deploymentHistoryClear(command: cli.IDeploymentHistoryClearCommand): Promise { + return confirm() + .then((wasConfirmed: boolean): Promise => { + if (wasConfirmed) { + return sdk.clearDeploymentHistory(command.appName, command.deploymentName) + .then((): void => { + log("Successfully cleared the release history associated with the \"" + command.deploymentName + "\" deployment from the \"" + command.appName + "\" app."); + }) + } + + log("Clear deployment cancelled."); + }); +} + export var deploymentList = (command: cli.IDeploymentListCommand, showPackage: boolean = true): Promise => { throwForInvalidOutputFormat(command.format); var deployments: Deployment[]; @@ -435,6 +449,9 @@ export function execute(command: cli.ICommand): Promise { case cli.CommandType.deploymentAdd: return deploymentAdd(command); + case cli.CommandType.deploymentHistoryClear: + return deploymentHistoryClear(command); + case cli.CommandType.deploymentHistory: return deploymentHistory(command); diff --git a/cli/script/command-parser.ts b/cli/script/command-parser.ts index 9d8276de..c91c1ec9 100644 --- a/cli/script/command-parser.ts +++ b/cli/script/command-parser.ts @@ -113,6 +113,15 @@ function removeCollaborator(commandName: string, yargs: yargs.Argv): void { addCommonConfiguration(yargs); } +function deploymentHistoryClear(commandName: string, yargs: yargs.Argv): void { + isValidCommand = true; + yargs.usage(USAGE_PREFIX + " deployment " + commandName + " ") + .demand(/*count*/ 4, /*max*/ 4) // Require exactly four non-option arguments. + .example("deployment " + commandName + " MyApp MyDeployment", "Clears the release history associated with deployment \"MyDeployment\" from app \"MyApp\""); + + addCommonConfiguration(yargs); +} + function deploymentList(commandName: string, yargs: yargs.Argv): void { isValidCommand = true; yargs.usage(USAGE_PREFIX + " deployment " + commandName + " [--format ] [--displayKeys]") @@ -227,6 +236,7 @@ var argv = yargs.usage(USAGE_PREFIX + " ") addCommonConfiguration(yargs); }) + .command("clear", "Clears 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) => { @@ -461,6 +471,17 @@ function createCommand(): cli.ICommand { } break; + case "clear": + if (arg2 && arg3) { + cmd = { type: cli.CommandType.deploymentHistoryClear }; + + var deploymentHistoryClearCommand = cmd; + + deploymentHistoryClearCommand.appName = arg2; + deploymentHistoryClearCommand.deploymentName = arg3; + } + break; + case "list": case "ls": if (arg2) { diff --git a/cli/test/cli.ts b/cli/test/cli.ts index a5ebe2fa..d6157d2b 100644 --- a/cli/test/cli.ts +++ b/cli/test/cli.ts @@ -52,6 +52,10 @@ export class SdkStub { }); } + public clearDeploymentHistory(appId: string, deployment: string): Promise { + return Q(null); + } + public getAccessKeys(): Promise { return Q([{ name: "8", @@ -516,6 +520,47 @@ describe("CLI", () => { }); }); + it("deploymentHistoryClear clears deployment", (done: MochaDone): void => { + var command: cli.IDeploymentHistoryClearCommand = { + type: cli.CommandType.deploymentHistoryClear, + appName: "a", + deploymentName: "Staging" + }; + + var clearDeployment: Sinon.SinonSpy = sandbox.spy(cmdexec.sdk, "clearDeploymentHistory"); + + cmdexec.execute(command) + .done((): void => { + sinon.assert.calledOnce(clearDeployment); + sinon.assert.calledWithExactly(clearDeployment, "a", "Staging"); + sinon.assert.calledOnce(log); + sinon.assert.calledWithExactly(log, "Successfully cleared the release history associated with the \"Staging\" deployment from the \"a\" app."); + + done(); + }); + }); + + it("deploymentHistoryClear does not clear deployment if cancelled", (done: MochaDone): void => { + var command: cli.IDeploymentHistoryClearCommand = { + type: cli.CommandType.deploymentHistoryClear, + appName: "a", + deploymentName: "Staging" + }; + + var clearDeployment: Sinon.SinonSpy = sandbox.spy(cmdexec.sdk, "clearDeploymentHistory"); + + wasConfirmed = false; + + cmdexec.execute(command) + .done((): void => { + sinon.assert.notCalled(clearDeployment); + sinon.assert.calledOnce(log); + sinon.assert.calledWithExactly(log, "Clear deployment cancelled."); + + done(); + }); + }); + it("deploymentList lists deployment names, deployment keys, and package information", (done: MochaDone): void => { var command: cli.IDeploymentListCommand = { type: cli.CommandType.deploymentList, diff --git a/sdk/script/management-sdk.ts b/sdk/script/management-sdk.ts index a5feab21..d7c56c87 100644 --- a/sdk/script/management-sdk.ts +++ b/sdk/script/management-sdk.ts @@ -176,6 +176,11 @@ class AccountManager { return this.post(urlEncode `/apps/${appName}/deployments/`, JSON.stringify(deployment), /*expectResponseBody=*/ true) .then((res: JsonResponse) => res.body.deployment); } + + public clearDeploymentHistory(appName: string, deploymentName: string): Promise { + return this.del(urlEncode `/apps/${appName}/deployments/${deploymentName}/history`) + .then(() => null); + } public getDeployments(appName: string): Promise { return this.get(urlEncode `/apps/${appName}/deployments/`)