[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,
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: [
{
@@ -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',
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 { 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) {
let argv;
@@ -34,6 +46,8 @@ export default async function list(client: Client) {
'--prod': Boolean, // this can be deprecated someday
'--yes': Boolean,
'-y': '--yes',
'--policy': [String],
'-p': '--policy',
// deprecated
'--confirm': Boolean,
@@ -65,6 +79,7 @@ export default async function list(client: Client) {
const autoConfirm = !!argv['--yes'];
const meta = parseMeta(argv['--meta']);
const policy = parseMeta(argv['--policy']);
const target = argv['--prod']
? 'production'
@@ -180,6 +195,7 @@ export default async function list(client: Client) {
meta,
nextTimestamp,
target,
policy,
});
let {
@@ -249,6 +265,7 @@ export default async function list(client: Client) {
const headers = ['Age', 'Deployment', 'Status', 'Environment', 'Duration'];
if (showUsername) headers.push('Username');
if (policy) headers.push(...['Expiration', 'Proposed Expiration']);
const urls: string[] = [];
client.output.print(
@@ -266,6 +283,10 @@ export default async function list(client: Client) {
dep.target === 'production' ? 'Production' : 'Preview',
chalk.gray(getDeploymentDuration(dep)),
showUsername ? chalk.gray(dep.creator?.username) : '',
policy && dep.expiration ? ToDate(dep.expiration) : '',
policy && dep.proposedExpiration
? ToDate(dep.proposedExpiration)
: '',
];
})
.filter(app =>

View File

@@ -63,6 +63,7 @@ export interface ListOptions {
meta?: Dictionary<string>;
nextTimestamp?: number;
target?: string;
policy?: Dictionary<string>;
}
export default class Now extends EventEmitter {
@@ -343,7 +344,13 @@ export default class Now extends EventEmitter {
async list(
app?: string,
{ version = 4, meta = {}, nextTimestamp, target }: ListOptions = {},
{
version = 4,
meta = {},
nextTimestamp,
target,
policy = {},
}: ListOptions = {},
prod?: boolean
) {
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
const query = new URLSearchParams({ limit: (20).toString() });
if (nextTimestamp) {
@@ -400,7 +407,13 @@ export default class Now extends EventEmitter {
query.set('app', app);
}
if (Object.keys(meta).length) {
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');