-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from konstructio/improve-current-flow
Improve and allow extendability of current CLI.
- Loading branch information
Showing
23 changed files
with
1,421 additions
and
234 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
name: Go unit tests | ||
|
||
on: [push, workflow_dispatch] | ||
|
||
permissions: | ||
checks: write | ||
contents: read | ||
|
||
jobs: | ||
run-tests: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Clone repository | ||
uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
- name: Set up Go | ||
uses: actions/setup-go@v5 | ||
with: | ||
go-version-file: go.mod | ||
- name: Run GolangCI-Lint | ||
uses: golangci/golangci-lint-action@v6 | ||
with: | ||
version: v1.59 | ||
- name: Test application | ||
run: go test -short -v ./... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ tmp/ | |
.vscode | ||
.DS_STORE | ||
dist/ | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
run: | ||
tests: false | ||
concurrency: 5 | ||
timeout: 3m | ||
|
||
linters: | ||
disable-all: true | ||
enable: | ||
- gosimple | ||
- govet | ||
- ineffassign | ||
- staticcheck | ||
- unused | ||
- asasalint | ||
- asciicheck | ||
- bidichk | ||
- bodyclose | ||
- contextcheck | ||
- decorder | ||
- dogsled | ||
- dupl | ||
- dupword | ||
- durationcheck | ||
- errchkjson | ||
- errname | ||
- errorlint | ||
- exhaustive | ||
- exportloopref | ||
- forcetypeassert | ||
- ginkgolinter | ||
- gocheckcompilerdirectives | ||
- gochecksumtype | ||
- gocritic | ||
- gocyclo | ||
- gofmt | ||
- gofumpt | ||
- goheader | ||
- goimports | ||
- gomodguard | ||
- goprintffuncname | ||
- gosec | ||
- gosmopolitan | ||
- grouper | ||
- importas | ||
- inamedparam | ||
- interfacebloat | ||
- ireturn | ||
- loggercheck | ||
- makezero | ||
- mirror | ||
- misspell | ||
- musttag | ||
- nakedret | ||
- nilerr | ||
- nilnil | ||
- noctx | ||
- nolintlint | ||
- nonamedreturns | ||
- nosprintfhostport | ||
- paralleltest | ||
- perfsprint | ||
- prealloc | ||
- predeclared | ||
- promlinter | ||
- protogetter | ||
- reassign | ||
- revive | ||
- rowserrcheck | ||
- sloglint | ||
- spancheck | ||
- sqlclosecheck | ||
- stylecheck | ||
- tenv | ||
- testableexamples | ||
- testifylint | ||
- testpackage | ||
- thelper | ||
- tparallel | ||
- unconvert | ||
- unparam | ||
- usestdlibvars | ||
- wastedassign | ||
- whitespace | ||
- wrapcheck | ||
- zerologlint | ||
|
||
linters-settings: | ||
perfsprint: | ||
int-conversion: false | ||
err-error: false | ||
errorf: true | ||
sprintf1: true | ||
strconcat: false | ||
|
||
ireturn: | ||
allow: | ||
- ssh.PublicKey | ||
- tea.Model | ||
- error | ||
|
||
gosec: | ||
confidence: medium | ||
excludes: | ||
- G107 # Potential HTTP request made with variable url: these are often false positives or intentional | ||
- G110 # Decompression bombs: we can check these manually when submitting code | ||
- G306 # Poor file permissions used when creating a directory: we can check these manually when submitting code | ||
- G404 # Use of weak random number generator (math/rand instead of crypto/rand): we can live with these | ||
|
||
stylecheck: | ||
checks: | ||
- "all" | ||
- "-ST1003" # this is covered by a different linter | ||
|
||
gocyclo: | ||
min-complexity: 60 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,88 @@ | ||
package cmd | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"os" | ||
|
||
"github.com/konstructio/dropkick/internal/civo" | ||
"github.com/konstructio/dropkick/internal/logger" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var CivoCmdOptions *civo.CivoCmdOptions = &civo.CivoCmdOptions{} | ||
func getCivoCommand() *cobra.Command { | ||
var ( | ||
nuke bool | ||
region string | ||
) | ||
|
||
var civoCmd = &cobra.Command{ | ||
Use: "civo", | ||
Short: "clean civo resources", | ||
Long: `clean civo resources`, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
civoCmd := &cobra.Command{ | ||
Use: "civo", | ||
Short: "clean civo resources", | ||
Long: `clean civo resources`, | ||
RunE: func(cmd *cobra.Command, _ []string) error { | ||
quiet := cmd.Flags().Lookup("quiet").Value.String() == "true" | ||
return runCivo(cmd.OutOrStderr(), region, os.Getenv("CIVO_TOKEN"), nuke, quiet) | ||
}, | ||
} | ||
|
||
if os.Getenv("CIVO_TOKEN") == "" { | ||
log.Fatal("no civoCmd token present") | ||
} | ||
civoCmd.Flags().BoolVar(&nuke, "nuke", false, "required to confirm deletion of resources") | ||
civoCmd.Flags().StringVar(®ion, "region", "", "the civo region to clean") | ||
err := civoCmd.MarkFlagRequired("region") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
civoConf := civo.CivoConfiguration{ | ||
Client: civo.NewClient(os.Getenv("CIVO_TOKEN"), CivoCmdOptions.Region), | ||
Context: context.Background(), | ||
} | ||
return civoCmd | ||
} | ||
|
||
err := civoConf.NukeKubernetesClusters(CivoCmdOptions) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
func runCivo(output io.Writer, region, token string, nuke, quiet bool) error { | ||
if token == "" { | ||
return errors.New("required environment variable $CIVO_TOKEN not found") | ||
} | ||
|
||
err = civoConf.NukeObjectStores(CivoCmdOptions) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
// Create a logger and make it quiet | ||
var log *logger.Logger | ||
if quiet { | ||
log = logger.New(io.Discard) | ||
} else { | ||
log = logger.New(output) | ||
} | ||
|
||
err = civoConf.NukeObjectStoreCredentials(CivoCmdOptions) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
client, err := civo.New( | ||
civo.WithToken(token), | ||
civo.WithRegion(region), | ||
civo.WithNuke(nuke), | ||
civo.WithLogger(log), | ||
) | ||
if err != nil { | ||
return fmt.Errorf("unable to create new client: %w", err) | ||
} | ||
|
||
err = civoConf.NukeVolumes(CivoCmdOptions) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
if err := client.NukeKubernetesClusters(); err != nil { | ||
return fmt.Errorf("unable to cleanup Kubernetes clusters: %w", err) | ||
} | ||
|
||
err = civoConf.NukeNetworks(CivoCmdOptions) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
}, | ||
} | ||
if err := client.NukeObjectStores(); err != nil { | ||
return fmt.Errorf("unable to cleanup object stores: %w", err) | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(civoCmd) | ||
civoCmd.Flags().BoolVar(&CivoCmdOptions.Nuke, "nuke", CivoCmdOptions.Nuke, "required to confirm deletion of resources") | ||
err = client.NukeObjectStoreCredentials() | ||
if err != nil { | ||
return fmt.Errorf("unable to cleanup object store credentials: %w", err) | ||
} | ||
|
||
civoCmd.Flags().StringVar(&CivoCmdOptions.Region, "region", CivoCmdOptions.Region, "the civo region to clean") | ||
err := civoCmd.MarkFlagRequired("region") | ||
err = client.NukeVolumes() | ||
if err != nil { | ||
log.Fatal(err) | ||
return fmt.Errorf("unable to cleanup volumes: %w", err) | ||
} | ||
|
||
err = client.NukeNetworks() | ||
if err != nil { | ||
return fmt.Errorf("unable to cleanup networks: %w", err) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package cmd | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"io" | ||
|
||
"github.com/konstructio/dropkick/internal/digitalocean" | ||
"github.com/konstructio/dropkick/internal/logger" | ||
"github.com/konstructio/dropkick/pkg/env" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type doOptions struct { | ||
nuke bool | ||
token string | ||
spacesAccessKey string | ||
spacesSecretKey string | ||
spacesRegion string | ||
} | ||
|
||
func getDigitalOceanCommand() *cobra.Command { | ||
var opts doOptions | ||
|
||
cmd := &cobra.Command{ | ||
Use: "digitalocean", | ||
Short: "clean digitalocean resources", | ||
Long: `clean digitalocean resources`, | ||
RunE: func(cmd *cobra.Command, _ []string) error { | ||
opts.token = env.GetFirstNotEmpty("DIGITALOCEAN_TOKEN") | ||
opts.spacesAccessKey = env.GetFirstNotEmpty("DIGITALOCEAN_SPACES_ACCESS_KEY", "SPACES_KEY") | ||
opts.spacesSecretKey = env.GetFirstNotEmpty("DIGITALOCEAN_SPACES_SECRET_KEY", "SPACES_SECRET") | ||
opts.spacesRegion = env.GetFirstNotEmpty("DIGITALOCEAN_SPACES_REGION", "SPACES_REGION") | ||
quiet := cmd.Flags().Lookup("quiet").Value.String() == "true" | ||
return runDigitalOcean(cmd.OutOrStderr(), opts, quiet) | ||
}, | ||
} | ||
|
||
cmd.Flags().BoolVar(&opts.nuke, "nuke", false, "required to confirm deletion of resources") | ||
return cmd | ||
} | ||
|
||
func runDigitalOcean(output io.Writer, opts doOptions, quiet bool) error { | ||
// Check token | ||
if opts.token == "" { | ||
return errors.New("required environment variable $DIGITALOCEAN_TOKEN not set") | ||
} | ||
|
||
// Check spaces credentials | ||
if opts.spacesAccessKey == "" { | ||
return errors.New("required environment variable $DIGITALOCEAN_SPACES_ACCESS_KEY or $SPACES_KEY not set") | ||
} | ||
if opts.spacesSecretKey == "" { | ||
return errors.New("required environment variable $DIGITALOCEAN_SPACES_SECRET_KEY or $SPACES_SECRET not set") | ||
} | ||
if opts.spacesRegion == "" { | ||
return errors.New("required environment variable $DIGITALOCEAN_SPACES_REGION or $SPACES_REGION not set") | ||
} | ||
|
||
// Create a logger and make it quiet | ||
var log *logger.Logger | ||
if quiet { | ||
log = logger.New(io.Discard) | ||
} else { | ||
log = logger.New(output) | ||
} | ||
|
||
// Create DigitalOcean client | ||
client, err := digitalocean.New( | ||
digitalocean.WithToken(opts.token), | ||
digitalocean.WithS3Storage(opts.spacesAccessKey, opts.spacesSecretKey, opts.spacesRegion), | ||
digitalocean.WithNuke(opts.nuke), | ||
digitalocean.WithContext(context.Background()), | ||
digitalocean.WithLogger(log), | ||
) | ||
if err != nil { | ||
return fmt.Errorf("unable to create new client: %w", err) | ||
} | ||
|
||
// Cleanup resources | ||
if err := client.NukeKubernetesClusters(); err != nil { | ||
return fmt.Errorf("unable to cleanup Kubernetes clusters: %w", err) | ||
} | ||
|
||
if err := client.NukeS3Storage(); err != nil { | ||
return fmt.Errorf("unable to cleanup spaces storage: %w", err) | ||
} | ||
|
||
if err := client.NukeVolumes(); err != nil { | ||
return fmt.Errorf("unable to cleanup volumes: %w", err) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.