From 0aab53066a42706f039be8af6cc0262c9dca0998 Mon Sep 17 00:00:00 2001 From: James Lucktaylor Date: Thu, 22 Aug 2019 10:14:54 +0100 Subject: [PATCH] Set up the 'destroy' subcommand (#27) --- README.md | 13 +++++++++++-- cmd/stack/main.go | 26 +++++++++++++++++++++----- cmd/stack/{build.go => queue.go} | 20 ++++++++++---------- stack.config.example.json | 3 ++- 4 files changed, 44 insertions(+), 18 deletions(-) rename cmd/stack/{build.go => queue.go} (90%) diff --git a/README.md b/README.md index afa0726..9dd9018 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ A support tool for use with Terraform stacks, Azure DevOps build pipelines, and It currently has the following functions: - initialising Terraform against remote state storage, for local execution -- queueing Terraform builds in an Azure DevOps CI/CD pipeline +- queueing Terraform plans to build and destroy stacks in an Azure DevOps CI/CD pipeline - cancelling unneeded releases of aforementioned builds - creating GitHub issues in corresponding projects @@ -129,6 +129,7 @@ authed, and available on your `$PATH`: - `init` - `build` +- `destroy` - `cancel` - `issue` @@ -157,7 +158,7 @@ the directory structure of the Terraform stack, and the value is the GUID of sai ### `stack build` -Queues a build in Azure DevOps for the current Terraform stack directory. +Queues a plan in Azure DevOps to build the Terraform stack in the current directory. ``` bash $ stack build @@ -185,6 +186,14 @@ For example: stack build --target="azurerm_resource_group.main;azurerm_virtual_machine.app;azurerm_virtual_machine.database" ``` +### `stack destroy` + +Queues a plan in Azure DevOps to destroy the Terraform stack in the current directory. + +Functionally identical to the `stack build` subcommand, including `--branch` and `--target` optional arguments, with +the singular difference being that this subcommand references `.azureDevOps.destroyDefID` in the config instead of +`.azureDevOps.buildDefID`. + ### `stack cancel` Cancels any pending releases in Azure DevOps. diff --git a/cmd/stack/main.go b/cmd/stack/main.go index 0cf33bd..199cab4 100644 --- a/cmd/stack/main.go +++ b/cmd/stack/main.go @@ -7,14 +7,16 @@ import ( "os" "os/exec" "strings" + "time" "github.com/spf13/viper" ) // Take ldflags from GoReleaser +//nolint var ( - //nolint - version, commit, date, builtBy string + version, commit, builtBy string + date = time.Now().UTC().String() ) func main() { @@ -31,8 +33,9 @@ func main() { // Define Usage() for flags and '--help' flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), "Available commands for '%s':\n", os.Args[0]) - fmt.Fprintf(flag.CommandLine.Output(), " build Queue a build of this Terraform stack\n") + fmt.Fprintf(flag.CommandLine.Output(), " build Queue a plan to build this Terraform stack\n") fmt.Fprintf(flag.CommandLine.Output(), " cancel Cancel release(s) of built/planned Terraform stack\n") + fmt.Fprintf(flag.CommandLine.Output(), " destroy Queue a plan to destroy this Terraform stack\n") fmt.Fprintf(flag.CommandLine.Output(), " init Initialise this Terraform stack against remote state\n") fmt.Fprintf(flag.CommandLine.Output(), " issue Add/update a GitHub issue for this Terraform stack\n") fmt.Fprintf(flag.CommandLine.Output(), " version Show details of this binary's current version\n") @@ -48,7 +51,7 @@ func main() { // Set up 'build' subcommand buildCommand := flag.NewFlagSet("build", flag.ExitOnError) - buildBranch := buildCommand.String("branch", currentBranch, "If given, build from this branch.\n"+ + buildBranch := buildCommand.String("branch", currentBranch, "If given, plan from this branch.\n"+ "Defaults to the current branch.") buildTargets := buildCommand.String("target", "", "If given, target these specific Terraform resources only.\n"+ "Delimit multiple target IDs with a semi-colon ';'.") @@ -56,6 +59,13 @@ func main() { // Set up 'cancel' subcommand cancelCommand := flag.NewFlagSet("cancel", flag.ExitOnError) + // Set up 'destroy' subcommand + destroyCommand := flag.NewFlagSet("destroy", flag.ExitOnError) + destroyBranch := destroyCommand.String("branch", currentBranch, "If given, plan from this branch.\n"+ + "Defaults to the current branch.") + destroyTargets := destroyCommand.String("target", "", "If given, target these specific Terraform resources only.\n"+ + "Delimit multiple target IDs with a semi-colon ';'.") + // Set up 'init' subcommand initCommand := flag.NewFlagSet("init", flag.ExitOnError) initCommand.Usage = func() { @@ -91,11 +101,17 @@ func main() { if errParse := buildCommand.Parse(os.Args[2:]); errParse != nil { log.Fatalf("error parsing build flags: %v", errParse) } - stackBuild(*buildBranch, *buildTargets) + stackQueue(*buildBranch, *buildTargets, uint(viper.GetInt("azureDevOps.buildDefID"))) case cancelCommand.Name(): if errParse := cancelCommand.Parse(os.Args[2:]); errParse != nil { log.Fatalf("error parsing cancel flags: %v", errParse) } + case destroyCommand.Name(): + // Parse and execute 'destroy' subcommand + if errParse := destroyCommand.Parse(os.Args[2:]); errParse != nil { + log.Fatalf("error parsing destroy flags: %v", errParse) + } + stackQueue(*destroyBranch, *destroyTargets, uint(viper.GetInt("azureDevOps.destroyDefID"))) case initCommand.Name(): // Execute on 'init' subcommand initStack() diff --git a/cmd/stack/build.go b/cmd/stack/queue.go similarity index 90% rename from cmd/stack/build.go rename to cmd/stack/queue.go index 54be92c..ac5eb11 100644 --- a/cmd/stack/build.go +++ b/cmd/stack/queue.go @@ -1,12 +1,5 @@ package main -// build flow: -// 0.1. count unpushed commits and warn if > 0 -// 1. get stack path -// 2. build POST payload using parameters -// 3. send request to API -// 4. print URL of build from API result - import ( "fmt" "log" @@ -26,7 +19,14 @@ const yeahNah = ` ! / ______|\___ >____ /___| / \____|__ (____ /___| / ! \/ \/ \/ \/ \/ \/ \/` -func stackBuild(branch, targets string) { +// queue flow: +// 0.1. count unpushed commits and warn if > 0 +// 1. get stack path +// 2. build POST payload using parameters +// 3. send request to API +// 4. print URL of build from API result + +func stackQueue(branch, targets string, defID uint) { // 0.1 unpushedRaw, errExec := exec.Command("git", "rev-list", "--count", "@{u}..").Output() if errExec != nil { @@ -62,7 +62,7 @@ func stackBuild(branch, targets string) { parameters["TerraformTarget"] = targets } - payload, errPayload := common.GetPostPayload(uint(viper.GetInt("azureDevOps.buildDefID")), parameters, branch) + payload, errPayload := common.GetPostPayload(defID, parameters, branch) if errPayload != nil { log.Fatal(errPayload) } @@ -83,5 +83,5 @@ func stackBuild(branch, targets string) { } // 4 - fmt.Println("Build URL:", apiResult) + fmt.Println("Stack (plan) URL:", apiResult) } diff --git a/stack.config.example.json b/stack.config.example.json index 95bff86..e5e1def 100644 --- a/stack.config.example.json +++ b/stack.config.example.json @@ -13,8 +13,9 @@ }, "azureDevOps": { "buildDefID": 5, + "destroyDefID": 6, "org": "MyAzureDevOpsOrg", - "pat": "<52 character alphanumeric, generated here: https://dev.azure.com/$org/_usersSettings/tokens>", + "pat": "<52 character alphanumeric, generated here: https://dev.azure.com//_usersSettings/tokens>", "project": "MyAzureDevOpsProject" }, "github": {