vercel
Version:
The command-line interface for Vercel
533 lines (526 loc) • 15.1 kB
JavaScript
import { createRequire as __createRequire } from 'node:module';
import { fileURLToPath as __fileURLToPath } from 'node:url';
import { dirname as __dirname_ } from 'node:path';
const require = __createRequire(import.meta.url);
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __dirname_(__filename);
import {
isValidName
} from "../../chunks/chunk-Y4JJYHUG.js";
import {
getCommandFlags
} from "../../chunks/chunk-EOZFDJSY.js";
import {
parseMeta
} from "../../chunks/chunk-EKPSCRJZ.js";
import {
getDeployment,
toHost
} from "../../chunks/chunk-NYJXGEIR.js";
import {
formatEnvironment,
validateLsArgs
} from "../../chunks/chunk-PPIAHRII.js";
import {
validateJsonOutput
} from "../../chunks/chunk-XPKWKPWA.js";
import {
getScope
} from "../../chunks/chunk-KWDV5FZH.js";
import {
listCommand
} from "../../chunks/chunk-4PSOOFYO.js";
import {
help
} from "../../chunks/chunk-MMF4BVAP.js";
import {
formatProject,
getLinkedProject,
getProjectByNameOrId,
parseTarget
} from "../../chunks/chunk-X775BOSL.js";
import {
TelemetryClient
} from "../../chunks/chunk-4OEA5ILS.js";
import "../../chunks/chunk-ULXHXZCZ.js";
import {
elapsed,
require_ms
} from "../../chunks/chunk-CO5D46AG.js";
import "../../chunks/chunk-N2T234LO.js";
import {
table
} from "../../chunks/chunk-DKD6GTQT.js";
import {
getFlagsSpecification,
parseArguments,
printError
} from "../../chunks/chunk-4GQQJY5Y.js";
import {
ProjectNotFound,
getCommandName,
require_lib
} from "../../chunks/chunk-UGXBNJMO.js";
import "../../chunks/chunk-P4QNYOFB.js";
import {
output_manager_default,
require_dist
} from "../../chunks/chunk-ZQKJVHXY.js";
import {
require_source
} from "../../chunks/chunk-S7KYDPEM.js";
import {
__toESM
} from "../../chunks/chunk-TZ2YI2VH.js";
// src/commands/list/index.ts
var import_ms = __toESM(require_ms(), 1);
var import_chalk = __toESM(require_source(), 1);
var import_title = __toESM(require_lib(), 1);
// src/util/parse-policy.ts
function parsePolicy(policy) {
if (!policy) {
return {};
}
if (typeof policy === "string") {
policy = [policy];
}
const parsed = {};
for (const item of policy) {
const [key, ...rest] = item.split("=");
parsed[key] = rest.join("=");
}
return parsed;
}
// src/commands/list/index.ts
var import_error_utils = __toESM(require_dist(), 1);
// src/util/telemetry/commands/list/index.ts
var ListTelemetryClient = class extends TelemetryClient {
trackCliFlagAll(all) {
if (all) {
this.trackCliFlag("all");
}
}
trackCliOptionMeta(meta) {
if (meta && meta.length > 0) {
this.trackCliOption({
option: "meta",
value: this.redactedValue
});
}
}
trackCliOptionPolicy(policy) {
if (policy && policy.length > 0) {
this.trackCliOption({
option: "policy",
value: this.redactedValue
});
}
}
trackCliOptionEnvironment(environment) {
if (environment) {
this.trackCliOption({
option: "environment",
value: this.redactedTargetName(environment)
});
}
}
trackCliOptionNext(next) {
if (next) {
this.trackCliOption({
option: "next",
value: this.redactedValue
});
}
}
trackCliFlagProd(flag) {
if (flag) {
this.trackCliFlag("prod");
}
}
trackCliFlagYes(flag) {
if (flag) {
this.trackCliFlag("yes");
}
}
trackCliFlagConfirm(flag) {
if (flag) {
this.trackCliFlag("confirm");
}
}
trackCliOptionStatus(status) {
if (status) {
this.trackCliOption({
option: "status",
value: this.redactedValue
});
}
}
trackCliArgumentApp(app) {
if (app) {
this.trackCliArgument({
arg: "app",
value: this.redactedValue
});
}
}
};
// src/commands/list/index.ts
function toDate(timestamp) {
const date = new Date(timestamp);
const options = {
year: "2-digit",
month: "2-digit",
day: "2-digit"
};
return date.toLocaleDateString("en-US", options);
}
async function list(client) {
const { print, log, warn, error, note, debug, spinner } = output_manager_default;
let parsedArgs = null;
const flagsSpecification = getFlagsSpecification(listCommand.options);
try {
parsedArgs = parseArguments(client.argv.slice(2), flagsSpecification);
} catch (error2) {
printError(error2);
return 1;
}
const telemetry = new ListTelemetryClient({
opts: {
store: client.telemetryEventStore
}
});
if (parsedArgs.flags["--help"]) {
telemetry.trackCliFlagHelp("list");
print(help(listCommand, { columns: client.stderr.columns }));
return 0;
}
const validationResult = validateLsArgs({
commandName: "ls [app]",
args: parsedArgs.args,
maxArgs: 2,
exitCode: 2
});
if (validationResult !== 0) {
return validationResult;
}
const formatResult = validateJsonOutput(parsedArgs.flags);
if (!formatResult.valid) {
error(formatResult.error);
return 1;
}
const asJson = formatResult.jsonOutput;
telemetry.trackCliFlagAll(parsedArgs.flags["--all"]);
telemetry.trackCliFlagProd(parsedArgs.flags["--prod"]);
telemetry.trackCliFlagYes(parsedArgs.flags["--yes"]);
telemetry.trackCliOptionEnvironment(parsedArgs.flags["--environment"]);
telemetry.trackCliOptionMeta(parsedArgs.flags["--meta"]);
telemetry.trackCliOptionNext(parsedArgs.flags["--next"]);
telemetry.trackCliOptionFormat(parsedArgs.flags["--format"]);
telemetry.trackCliOptionPolicy(parsedArgs.flags["--policy"]);
telemetry.trackCliOptionStatus(parsedArgs.flags["--status"]);
if ("--confirm" in parsedArgs.flags) {
telemetry.trackCliFlagConfirm(parsedArgs.flags["--confirm"]);
warn("`--confirm` is deprecated, please use `--yes` instead");
parsedArgs.flags["--yes"] = parsedArgs.flags["--confirm"];
}
const meta = parseMeta(parsedArgs.flags["--meta"]);
const policy = parsePolicy(parsedArgs.flags["--policy"]);
const target = parseTarget({
flagName: "environment",
flags: parsedArgs.flags
});
const statusFlag = parsedArgs.flags["--status"];
let status;
if (statusFlag) {
const validStatuses = [
"BUILDING",
"ERROR",
"INITIALIZING",
"QUEUED",
"READY",
"CANCELED"
];
const statusValues = statusFlag.split(",").map((s) => s.trim().toUpperCase());
const invalidStatuses = statusValues.filter(
(s) => !validStatuses.includes(s)
);
if (invalidStatuses.length > 0) {
error(
`Invalid status values: ${invalidStatuses.join(", ")}. Valid values are: ${validStatuses.join(", ")}`
);
return 1;
}
status = statusValues.join(",");
}
let project;
let pagination;
let contextName = "";
let app = parsedArgs.args[1];
const deployments = [];
let singleDeployment = false;
const allFlag = parsedArgs.flags["--all"];
let showAllProjects = false;
if (allFlag && app) {
error("Cannot use --all flag with a project argument");
return 1;
}
if (app) {
if (!isValidName(app)) {
error(`The provided argument "${app}" is not a valid project name`);
return 1;
}
telemetry.trackCliArgumentApp(app);
if (app.includes(".")) {
try {
({ contextName } = await getScope(client));
} catch (err) {
if ((0, import_error_utils.isErrnoException)(err) && (err.code === "NOT_AUTHORIZED" || err.code === "TEAM_DELETED")) {
error(err.message);
return 1;
}
}
if (!contextName) {
error("No context name found");
return 1;
}
const host = toHost(app);
const deployment = await getDeployment(client, contextName, host);
if (!deployment.projectId) {
error(`Could not find a deployment for "${host}"`);
return 1;
}
app = deployment.projectId;
note(
`We suggest using ${getCommandName(
"inspect <deployment>"
)} for retrieving details about a single deployment`
);
deployments.push(deployment);
singleDeployment = true;
}
const p = await getProjectByNameOrId(client, app);
if (p instanceof ProjectNotFound) {
error(`The provided argument "${app}" is not a valid project name`);
return 1;
}
project = p;
} else if (allFlag) {
showAllProjects = true;
} else {
const link = await getLinkedProject(client, client.cwd);
if (link.status === "error") {
return link.exitCode;
}
if (link.status === "linked") {
project = link.project;
client.config.currentTeam = link.org.id;
} else {
showAllProjects = true;
}
}
if (!contextName) {
try {
({ contextName } = await getScope(client));
} catch (err) {
if ((0, import_error_utils.isErrnoException)(err) && (err.code === "NOT_AUTHORIZED" || err.code === "TEAM_DELETED")) {
error(err.message);
return 1;
}
}
}
const nextTimestamp = parsedArgs.flags["--next"];
if (Number.isNaN(nextTimestamp)) {
error("Please provide a number for flag `--next`");
return 1;
}
const projectSlugLink = project ? formatProject(contextName, project.name) : null;
if (!singleDeployment) {
if (!asJson) {
spinner(`Fetching deployments in ${import_chalk.default.bold(contextName)}`);
}
const start = Date.now();
debug("Fetching deployments");
const query = new URLSearchParams({ limit: "20" });
if (project) {
query.set("projectId", project.id);
}
for (const [k, v] of Object.entries(meta)) {
query.set(`meta-${k}`, v);
}
for (const [k, v] of Object.entries(policy)) {
query.set(`policy-${k}`, v);
}
if (nextTimestamp) {
query.set("until", String(nextTimestamp));
}
if (target) {
query.set("target", target);
}
if (status) {
query.set("state", status);
}
for await (const chunk of client.fetchPaginated(`/v6/deployments?${query}`)) {
deployments.push(...chunk.deployments);
pagination = chunk.pagination;
if (deployments.length >= 20) {
break;
}
}
if (!deployments.length) {
if (asJson) {
const jsonOutput = { deployments: [], pagination, contextName };
client.stdout.write(`${JSON.stringify(jsonOutput, null, 2)}
`);
} else {
log(`No deployments found under ${import_chalk.default.bold(contextName)}.`);
}
return 0;
}
if (!asJson) {
const deploymentsLabel = target === "production" ? "Production deployments" : "Deployments";
if (showAllProjects) {
log(
`${deploymentsLabel} under ${import_chalk.default.bold(contextName)} ${elapsed(Date.now() - start)}`
);
} else {
log(
`${deploymentsLabel} for ${projectSlugLink} ${elapsed(Date.now() - start)}`
);
}
}
}
if (asJson) {
const jsonOutput = {
contextName,
deployments: deployments.sort(sortByCreatedAt).map((dep) => ({
id: dep.id,
url: dep.url,
name: dep.name,
state: dep.readyState,
target: dep.target,
customEnvironment: dep.customEnvironment ? {
id: dep.customEnvironment.id,
slug: dep.customEnvironment.slug
} : void 0,
createdAt: dep.createdAt,
buildingAt: dep.buildingAt,
ready: dep.ready,
creator: dep.creator ? {
uid: dep.creator.uid,
username: dep.creator.username
} : void 0,
meta: dep.meta
})),
pagination
};
client.stdout.write(`${JSON.stringify(jsonOutput, null, 2)}
`);
return 0;
}
const headers = ["Age", "Project", "Deployment", "Status", "Environment"];
const showPolicy = Object.keys(policy).length > 0;
if (!showPolicy)
headers.push("Duration", "Username");
if (showPolicy)
headers.push("Proposed Expiration");
const urls = [];
const tablePrint = table(
[
headers.map((header) => import_chalk.default.bold(import_chalk.default.cyan(header))),
...deployments.sort(sortByCreatedAt).map((dep) => {
urls.push(`https://${dep.url}`);
const proposedExp = dep.proposedExpiration ? toDate(Math.min(Date.now(), dep.proposedExpiration)) : "No expiration";
const createdAt = (0, import_ms.default)(
Date.now() - (dep?.undeletedAt ?? dep.createdAt)
);
const targetName = dep.customEnvironment?.slug || (dep.target === "production" ? "Production" : "Preview");
const targetSlug = dep.customEnvironment?.id || dep.target || "preview";
return [
import_chalk.default.gray(createdAt),
formatProject(contextName, dep.name),
`https://${dep.url}`,
stateString(dep.readyState || ""),
formatEnvironment(contextName, dep.name, {
id: targetSlug,
slug: targetName
}),
...!showPolicy ? [import_chalk.default.gray(getDeploymentDuration(dep))] : [],
...!showPolicy ? [import_chalk.default.gray(dep.creator?.username)] : [],
...showPolicy ? [import_chalk.default.gray(proposedExp)] : []
];
}).filter(
(app2) => (
// if an app wasn't supplied to filter by,
// we only want to render one deployment per app
app2 === null ? filterUniqueApps() : () => true
)
)
],
{ hsep: 5 }
).replace(/^/gm, " ");
print(`
${tablePrint}
`);
if (!client.stdout.isTTY) {
client.stdout.write(urls.join("\n"));
client.stdout.write("\n");
}
if (pagination?.next) {
const flags = getCommandFlags(parsedArgs.flags, ["--next"]);
log(
`To display the next page, run ${getCommandName(
`ls${app ? ` ${app}` : ""}${flags} --next ${pagination.next}`
)}`
);
}
return 0;
}
function getDeploymentDuration(dep) {
if (!dep || !dep.ready || !dep.buildingAt) {
return "?";
}
const duration = (0, import_ms.default)(dep.ready - dep.buildingAt);
if (duration === "0ms") {
return "--";
}
return duration;
}
function stateString(s) {
const CIRCLE = "\u25CF ";
const sTitle = (0, import_title.default)(s);
switch (s) {
case "INITIALIZING":
case "BUILDING":
case "DEPLOYING":
case "ANALYZING":
return import_chalk.default.yellow(CIRCLE) + sTitle;
case "ERROR":
return import_chalk.default.red(CIRCLE) + sTitle;
case "READY":
return import_chalk.default.green(CIRCLE) + sTitle;
case "QUEUED":
return import_chalk.default.white(CIRCLE) + sTitle;
case "CANCELED":
return import_chalk.default.gray(sTitle);
default:
return import_chalk.default.gray("UNKNOWN");
}
}
function sortByCreatedAt(a, b) {
return b.createdAt - a.createdAt;
}
function filterUniqueApps() {
const uniqueApps = /* @__PURE__ */ new Set();
return function uniqueAppFilter([appName]) {
if (uniqueApps.has(appName)) {
return false;
}
uniqueApps.add(appName);
return true;
};
}
export {
list as default,
getDeploymentDuration,
stateString
};