appcenter-cli
Version:
Command line tool for Visual Studio App Center
134 lines (108 loc) • 5.72 kB
text/typescript
import { AppCommand, CommandArgs, CommandResult, help, failure, ErrorCodes, success, shortName, longName } from "../../../util/commandline";
import { out } from "../../../util/interaction";
import { inspect } from "util";
import { AppCenterClient, models, clientRequest } from "../../../util/apis";
import * as chalk from "chalk";
import { scriptName } from "../../../util/misc";
import { formatDate } from "./lib/date-helper";
const debug = require("debug")("appcenter-cli:commands:codepush:deployments:list");
("List the deployments associated with an app")
export default class CodePushDeploymentListListCommand extends AppCommand {
("Specifies whether to display the deployment keys")
("k")
("displayKeys")
public displayKeys: boolean;
constructor(args: CommandArgs) {
super(args);
}
async run(client: AppCenterClient): Promise<CommandResult> {
const app = this.app;
let deployments: models.Deployment[];
try {
const httpRequest = await out.progress("Getting CodePush deployments...", clientRequest<models.Deployment[]>(
(cb) => client.codePushDeployments.list(app.ownerName, app.appName, cb)));
deployments = httpRequest.result;
if (this.displayKeys) {
out.table(out.getCommandOutputTableOptions(this.generateColoredTableTitles(["Name", "Key"])),
deployments.map((deployment) => [deployment.name, deployment.key])
);
} else {
out.text("Note: To display deployment keys add -k|--displayKeys option");
out.table(out.getCommandOutputTableOptions(this.generateColoredTableTitles(["Name", "Update Metadata", "Install Metrics"])),
await this.generateTableInfoRows(deployments, client)
);
}
return success();
} catch (error) {
debug(`Failed to get list of Codepush deployments - ${inspect(error)}`);
if (error.statusCode === 404) {
const appNotFoundErrorMsg = `The app ${this.identifier} does not exist. Please double check the name, and provide it in the form owner/appname. \nRun the command ${chalk.bold(`${scriptName} apps list`)} to see what apps you have access to.`;
return failure(ErrorCodes.InvalidParameter, appNotFoundErrorMsg);
} else {
return failure(ErrorCodes.Exception, "Failed to get list of deployments for the app");
}
}
}
private generateColoredTableTitles(tableTitles: string[]): string[] {
return tableTitles.map((title) => chalk.cyan(title));
}
private async generateTableInfoRows(deployments: models.Deployment[], client: AppCenterClient): Promise<string[][]> {
return await Promise.all(deployments.map(async (deployment: models.Deployment): Promise<string[]> => {
let metadataString: string = "";
let metricsString: string = "";
if (deployment.latestRelease) {
metadataString = this.generateMetadataString(deployment.latestRelease);
metricsString = await this.getMetricsString(deployment, client);
} else {
metadataString = chalk.magenta("No updates released");
metricsString = chalk.magenta("No installs recorded");
}
return [deployment.name, metadataString, metricsString];
}));
}
private async getMetricsString(deployment: models.Deployment, client: AppCenterClient): Promise<string> {
let metrics: models.CodePushReleaseMetric[];
const httpRequest = await out.progress("Getting CodePush deployments metrics...", clientRequest<models.CodePushReleaseMetric[]>(
(cb) => client.codePushDeploymentMetrics.get(deployment.name, this.app.ownerName, this.app.appName, cb)));
metrics = httpRequest.result;
let releasesTotalActive: number = 0;
metrics.forEach((metric) => releasesTotalActive += metric.active);
const releaseMetrics: models.CodePushReleaseMetric = metrics.find((metric) => metric.label === deployment.latestRelease.label);
return this.generateMetricsString(releaseMetrics, releasesTotalActive);
}
private generateMetricsString(releaseMetrics: models.CodePushReleaseMetric, releasesTotalActive: number): string {
if (releaseMetrics) {
let metricsString: string = "";
const activePercent: number = (releasesTotalActive) ? releaseMetrics.active / releasesTotalActive * 100 : 0.0;
let percentString: string;
if (activePercent === 100.0) {
percentString = "100%";
} else if (activePercent === 0.0) {
percentString = "0%";
} else {
percentString = activePercent.toPrecision(2) + "%";
}
metricsString += chalk.green("Active: ") + percentString + ` (${releaseMetrics.active} of ${releasesTotalActive})\n`;
if (releaseMetrics.installed != null) {
metricsString += chalk.green("Installed: ") + releaseMetrics.installed;
}
const pending: number = releaseMetrics.downloaded - releaseMetrics.installed - releaseMetrics.failed;
if (pending) {
metricsString += ` (${pending} pending)`;
}
return metricsString;
} else {
return chalk.magenta("No installs recorded");
}
}
private generateMetadataString(release: models.CodePushRelease): string {
let metadataString: string = "";
const lineFeed: string = "\n";
metadataString += chalk.green("Label: ") + release.label + lineFeed;
metadataString += chalk.green("App Version: ") + release.targetBinaryRange + lineFeed;
metadataString += chalk.green("Mandatory: ") + (release.isMandatory ? "Yes" : "No") + lineFeed;
metadataString += chalk.green("Release Time: ") + formatDate(release.uploadTime) + lineFeed;
metadataString += chalk.green("Released By: ") + release.releasedBy;
return metadataString;
}
}