@@ -78,23 +78,24 @@ SUBCOMMANDS:
7878 show the details of the current production deployment of the project specified in the config file or with the --project option.
7979 Use --next and --prev to fetch the deployments deployed after or before the specified (or production) deployment.
8080 list List the deployments of a project. Specify the project using --project. Pagination can be controlled with --page and --limit.
81+ delete Delete a deployment. Same options to select the deployment as the show subcommand apply (--id, --project, --next and --prev).
8182
8283OPTIONS:
8384 -h, --help Prints this help information
84- --id=<deployment-id> [show] Id of the deployment of which to show details
85- -p, --project=<NAME|ID> [show] The project the production deployment of which to show the details . Ignored if combined with --id
85+ --id=<deployment-id> [show,delete] Select a deployment by id.
86+ -p, --project=<NAME|ID> [show,delete] Select the production deployment of a project . Ignored if combined with --id
8687 [list] The project of which to list deployments.
87- --next[=pos] [show] Show the details of a deployment deployed after the specified deployment
88+ --next[=pos] [show,delete] Modifier that selects a deployment deployed chronologically after the deployment selected with --id or --project
8889 Can be used multiple times (--next --next is the same as --next=2)
89- --prev[=pos] [show] Show the details of a deployment deployed before the specified deployment.
90+ --prev[=pos] [show,delete] Modifier that selects a deployment deployed chronologically before the deployment selected with --id or --project
9091 Can be used multiple times (--prev --prev is the same as --prev=2)
9192 --page=<num> [list] Page of the deployments list to fetch
9293 --limit=<num> [list] Amount of deployments to include in the list
9394 --format=<overview|json> Output the deployment details in an overview or JSON-encoded. Defaults to 'overview' when stdout is a tty, and 'json' otherwise.
9495 --token=<TOKEN> The API token to use (defaults to DENO_DEPLOY_TOKEN env var)
9596 --config=<PATH> Path to the file from where to load DeployCTL config. Defaults to 'deno.json'
9697 --color=<auto|always|never> Enable or disable colored output. Defaults to 'auto' (colored when stdout is a tty)
97- --force Automatically execute the command without waiting for confirmation.
98+ --force [delete] Automatically execute the command without waiting for confirmation.
9899` ;
99100
100101export default async function ( args : Args ) : Promise < void > {
@@ -110,6 +111,9 @@ export default async function (args: Args): Promise<void> {
110111 case "show" :
111112 await showDeployment ( args ) ;
112113 break ;
114+ case "delete" :
115+ await deleteDeployment ( args ) ;
116+ break ;
113117 default :
114118 console . error ( help ) ;
115119 Deno . exit ( 1 ) ;
@@ -212,98 +216,20 @@ async function listDeployments(args: Args): Promise<void> {
212216
213217// TODO: Show if active (and maybe some stats?)
214218async function showDeployment ( args : Args ) : Promise < void > {
215- const deploymentIdArg = args . _ . shift ( ) ?. toString ( ) || args . id ;
216- // Ignore --project if user also provided --id
217- const projectIdArg = deploymentIdArg ? undefined : args . project ;
218-
219219 const api = args . token
220220 ? API . fromToken ( args . token )
221221 : API . withTokenProvisioner ( TokenProvisioner ) ;
222222
223- let deploymentId ,
224- projectId ,
225- build : Build | null | undefined ,
226- project : Project | null | undefined ,
227- databases : Database [ ] | null ;
228-
229- if ( deploymentIdArg ) {
230- deploymentId = deploymentIdArg ;
231- } else {
232- // Default to showing the production deployment of the project
233- if ( ! projectIdArg ) {
234- error (
235- "No deployment or project specified. Use --id <deployment-id> or --project <project-name>" ,
236- ) ;
237- }
238- projectId = projectIdArg ;
239- const spinner = wait (
240- `Searching production deployment of project '${ projectId } '...` ,
241- ) . start ( ) ;
242- project = await api . getProject ( projectId ) ;
243- if ( ! project ) {
244- spinner . fail (
245- `The project '${ projectId } ' does not exist, or you don't have access to it` ,
246- ) ;
247- return Deno . exit ( 1 ) ;
248- }
249- if ( ! project . productionDeployment ) {
250- spinner . fail (
251- `Project '${ project . name } ' does not have a production deployment. Use --id <deployment-id> to specify the deployment to show` ,
252- ) ;
253- return Deno . exit ( 1 ) ;
254- }
255- deploymentId = project . productionDeployment . deploymentId ;
256- spinner . succeed (
257- `The production deployment of the project '${ project . name } ' is '${ deploymentId } '` ,
258- ) ;
259- }
260-
261- if ( args . prev . length !== 0 || args . next . length !== 0 ) {
262- // Search the deployment relative to the specified deployment
263- if ( ! projectId ) {
264- // Fetch the deployment specified with --id, to know of which project to search the relative deployment
265- // If user didn't use --id, they must have used --project, thus we already know the project-id
266- const spinner_ = wait ( `Fetching deployment '${ deploymentId } '...` )
267- . start ( ) ;
268- const specifiedDeployment = await api . getDeployment ( deploymentId ) ;
269- if ( ! specifiedDeployment ) {
270- spinner_ . fail (
271- `The deployment '${ deploymentId } ' does not exist, or you don't have access to it` ,
272- ) ;
273- return Deno . exit ( 1 ) ;
274- }
275- spinner_ . succeed ( `Deployment '${ deploymentId } ' found` ) ;
276- projectId = specifiedDeployment . project . id ;
277- }
278- let relativePos = 0 ;
279- for ( const prev of args . prev ) {
280- relativePos -= parseInt ( prev || "1" ) ;
281- }
282- for ( const next of args . next ) {
283- relativePos += parseInt ( next || "1" ) ;
284- }
285- const relativePosString = relativePos . toLocaleString ( navigator . language , {
286- signDisplay : "exceptZero" ,
287- } ) ;
288- const spinner = wait (
289- `Searching the deployment ${ relativePosString } relative to '${ deploymentId } '...` ,
290- ) . start ( ) ;
291- const maybeBuild = await searchRelativeDeployment (
292- api . listAllDeployments ( projectId ) ,
293- deploymentId ,
294- relativePos ,
295- ) ;
296- if ( ! maybeBuild ) {
297- spinner . fail (
298- `The deployment '${ deploymentId } ' does not have a deployment ${ relativePosString } relative to it` ,
299- ) ;
300- return Deno . exit ( 1 ) ;
301- }
302- build = maybeBuild ;
303- spinner . succeed (
304- `The deployment ${ relativePosString } relative to '${ deploymentId } ' is '${ build . deploymentId } '` ,
305- ) ;
306- }
223+ let [ deploymentId , projectId , build , project ] : [
224+ string ,
225+ string | undefined ,
226+ Build | null | undefined ,
227+ Project | null | undefined ,
228+ ] = await resolveDeploymentId (
229+ args ,
230+ api ,
231+ ) ;
232+ let databases : Database [ ] | null ;
307233
308234 const spinner = wait ( `Fetching deployment '${ deploymentId } ' details...` )
309235 . start ( ) ;
@@ -375,6 +301,35 @@ async function showDeployment(args: Args): Promise<void> {
375301 }
376302}
377303
304+ async function deleteDeployment ( args : Args ) : Promise < void > {
305+ const api = args . token
306+ ? API . fromToken ( args . token )
307+ : API . withTokenProvisioner ( TokenProvisioner ) ;
308+ const [ deploymentId , _projectId , _build , _project ] =
309+ await resolveDeploymentId (
310+ args ,
311+ api ,
312+ ) ;
313+ const confirmation = args . force ? true : confirm (
314+ `${
315+ magenta ( "?" )
316+ } Are you sure you want to delete the deployment '${ deploymentId } '?`,
317+ ) ;
318+ if ( ! confirmation ) {
319+ wait ( "" ) . fail ( "Delete canceled" ) ;
320+ return ;
321+ }
322+ const spinner = wait ( `Deleting deployment '${ deploymentId } '...` ) . start ( ) ;
323+ const deleted = await api . deleteDeployment ( deploymentId ) ;
324+ if ( deleted ) {
325+ spinner . succeed ( `Deployment '${ deploymentId } ' deleted successfully` ) ;
326+ } else {
327+ spinner . fail (
328+ `Deployment '${ deploymentId } ' not found, or you don't have access to it` ,
329+ ) ;
330+ }
331+ }
332+
378333async function searchRelativeDeployment (
379334 deployments : AsyncGenerator < Build > ,
380335 deploymentId : string ,
@@ -722,3 +677,107 @@ function renderTable(table: Record<string, string>[]) {
722677 }
723678 console . log ( `\u2514\u2500${ divisor } \u2500\u2518` ) ;
724679}
680+
681+ type DeploymentId = string ;
682+ type ProjectId = string ;
683+
684+ async function resolveDeploymentId (
685+ args : Args ,
686+ api : API ,
687+ ) : Promise <
688+ [ DeploymentId , ProjectId | undefined , Build | undefined , Project | undefined ]
689+ > {
690+ const deploymentIdArg = args . _ . shift ( ) ?. toString ( ) || args . id ;
691+ // Ignore --project if user also provided --id
692+ const projectIdArg = deploymentIdArg ? undefined : args . project ;
693+
694+ let deploymentId ,
695+ projectId : string | undefined ,
696+ build : Build | undefined ,
697+ project : Project | undefined ;
698+
699+ if ( deploymentIdArg ) {
700+ deploymentId = deploymentIdArg ;
701+ } else {
702+ // Default to showing the production deployment of the project
703+ if ( ! projectIdArg ) {
704+ error (
705+ "No deployment or project specified. Use --id <deployment-id> or --project <project-name>" ,
706+ ) ;
707+ }
708+ projectId = projectIdArg ;
709+ const spinner = wait (
710+ `Searching production deployment of project '${ projectId } '...` ,
711+ ) . start ( ) ;
712+ const maybeProject = await api . getProject ( projectId ) ;
713+ if ( ! maybeProject ) {
714+ spinner . fail (
715+ `The project '${ projectId } ' does not exist, or you don't have access to it` ,
716+ ) ;
717+ return Deno . exit ( 1 ) ;
718+ }
719+ project = maybeProject ;
720+ if ( ! project . productionDeployment ) {
721+ spinner . fail (
722+ `Project '${ project . name } ' does not have a production deployment. Use --id <deployment-id> to specify the deployment to show` ,
723+ ) ;
724+ return Deno . exit ( 1 ) ;
725+ }
726+ deploymentId = project . productionDeployment . deploymentId ;
727+ spinner . succeed (
728+ `The production deployment of the project '${ project . name } ' is '${ deploymentId } '` ,
729+ ) ;
730+ }
731+
732+ if ( args . prev . length !== 0 || args . next . length !== 0 ) {
733+ // Search the deployment relative to the specified deployment
734+ if ( ! projectId ) {
735+ // Fetch the deployment specified with --id, to know of which project to search the relative deployment
736+ // If user didn't use --id, they must have used --project, thus we already know the project-id
737+ const spinner_ = wait ( `Fetching deployment '${ deploymentId } '...` )
738+ . start ( ) ;
739+ const specifiedDeployment = await api . getDeployment ( deploymentId ) ;
740+ if ( ! specifiedDeployment ) {
741+ spinner_ . fail (
742+ `The deployment '${ deploymentId } ' does not exist, or you don't have access to it` ,
743+ ) ;
744+ return Deno . exit ( 1 ) ;
745+ }
746+ spinner_ . succeed ( `Deployment '${ deploymentId } ' found` ) ;
747+ projectId = specifiedDeployment . project . id ;
748+ }
749+ let relativePos = 0 ;
750+ for ( const prev of args . prev ) {
751+ relativePos -= parseInt ( prev || "1" ) ;
752+ }
753+ for ( const next of args . next ) {
754+ relativePos += parseInt ( next || "1" ) ;
755+ }
756+ if ( Number . isNaN ( relativePos ) ) {
757+ error ( "Value of --next and --prev must be a number" ) ;
758+ }
759+ const relativePosString = relativePos . toLocaleString ( navigator . language , {
760+ signDisplay : "exceptZero" ,
761+ } ) ;
762+ const spinner = wait (
763+ `Searching the deployment ${ relativePosString } relative to '${ deploymentId } '...` ,
764+ ) . start ( ) ;
765+ const maybeBuild = await searchRelativeDeployment (
766+ api . listAllDeployments ( projectId ) ,
767+ deploymentId ,
768+ relativePos ,
769+ ) ;
770+ if ( ! maybeBuild ) {
771+ spinner . fail (
772+ `The deployment '${ deploymentId } ' does not have a deployment ${ relativePosString } relative to it` ,
773+ ) ;
774+ return Deno . exit ( 1 ) ;
775+ }
776+ build = maybeBuild ;
777+ deploymentId = build . deploymentId ;
778+ spinner . succeed (
779+ `The deployment ${ relativePosString } relative to '${ deploymentId } ' is '${ build . deploymentId } '` ,
780+ ) ;
781+ }
782+ return [ deploymentId , projectId , build , project ] ;
783+ }
0 commit comments