diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..7051f2a --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,25 @@ +name: Lint + +on: [push] + +jobs: + lint: + name: Lint the code + runs-on: ubuntu-latest + container: golang:1.16 + + steps: + - name: Check out repository code + uses: actions/checkout@master + + - name: Check formatting using gofmt + run: gofmt -s -l -d . + + - name: Check for suspicious constructs using "go vet" + run: go vet ./... + + - name: Lint the code using "golint" + run: go get -u golang.org/x/lint/golint && golint -set_exit_status ./... + + - name: Run staticcheck + run: go get -u honnef.co/go/tools/cmd/staticcheck && staticcheck ./... diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..7ee6b73 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,36 @@ +name: Release + +on: + push: { tags: ["v*"] } + +jobs: + release: + name: Release new version + runs-on: ubuntu-latest + container: golang:1.16 + + steps: + - name: Check out repository code + uses: actions/checkout@master + + - name: Build release + run: make release + + - name: Release + uses: docker://antonyurchenko/git-release:latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DRAFT_RELEASE: "true" + PRE_RELEASE: "false" + CHANGELOG_FILE: "none" + ALLOW_EMPTY_CHANGELOG: "true" + ALLOW_TAG_PREFIX: "true" + RELEASE_NAME_PREFIX: "Release " + with: + args: | + ./build/spacelift-cli-darwin-amd64.tar.gz + ./build/spacelift-cli-darwin-arm64.tar.gz + ./build/spacelift-cli-linux-amd64.tar.gz + ./build/spacelift-cli-linux-arm64.tar.gz + ./build/spacelift-cli-windows-amd64.tar.gz + ./LICENSE diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..d99051c --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,48 @@ +name: Security + +on: + push: { branches: [main] } + pull_request: { branches: [main] } + schedule: + - cron: "19 7 * * 0" + +jobs: + codeql: + name: Analyze + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: "go" + + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 + + + gosec: + name: GoSec + runs-on: ubuntu-latest + env: + GO111MODULE: on + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Run GoSec Security Scanner + uses: securego/gosec@master + with: + args: "-severity=medium -no-fail -fmt sarif -out gosec-results.sarif ./..." + + - name: Upload GoSec scan results to GitHub Security tab + uses: github/codeql-action/upload-sarif@v1 + with: + sarif_file: "gosec-results.sarif" diff --git a/.gitignore b/.gitignore index 2fcad80..f9db24c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ spacelift-cli # Output of the go coverage tool, specifically when used with LiteIDE *.out +build diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1eba296 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +BINARY := spacelift-cli +PKG := github.com/spacelift-io/spacelift-cli/cmd +BUILD_FLAGS := -a -tags netgo -ldflags '-w -extldflags "-static"' + +darwin: + env GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build $(BUILD_FLAGS) -o build/$(BINARY)-darwin-amd64 $(PKG) + env GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build $(BUILD_FLAGS) -o build/$(BINARY)-darwin-arm64 $(PKG) + +linux: + env GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build $(BUILD_FLAGS) -o build/$(BINARY)-linux-amd64 $(PKG) + env GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build $(BUILD_FLAGS) -o build/$(BINARY)-linux-arm64 $(PKG) + +windows: + env GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build $(BUILD_FLAGS) -o build/$(BINARY)-windows-amd64 $(PKG) + +build: darwin linux windows + +release: build + cd build; tar -czf $(BINARY)-darwin-amd64.tar.gz $(BINARY)-darwin-amd64 + cd build; tar -czf $(BINARY)-darwin-arm64.tar.gz $(BINARY)-darwin-arm64 + cd build; tar -czf $(BINARY)-linux-amd64.tar.gz $(BINARY)-linux-amd64 + cd build; tar -czf $(BINARY)-linux-arm64.tar.gz $(BINARY)-linux-amd64 + cd build; tar -czf $(BINARY)-windows-amd64.tar.gz $(BINARY)-windows-amd64 + +clean: + go clean + rm -rf build/$(BINARY)* diff --git a/client/interface.go b/client/interface.go index eb73c47..b766351 100644 --- a/client/interface.go +++ b/client/interface.go @@ -2,6 +2,7 @@ package client import "context" +// Client abstracts away Spacelift's client API. type Client interface { // Query executes a single GraphQL query request. Query(context.Context, interface{}, map[string]interface{}) error diff --git a/client/session/api_key.go b/client/session/api_key.go index 7b81295..b448da4 100644 --- a/client/session/api_key.go +++ b/client/session/api_key.go @@ -9,6 +9,8 @@ import ( "github.com/shurcooL/graphql" ) +// FromAPIKey builds a Spacelift session from a combination of endpoint, API key +// ID and API key secret. func FromAPIKey(ctx context.Context, client *http.Client) func(string, string, string) (Session, error) { return func(endpoint, keyID, keySecret string) (Session, error) { out := &apiKey{ diff --git a/client/session/github_token.go b/client/session/github_token.go index 6d36cfb..d77b2ec 100644 --- a/client/session/github_token.go +++ b/client/session/github_token.go @@ -9,6 +9,8 @@ import ( "github.com/shurcooL/graphql" ) +// FromGitHubToken builds a Spacelift session from a combination of endpoint, +// and a GitHub access token. func FromGitHubToken(ctx context.Context, client *http.Client) func(string, string) (Session, error) { return func(endpoint, accessToken string) (Session, error) { out := &gitHubToken{ diff --git a/client/session/stored_credentials.go b/client/session/stored_credentials.go index d465a77..dd4cf4c 100644 --- a/client/session/stored_credentials.go +++ b/client/session/stored_credentials.go @@ -6,6 +6,7 @@ import ( "net/http" ) +// CredentialsType represents the type of credentials being used. type CredentialsType uint const ( @@ -31,6 +32,7 @@ type StoredCredentials struct { KeySecret string `json:"key_secret,omitempty"` } +// Session creates a Spacelift Session from stored credentials. func (s *StoredCredentials) Session(ctx context.Context, client *http.Client) (Session, error) { switch s.Type { case CredentialsTypeAPIKey: diff --git a/client/structs/run_state_transition.go b/client/structs/run_state_transition.go index 594fe21..619fe93 100644 --- a/client/structs/run_state_transition.go +++ b/client/structs/run_state_transition.go @@ -16,6 +16,7 @@ type RunStateTransition struct { Username *string `graphql:"username"` } +// About returns "header" information about the state transition. func (r *RunStateTransition) About() string { parts := []string{ string(r.State), diff --git a/client/structs/run_type.go b/client/structs/run_type.go index 43c6361..f95c868 100644 --- a/client/structs/run_type.go +++ b/client/structs/run_type.go @@ -3,6 +3,7 @@ package structs // RunType is the type of the run. type RunType string +// NewRunType takes a string and returns a pointer to a RunType. func NewRunType(in string) *RunType { out := RunType(in) return &out diff --git a/cmd/internal/account/account.go b/cmd/internal/account/account.go index b382801..c53d9a0 100644 --- a/cmd/internal/account/account.go +++ b/cmd/internal/account/account.go @@ -2,6 +2,7 @@ package account import "github.com/urfave/cli/v2" +// Command encapsulates the account command subtree. func Command() *cli.Command { return &cli.Command{ Name: "account", diff --git a/cmd/internal/stack/stack.go b/cmd/internal/stack/stack.go index 83786e4..51356f2 100644 --- a/cmd/internal/stack/stack.go +++ b/cmd/internal/stack/stack.go @@ -9,6 +9,7 @@ import ( "github.com/spacelift-io/spacelift-cli/cmd/internal/authenticated" ) +// Command encapsulates the stack command subtree. func Command() *cli.Command { return &cli.Command{ Name: "stack",