mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-10 04:22:12 +00:00
[deployment-retention]: feat: preview policies
This commit is contained in:
@@ -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`,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 =>
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(meta).map(key => query.set(`meta-${key}`, meta[key]));
|
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');
|
query.set('limit', '20');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user