[deployment-retention]: feat: preview policies

This commit is contained in:
Brooke Mosby
2024-05-29 15:01:21 -06:00
parent 9db0298981
commit def0e28ede
3 changed files with 51 additions and 3 deletions

View File

@@ -36,6 +36,16 @@ export const listCommand: Command = {
type: String, type: String,
deprecated: false, deprecated: false,
}, },
{
name: 'policy',
description:
'Preview deployments by retention policy (e.g.: `-p preview=1w`). Can appear many times.',
argument:
'[canceled|errored|preview|production]=[1d|1w|1m|2m|3m|1y|unlimited]',
shorthand: null,
type: [String],
deprecated: false,
},
], ],
examples: [ examples: [
{ {
@@ -54,5 +64,9 @@ export const listCommand: Command = {
name: 'Paginate deployments for a project, where `1584722256178` is the time in milliseconds since the UNIX epoch', name: 'Paginate deployments for a project, where `1584722256178` is the time in milliseconds since the UNIX epoch',
value: `${packageName} list my-app --next 1584722256178`, value: `${packageName} list my-app --next 1584722256178`,
}, },
{
name: 'Preview deployments affected by deployment retention policies',
value: `${packageName} list -policy canceled=1d -policy errored=1w -policy preview=1m -policy production=1y`,
},
], ],
}; };

View File

@@ -21,6 +21,18 @@ import { isErrnoException } from '@vercel/error-utils';
import { help } from '../help'; import { help } from '../help';
import { listCommand } from './command'; import { listCommand } from './command';
function ToDate(timestamp: number): string {
const date = new Date(timestamp);
const options: Intl.DateTimeFormatOptions = {
year: '2-digit',
month: '2-digit',
day: '2-digit',
};
// The locale 'en-US' ensures the format is MM/DD/YY
return date.toLocaleDateString('en-US', options);
}
export default async function list(client: Client) { export default async function list(client: Client) {
let argv; let argv;
@@ -34,6 +46,8 @@ export default async function list(client: Client) {
'--prod': Boolean, // this can be deprecated someday '--prod': Boolean, // this can be deprecated someday
'--yes': Boolean, '--yes': Boolean,
'-y': '--yes', '-y': '--yes',
'--policy': [String],
'-p': '--policy',
// deprecated // deprecated
'--confirm': Boolean, '--confirm': Boolean,
@@ -65,6 +79,7 @@ export default async function list(client: Client) {
const autoConfirm = !!argv['--yes']; const autoConfirm = !!argv['--yes'];
const meta = parseMeta(argv['--meta']); const meta = parseMeta(argv['--meta']);
const policy = parseMeta(argv['--policy']);
const target = argv['--prod'] const target = argv['--prod']
? 'production' ? 'production'
@@ -180,6 +195,7 @@ export default async function list(client: Client) {
meta, meta,
nextTimestamp, nextTimestamp,
target, target,
policy,
}); });
let { let {
@@ -249,6 +265,7 @@ export default async function list(client: Client) {
const headers = ['Age', 'Deployment', 'Status', 'Environment', 'Duration']; const headers = ['Age', 'Deployment', 'Status', 'Environment', 'Duration'];
if (showUsername) headers.push('Username'); if (showUsername) headers.push('Username');
if (policy) headers.push(...['Expiration', 'Proposed Expiration']);
const urls: string[] = []; const urls: string[] = [];
client.output.print( client.output.print(
@@ -266,6 +283,10 @@ export default async function list(client: Client) {
dep.target === 'production' ? 'Production' : 'Preview', dep.target === 'production' ? 'Production' : 'Preview',
chalk.gray(getDeploymentDuration(dep)), chalk.gray(getDeploymentDuration(dep)),
showUsername ? chalk.gray(dep.creator?.username) : '', showUsername ? chalk.gray(dep.creator?.username) : '',
policy && dep.expiration ? ToDate(dep.expiration) : '',
policy && dep.proposedExpiration
? ToDate(dep.proposedExpiration)
: '',
]; ];
}) })
.filter(app => .filter(app =>

View File

@@ -63,6 +63,7 @@ export interface ListOptions {
meta?: Dictionary<string>; meta?: Dictionary<string>;
nextTimestamp?: number; nextTimestamp?: number;
target?: string; target?: string;
policy?: Dictionary<string>;
} }
export default class Now extends EventEmitter { export default class Now extends EventEmitter {
@@ -343,7 +344,13 @@ export default class Now extends EventEmitter {
async list( async list(
app?: string, app?: string,
{ version = 4, meta = {}, nextTimestamp, target }: ListOptions = {}, {
version = 4,
meta = {},
nextTimestamp,
target,
policy = {},
}: ListOptions = {},
prod?: boolean prod?: boolean
) { ) {
const fetchRetry = async (url: string, options: FetchOptions = {}) => { const fetchRetry = async (url: string, options: FetchOptions = {}) => {
@@ -371,7 +378,7 @@ export default class Now extends EventEmitter {
); );
}; };
if (!app && !Object.keys(meta).length) { if (!app && !Object.keys(meta).length && !Object.keys(policy).length) {
// Get the 20 latest projects and their latest deployment // Get the 20 latest projects and their latest deployment
const query = new URLSearchParams({ limit: (20).toString() }); const query = new URLSearchParams({ limit: (20).toString() });
if (nextTimestamp) { if (nextTimestamp) {
@@ -400,7 +407,13 @@ export default class Now extends EventEmitter {
query.set('app', app); query.set('app', app);
} }
if (Object.keys(meta).length) {
Object.keys(meta).map(key => query.set(`meta-${key}`, meta[key])); Object.keys(meta).map(key => query.set(`meta-${key}`, meta[key]));
}
if (Object.keys(policy).length) {
Object.keys(policy).map(key => query.set(`policy-${key}`, policy[key]));
}
query.set('limit', '20'); query.set('limit', '20');