diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33613e8d..259b5679 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,9 +35,10 @@ jobs: touch internal/config/embedded-config.yaml - name: Run linter - uses: golangci/golangci-lint-action@v6 + uses: golangci/golangci-lint-action@v8 with: - version: v1.64 + version: v2.4 + args: --timeout=5m - name: Run tests run: make test diff --git a/.golangci.yml b/.golangci.yml index 88693540..48e27814 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,142 +1,75 @@ -linters-settings: - errcheck: - # report about not checking of errors in type assertions: `a := b.(MyStruct)`; - # default is false: such cases aren't reported by default. - check-type-assertions: true - goconst: - # minimal occurrences count to trigger, 3 by default - min-occurrences: 5 - gocritic: - # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks. - # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". - enabled-tags: - - diagnostic - - experimental - - opinionated - - performance - - style - disabled-checks: - - whyNoLint - - emptyStringTest - goimports: - # put imports beginning with prefix after 3rd-party packages; - # it's a comma-separated list of prefixes - local-prefixes: github.com/platformsh/cli - lll: - # max line length, lines longer will be reported. Default is 120. - # '\t' is counted as 1 character by default, and can be changed with the tab-width option - line-length: 120 - misspell: - # Correct spellings using locale preferences for US or UK. - # Default is to use a neutral variety of English. - # Setting locale to US will correct the British spelling of 'colour' to 'color'. - locale: US - nolintlint: - # Enable to ensure that nolint directives are all used. Default is true. - allow-unused: false - # Require to specify linter that is being skipped. Default is false - require-specific: true - prealloc: - # Report preallocation suggestions on for loops, false by default - for-loops: true - +version: "2" linters: - # please, do not use `enable-all`: it's deprecated and will be removed soon. - # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint - disable-all: true + default: none enable: - # Simple linter to check that your code does not contain non-ASCII identifiers - # - asciicheck - # checks whether HTTP response body is closed successfully - bodyclose - # Checks assignments with too many blank identifiers (e.g. x, , , _, := f()) - dogsled - # Tool for code clone detection - # - dupl - # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases - errcheck - # Tool for detection of long functions - # - funlen - # Checks that no globals are present in Go code - # - gochecknoglobals - # Checks that no init functions are present in Go code - # - gochecknoinits - # Computes and checks the cognitive complexity of functions - # - gocognit - # Finds repeated strings that could be replaced by a constant - goconst - # The most opinionated Go source code linter - gocritic - # Computes and checks the cyclomatic complexity of functions - # - gocyclo - # Check if comments end in a period - # - godot - # Tool for detection of FIXME, TODO and other comment keywords - # - godox - # Golang linter to check the errors handling expressions - # - goerr113 - # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification - - gofmt - # Goimports does everything that gofmt does. Additionally, it checks unused imports - - goimports - # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes - - revive - # An analyzer to detect magic numbers. - # - gomnd - # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. - # - gomodguard - # Checks that printf-like functions are named with f at the end - goprintffuncname - # Inspects source code for security problems - gosec - # Linter for Go source code that specializes in simplifying a code - - gosimple - # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string - govet - # Detects when assignments to existing variables are not used - ineffassign - # Linter that suggests narrower interface types - # - interfacer - # Reports long lines - lll - # Tool to detect Go structs that would take less memory if their fields were sorted - # - maligned - # Finds commonly misspelled English words in comments - misspell - # (?) Finds naked returns in functions greater than a specified function length - nakedret - # Reports deeply nested if statements - # - nestif - # Reports ill-formed or insufficient nolint directives - nolintlint - # Finds slice declarations that could potentially be preallocated - prealloc - # Find code that shadows one of Go's predeclared identifiers. - predeclared - # checks whether Err of rows is checked successfully - # rowserrcheck is disabled because of generics. See https://github.com/golangci/golangci-lint/issues/2649. - # - rowserrcheck - # Scopelint checks for unpinned variables in go programs - # - scopelint - # Staticcheck is a go vet on steroids, applying a ton of static analysis checks + - revive - staticcheck - # Stylecheck is a replacement for golint - - stylecheck - # linter that makes you use a separate _test package - # - testpackage - # Like the front-end of a Go compiler, parses and type-checks Go code - - typecheck - # Remove unnecessary type conversions - unconvert - # (?) Reports unused function parameters - # - unparam - # Checks Go code for unused constants, variables, functions and types - unused - # Tool for detection of leading and trailing whitespace - whitespace - # Whitespace Linter - Forces you to use empty lines! - # - wsl - -issues: - exclude-dirs: - - vendor + settings: + errcheck: + check-type-assertions: true + goconst: + min-occurrences: 5 + gocritic: + disabled-checks: + - whyNoLint + - emptyStringTest + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + lll: + line-length: 120 + misspell: + locale: US + nolintlint: + require-specific: true + allow-unused: false + prealloc: + for-loops: true + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - vendor + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - goimports + settings: + goimports: + local-prefixes: + - github.com/platformsh/cli + exclusions: + generated: lax + paths: + - vendor + - third_party$ + - builtin$ + - examples$ diff --git a/Makefile b/Makefile index 13401614..43cbe0c1 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,6 @@ VERSION := $(shell git describe --always) # Tooling versions GORELEASER_VERSION=v1.26 -GOLANGCI_LINT_VERSION=v1.64 internal/legacy/archives/platform.phar: curl -L https://github.com/platformsh/legacy-cli/releases/download/v$(LEGACY_CLI_VERSION)/platform.phar -o internal/legacy/archives/platform.phar @@ -93,12 +92,9 @@ test: ## Run unit tests go clean -testcache go test -v -race -mod=readonly -cover ./... -golangci-lint: - command -v golangci-lint >/dev/null || go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) - .PHONY: lint -lint: golangci-lint ## Run linter - golangci-lint run --timeout=10m --verbose +lint: ## Run linter + golangci-lint run --timeout=5m --verbose .goreleaser.vendor.yaml: check-vendor ## Generate the goreleaser vendor config cat .goreleaser.vendor.yaml.tpl | envsubst > .goreleaser.vendor.yaml diff --git a/internal/config/alt/alt.go b/internal/config/alt/alt.go index ab132bf7..c62398de 100644 --- a/internal/config/alt/alt.go +++ b/internal/config/alt/alt.go @@ -43,7 +43,7 @@ func (a *Alt) GenerateAndSave() error { } func (a *Alt) generateExecutable() string { - if runtime.GOOS == "windows" { //nolint:goconst + if runtime.GOOS == "windows" { return ":: " + a.comment + "\r\n" + "@echo off\r\n" + "setlocal\r\n" + diff --git a/internal/config/alt/fetch.go b/internal/config/alt/fetch.go index fccb3d9d..0185e073 100644 --- a/internal/config/alt/fetch.go +++ b/internal/config/alt/fetch.go @@ -19,6 +19,8 @@ import ( // needing to know the whole schema, and to preserve comments. A comment and some // metadata are added to the cnfNode. A "cnfStruct" is also returned to allow // reading some keys. +// +//nolint:gocritic // The "importShadow" rule complains about the url parameter. func FetchConfig(ctx context.Context, url string) (cnfNode *yaml.Node, cnfStruct *config.Config, err error) { if err := validateConfigURL(url); err != nil { return nil, nil, err diff --git a/internal/config/alt/fs_test.go b/internal/config/alt/fs_test.go index caeeec71..0ec9aecc 100644 --- a/internal/config/alt/fs_test.go +++ b/internal/config/alt/fs_test.go @@ -15,7 +15,7 @@ func TestFindConfigDir(t *testing.T) { t.Run("XDG_CONFIG_HOME exists", func(t *testing.T) { switch runtime.GOOS { - case "windows", "darwin", "ios", "plan9": + case "windows", "darwin", "ios", "plan9": //nolint:goconst t.Skip() } err := os.Setenv("XDG_CONFIG_HOME", tempDir) diff --git a/pkg/mockapi/activities.go b/pkg/mockapi/activities.go index 3587b658..68b349ef 100644 --- a/pkg/mockapi/activities.go +++ b/pkg/mockapi/activities.go @@ -9,11 +9,11 @@ import ( ) func (h *Handler) handleListProjectActivities(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") - var activities = make([]*Activity, 0, len(h.store.activities[projectID])) - for _, a := range h.store.activities[projectID] { + var activities = make([]*Activity, 0, len(h.activities[projectID])) + for _, a := range h.activities[projectID] { activities = append(activities, a) } // Sort activities in descending order by created date. @@ -22,11 +22,11 @@ func (h *Handler) handleListProjectActivities(w http.ResponseWriter, req *http.R } func (h *Handler) handleGetProjectActivity(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") activityID := chi.URLParam(req, "id") - if projectActivities := h.store.activities[projectID]; projectActivities != nil { + if projectActivities := h.activities[projectID]; projectActivities != nil { _ = json.NewEncoder(w).Encode(projectActivities[activityID]) return } @@ -34,12 +34,12 @@ func (h *Handler) handleGetProjectActivity(w http.ResponseWriter, req *http.Requ } func (h *Handler) handleListEnvironmentActivities(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") environmentID := chi.URLParam(req, "environment_id") - var activities = make([]*Activity, 0, len(h.store.activities[projectID])) - for _, a := range h.store.activities[projectID] { + var activities = make([]*Activity, 0, len(h.activities[projectID])) + for _, a := range h.activities[projectID] { if slices.Contains(a.Environments, environmentID) { activities = append(activities, a) } @@ -50,11 +50,11 @@ func (h *Handler) handleListEnvironmentActivities(w http.ResponseWriter, req *ht } func (h *Handler) handleGetEnvironmentActivity(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") activityID := chi.URLParam(req, "id") - if projectActivities := h.store.activities[projectID]; projectActivities != nil { + if projectActivities := h.activities[projectID]; projectActivities != nil { environmentID := chi.URLParam(req, "environment_id") a := projectActivities[activityID] if a == nil || !slices.Contains(a.Environments, environmentID) { diff --git a/pkg/mockapi/api_server.go b/pkg/mockapi/api_server.go index 66bdc0c9..a054f1c2 100644 --- a/pkg/mockapi/api_server.go +++ b/pkg/mockapi/api_server.go @@ -25,10 +25,10 @@ func NewHandler(t *testing.T) *Handler { h.Mux = chi.NewRouter() if testing.Verbose() { - h.Mux.Use(middleware.DefaultLogger) + h.Use(middleware.DefaultLogger) } - h.Mux.Use(func(next http.Handler) http.Handler { + h.Use(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { authHeader := req.Header.Get("Authorization") require.NotEmpty(t, authHeader) @@ -37,64 +37,64 @@ func NewHandler(t *testing.T) *Handler { }) }) - h.Mux.Get("/users/me", h.handleUsersMe) - h.Mux.Get("/users/{user_id}/extended-access", h.handleUserExtendedAccess) - h.Mux.Get("/ref/users", h.handleUserRefs) - h.Mux.Post("/me/verification", func(w http.ResponseWriter, _ *http.Request) { + h.Get("/users/me", h.handleUsersMe) + h.Get("/users/{user_id}/extended-access", h.handleUserExtendedAccess) + h.Get("/ref/users", h.handleUserRefs) + h.Post("/me/verification", func(w http.ResponseWriter, _ *http.Request) { _ = json.NewEncoder(w).Encode(map[string]any{"state": false, "type": ""}) }) - h.Mux.Get("/organizations", h.handleListOrgs) - h.Mux.Post("/organizations", h.handleCreateOrg) - h.Mux.Get("/organizations/{organization_id}", h.handleGetOrg) - h.Mux.Patch("/organizations/{organization_id}", h.handlePatchOrg) - h.Mux.Get("/users/{user_id}/organizations", h.handleListOrgs) - h.Mux.Get("/ref/organizations", h.handleOrgRefs) - - h.Mux.Post("/organizations/{organization_id}/subscriptions", h.handleCreateSubscription) - h.Mux.Get("/subscriptions/{subscription_id}", h.handleGetSubscription) - h.Mux.Get("/organizations/{organization_id}/subscriptions/{subscription_id}", h.handleGetSubscription) - h.Mux.Get("/organizations/{organization_id}/subscriptions/can-create", h.handleCanCreateSubscriptions) - h.Mux.Get("/organizations/{organization_id}/setup/options", func(w http.ResponseWriter, _ *http.Request) { + h.Get("/organizations", h.handleListOrgs) + h.Post("/organizations", h.handleCreateOrg) + h.Get("/organizations/{organization_id}", h.handleGetOrg) + h.Patch("/organizations/{organization_id}", h.handlePatchOrg) + h.Get("/users/{user_id}/organizations", h.handleListOrgs) + h.Get("/ref/organizations", h.handleOrgRefs) + + h.Post("/organizations/{organization_id}/subscriptions", h.handleCreateSubscription) + h.Get("/subscriptions/{subscription_id}", h.handleGetSubscription) + h.Get("/organizations/{organization_id}/subscriptions/{subscription_id}", h.handleGetSubscription) + h.Get("/organizations/{organization_id}/subscriptions/can-create", h.handleCanCreateSubscriptions) + h.Get("/organizations/{organization_id}/setup/options", func(w http.ResponseWriter, _ *http.Request) { type options struct { Plans []string `json:"plans"` Regions []string `json:"regions"` } _ = json.NewEncoder(w).Encode(options{[]string{"development"}, []string{"test-region"}}) }) - h.Mux.Get("/organizations/{organization_id}/subscriptions/estimate", func(w http.ResponseWriter, _ *http.Request) { + h.Get("/organizations/{organization_id}/subscriptions/estimate", func(w http.ResponseWriter, _ *http.Request) { _ = json.NewEncoder(w).Encode(map[string]any{"total": "$1,000 USD"}) }) - h.Mux.Get("/projects/{project_id}", h.handleGetProject) - h.Mux.Patch("/projects/{project_id}", h.handlePatchProject) - h.Mux.Get("/projects/{project_id}/environments", h.handleListEnvironments) - h.Mux.Get("/projects/{project_id}/environments/{environment_id}", h.handleGetEnvironment) - h.Mux.Patch("/projects/{project_id}/environments/{environment_id}", h.handlePatchEnvironment) - h.Mux.Get("/projects/{project_id}/environments/{environment_id}/settings", h.handleGetEnvironmentSettings) - h.Mux.Patch("/projects/{project_id}/environments/{environment_id}/settings", h.handleSetEnvironmentSettings) - h.Mux.Post("/projects/{project_id}/environments/{environment_id}/deploy", h.handleDeployEnvironment) - h.Mux.Get("/projects/{project_id}/environments/{environment_id}/backups", h.handleListBackups) - h.Mux.Post("/projects/{project_id}/environments/{environment_id}/backups", h.handleCreateBackup) - h.Mux.Get("/projects/{project_id}/environments/{environment_id}/deployments/current", h.handleGetCurrentDeployment) - h.Mux.Get("/projects/{project_id}/user-access", h.handleProjectUserAccess) - h.Mux.Get("/ref/projects", h.handleProjectRefs) - - h.Mux.Get("/regions", h.handleListRegions) - - h.Mux.Get("/projects/{project_id}/activities", h.handleListProjectActivities) - h.Mux.Get("/projects/{project_id}/activities/{id}", h.handleGetProjectActivity) - h.Mux.Get("/projects/{project_id}/environments/{environment_id}/activities", h.handleListEnvironmentActivities) - h.Mux.Get("/projects/{project_id}/environments/{environment_id}/activities/{id}", h.handleGetEnvironmentActivity) - - h.Mux.Get("/projects/{project_id}/variables", h.handleListProjectVariables) - h.Mux.Post("/projects/{project_id}/variables", h.handleCreateProjectVariable) - h.Mux.Get("/projects/{project_id}/variables/{name}", h.handleGetProjectVariable) - h.Mux.Patch("/projects/{project_id}/variables/{name}", h.handlePatchProjectVariable) - h.Mux.Get("/projects/{project_id}/environments/{environment_id}/variables", h.handleListEnvLevelVariables) - h.Mux.Post("/projects/{project_id}/environments/{environment_id}/variables", h.handleCreateEnvLevelVariable) - h.Mux.Get("/projects/{project_id}/environments/{environment_id}/variables/{name}", h.handleGetEnvLevelVariable) - h.Mux.Patch("/projects/{project_id}/environments/{environment_id}/variables/{name}", h.handlePatchEnvLevelVariable) + h.Get("/projects/{project_id}", h.handleGetProject) + h.Patch("/projects/{project_id}", h.handlePatchProject) + h.Get("/projects/{project_id}/environments", h.handleListEnvironments) + h.Get("/projects/{project_id}/environments/{environment_id}", h.handleGetEnvironment) + h.Patch("/projects/{project_id}/environments/{environment_id}", h.handlePatchEnvironment) + h.Get("/projects/{project_id}/environments/{environment_id}/settings", h.handleGetEnvironmentSettings) + h.Patch("/projects/{project_id}/environments/{environment_id}/settings", h.handleSetEnvironmentSettings) + h.Post("/projects/{project_id}/environments/{environment_id}/deploy", h.handleDeployEnvironment) + h.Get("/projects/{project_id}/environments/{environment_id}/backups", h.handleListBackups) + h.Post("/projects/{project_id}/environments/{environment_id}/backups", h.handleCreateBackup) + h.Get("/projects/{project_id}/environments/{environment_id}/deployments/current", h.handleGetCurrentDeployment) + h.Get("/projects/{project_id}/user-access", h.handleProjectUserAccess) + h.Get("/ref/projects", h.handleProjectRefs) + + h.Get("/regions", h.handleListRegions) + + h.Get("/projects/{project_id}/activities", h.handleListProjectActivities) + h.Get("/projects/{project_id}/activities/{id}", h.handleGetProjectActivity) + h.Get("/projects/{project_id}/environments/{environment_id}/activities", h.handleListEnvironmentActivities) + h.Get("/projects/{project_id}/environments/{environment_id}/activities/{id}", h.handleGetEnvironmentActivity) + + h.Get("/projects/{project_id}/variables", h.handleListProjectVariables) + h.Post("/projects/{project_id}/variables", h.handleCreateProjectVariable) + h.Get("/projects/{project_id}/variables/{name}", h.handleGetProjectVariable) + h.Patch("/projects/{project_id}/variables/{name}", h.handlePatchProjectVariable) + h.Get("/projects/{project_id}/environments/{environment_id}/variables", h.handleListEnvLevelVariables) + h.Post("/projects/{project_id}/environments/{environment_id}/variables", h.handleCreateEnvLevelVariable) + h.Get("/projects/{project_id}/environments/{environment_id}/variables/{name}", h.handleGetEnvLevelVariable) + h.Patch("/projects/{project_id}/environments/{environment_id}/variables/{name}", h.handlePatchEnvLevelVariable) return h } diff --git a/pkg/mockapi/environments.go b/pkg/mockapi/environments.go index ad388a97..067c82ac 100644 --- a/pkg/mockapi/environments.go +++ b/pkg/mockapi/environments.go @@ -13,11 +13,11 @@ import ( ) func (h *Handler) handleListEnvironments(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") var envs []*Environment - for _, e := range h.store.environments { + for _, e := range h.environments { if e.Project == projectID { envs = append(envs, e) } @@ -26,11 +26,11 @@ func (h *Handler) handleListEnvironments(w http.ResponseWriter, req *http.Reques } func (h *Handler) handleGetEnvironment(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") environmentID := chi.URLParam(req, "environment_id") - for id, e := range h.store.environments { + for id, e := range h.environments { if e.Project == projectID && id == environmentID { _ = json.NewEncoder(w).Encode(e) break @@ -45,8 +45,8 @@ func (h *Handler) handlePatchEnvironment(w http.ResponseWriter, req *http.Reques w.WriteHeader(http.StatusNotFound) return } - h.store.Lock() - defer h.store.Unlock() + h.Lock() + defer h.Unlock() patched := *env err := json.NewDecoder(req.Body).Decode(&patched) @@ -56,7 +56,7 @@ func (h *Handler) handlePatchEnvironment(w http.ResponseWriter, req *http.Reques } patched.UpdatedAt = time.Now() - h.store.environments[patched.ID] = &patched + h.environments[patched.ID] = &patched _ = json.NewEncoder(w).Encode(&patched) } @@ -66,8 +66,8 @@ func (h *Handler) handleGetEnvironmentSettings(w http.ResponseWriter, req *http. w.WriteHeader(http.StatusNotFound) return } - h.store.Lock() - defer h.store.Unlock() + h.Lock() + defer h.Unlock() settings := make(map[string]any) if env.settings != nil { @@ -87,8 +87,8 @@ func (h *Handler) handleSetEnvironmentSettings(w http.ResponseWriter, req *http. w.WriteHeader(http.StatusNotFound) return } - h.store.Lock() - defer h.store.Unlock() + h.Lock() + defer h.Unlock() settings := make(map[string]any) err := json.NewDecoder(req.Body).Decode(&settings) @@ -105,7 +105,7 @@ func (h *Handler) handleSetEnvironmentSettings(w http.ResponseWriter, req *http. "#edit=/projects/"+env.Project+"/environments/"+env.ID+"/settings", ) - h.store.environments[env.ID] = env + h.environments[env.ID] = env _ = json.NewEncoder(w).Encode(map[string]any{ "_embedded": map[string]any{"entity": settings}, }) @@ -124,12 +124,12 @@ func (h *Handler) handleDeployEnvironment(w http.ResponseWriter, req *http.Reque } func (h *Handler) handleGetCurrentDeployment(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") environmentID := chi.URLParam(req, "environment_id") var d *Deployment - for _, e := range h.store.environments { + for _, e := range h.environments { if e.Project == projectID && e.ID == environmentID { d = e.currentDeployment } @@ -162,12 +162,12 @@ func (h *Handler) handleCreateBackup(w http.ResponseWriter, req *http.Request) { } func (h *Handler) handleListBackups(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") environmentID := chi.URLParam(req, "environment_id") var backups []*Backup - if projectBackups, ok := h.store.projectBackups[projectID]; ok { + if projectBackups, ok := h.projectBackups[projectID]; ok { for _, b := range projectBackups { if b.EnvironmentID == environmentID { backups = append(backups, b) diff --git a/pkg/mockapi/orgs.go b/pkg/mockapi/orgs.go index a3077ad0..a9020c1d 100644 --- a/pkg/mockapi/orgs.go +++ b/pkg/mockapi/orgs.go @@ -15,13 +15,13 @@ import ( ) func (h *Handler) handleOrgRefs(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() require.NoError(h.t, req.ParseForm()) ids := strings.Split(req.Form.Get("in"), ",") refs := make(map[string]*OrgRef, len(ids)) for _, id := range ids { - if o, ok := h.store.orgs[id]; ok { + if o, ok := h.orgs[id]; ok { refs[id] = o.AsRef() } else { refs[id] = nil @@ -31,13 +31,13 @@ func (h *Handler) handleOrgRefs(w http.ResponseWriter, req *http.Request) { } func (h *Handler) handleListOrgs(w http.ResponseWriter, _ *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() var ( - orgs = make([]*Org, 0, len(h.store.orgs)) + orgs = make([]*Org, 0, len(h.orgs)) ownerIDs = make(uniqueMap) ) - for _, o := range h.store.orgs { + for _, o := range h.orgs { orgs = append(orgs, o) ownerIDs[o.Owner] = struct{}{} } @@ -52,21 +52,21 @@ func (h *Handler) handleListOrgs(w http.ResponseWriter, _ *http.Request) { } func (h *Handler) handleGetOrg(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() var org *Org orgID := chi.URLParam(req, "organization_id") if strings.HasPrefix(orgID, "name%3D") { name := strings.TrimPrefix(orgID, "name%3D") - for _, o := range h.store.orgs { + for _, o := range h.orgs { if o.Name == name { org = o break } } } else { - org = h.store.orgs[path.Base(req.URL.Path)] + org = h.orgs[path.Base(req.URL.Path)] } if org == nil { @@ -78,33 +78,33 @@ func (h *Handler) handleGetOrg(w http.ResponseWriter, req *http.Request) { } func (h *Handler) handleCreateOrg(w http.ResponseWriter, req *http.Request) { - h.store.Lock() - defer h.store.Unlock() + h.Lock() + defer h.Unlock() var org Org err := json.NewDecoder(req.Body).Decode(&org) if err != nil { w.WriteHeader(http.StatusBadRequest) return } - for _, o := range h.store.orgs { + for _, o := range h.orgs { if o.Name == org.Name { w.WriteHeader(http.StatusConflict) return } } org.ID = ulid.MustNew(ulid.Now(), rand.Reader).String() - org.Owner = h.store.myUser.ID + org.Owner = h.myUser.ID org.Capabilities = []string{} org.Links = MakeHALLinks("self=/organizations/" + url.PathEscape(org.ID)) - h.store.orgs[org.ID] = &org + h.orgs[org.ID] = &org _ = json.NewEncoder(w).Encode(&org) } func (h *Handler) handlePatchOrg(w http.ResponseWriter, req *http.Request) { - h.store.Lock() - defer h.store.Unlock() + h.Lock() + defer h.Unlock() orgID := chi.URLParam(req, "organization_id") - p, ok := h.store.orgs[orgID] + p, ok := h.orgs[orgID] if !ok { w.WriteHeader(http.StatusNotFound) return @@ -115,6 +115,6 @@ func (h *Handler) handlePatchOrg(w http.ResponseWriter, req *http.Request) { w.WriteHeader(http.StatusBadRequest) return } - h.store.orgs[orgID] = &patched + h.orgs[orgID] = &patched _ = json.NewEncoder(w).Encode(&patched) } diff --git a/pkg/mockapi/projects.go b/pkg/mockapi/projects.go index d731eb07..83bd160d 100644 --- a/pkg/mockapi/projects.go +++ b/pkg/mockapi/projects.go @@ -11,13 +11,13 @@ import ( ) func (h *Handler) handleProjectRefs(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() require.NoError(h.t, req.ParseForm()) ids := strings.Split(req.Form.Get("in"), ",") refs := make(map[string]*ProjectRef, len(ids)) for _, id := range ids { - if p, ok := h.store.projects[id]; ok { + if p, ok := h.projects[id]; ok { refs[id] = p.AsRef() } else { refs[id] = nil @@ -27,10 +27,10 @@ func (h *Handler) handleProjectRefs(w http.ResponseWriter, req *http.Request) { } func (h *Handler) handleGetProject(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") - if p, ok := h.store.projects[projectID]; ok { + if p, ok := h.projects[projectID]; ok { _ = json.NewEncoder(w).Encode(p) return } @@ -38,10 +38,10 @@ func (h *Handler) handleGetProject(w http.ResponseWriter, req *http.Request) { } func (h *Handler) handlePatchProject(w http.ResponseWriter, req *http.Request) { - h.store.Lock() - defer h.store.Unlock() + h.Lock() + defer h.Unlock() projectID := chi.URLParam(req, "project_id") - p, ok := h.store.projects[projectID] + p, ok := h.projects[projectID] if !ok { w.WriteHeader(http.StatusNotFound) return @@ -53,7 +53,7 @@ func (h *Handler) handlePatchProject(w http.ResponseWriter, req *http.Request) { return } patched.UpdatedAt = time.Now() - h.store.projects[projectID] = &patched + h.projects[projectID] = &patched _ = json.NewEncoder(w).Encode(&patched) } @@ -76,16 +76,16 @@ func (h *Handler) handleListRegions(w http.ResponseWriter, _ *http.Request) { } func (h *Handler) handleProjectUserAccess(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") require.NoError(h.t, req.ParseForm()) var ( - projectGrants = make([]*ProjectUserGrant, 0, len(h.store.userGrants)) + projectGrants = make([]*ProjectUserGrant, 0, len(h.userGrants)) userIDs = make(uniqueMap) orgIDs = make(uniqueMap) ) - for _, g := range h.store.userGrants { + for _, g := range h.userGrants { if g.ResourceType == "project" && g.ResourceID == projectID { projectGrants = append(projectGrants, &ProjectUserGrant{ ProjectID: g.ResourceID, diff --git a/pkg/mockapi/subscriptions.go b/pkg/mockapi/subscriptions.go index ab701d28..2cca2ffc 100644 --- a/pkg/mockapi/subscriptions.go +++ b/pkg/mockapi/subscriptions.go @@ -31,15 +31,15 @@ func (h *Handler) handleCreateSubscription(w http.ResponseWriter, req *http.Requ Status: "provisioning", } - h.store.Lock() - if h.store.subscriptions == nil { - h.store.subscriptions = make(map[string]*Subscription) + h.Lock() + if h.subscriptions == nil { + h.subscriptions = make(map[string]*Subscription) } - h.store.subscriptions[sub.ID] = &sub - if h.store.projects == nil { - h.store.projects = make(map[string]*Project) + h.subscriptions[sub.ID] = &sub + if h.projects == nil { + h.projects = make(map[string]*Project) } - h.store.projects[projectID] = &Project{ + h.projects[projectID] = &Project{ ID: projectID, Links: MakeHALLinks("self=/projects/" + projectID), Repository: ProjectRepository{URL: projectID + "@git.example.com:" + projectID + ".git"}, @@ -49,16 +49,16 @@ func (h *Handler) handleCreateSubscription(w http.ResponseWriter, req *http.Requ }, Organization: chi.URLParam(req, "organization_id"), } - h.store.Unlock() + h.Unlock() _ = json.NewEncoder(w).Encode(sub) // Imitate "provisioning": wait a little and then activate. go func(subID string, projectID string) { time.Sleep(time.Second * 2) - h.store.Lock() - defer h.store.Unlock() - sub := h.store.subscriptions[subID] + h.Lock() + defer h.Unlock() + sub := h.subscriptions[subID] sub.Status = "active" sub.ProjectID = projectID sub.ProjectUI = "http://console.example.com/projects/" + url.PathEscape(projectID) @@ -66,10 +66,10 @@ func (h *Handler) handleCreateSubscription(w http.ResponseWriter, req *http.Requ } func (h *Handler) handleGetSubscription(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() id := chi.URLParam(req, "subscription_id") - sub := h.store.subscriptions[id] + sub := h.subscriptions[id] if sub == nil { w.WriteHeader(http.StatusNotFound) return @@ -78,10 +78,10 @@ func (h *Handler) handleGetSubscription(w http.ResponseWriter, req *http.Request } func (h *Handler) handleCanCreateSubscriptions(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() id := chi.URLParam(req, "organization_id") - cc := h.store.canCreate[id] + cc := h.canCreate[id] if cc == nil { cc = &CanCreateResponse{CanCreate: true} } diff --git a/pkg/mockapi/users.go b/pkg/mockapi/users.go index 4d27ed6b..a2073010 100644 --- a/pkg/mockapi/users.go +++ b/pkg/mockapi/users.go @@ -10,7 +10,7 @@ import ( ) func (h *Handler) handleUsersMe(w http.ResponseWriter, _ *http.Request) { - _ = json.NewEncoder(w).Encode(h.store.myUser) + _ = json.NewEncoder(w).Encode(h.myUser) } func (h *Handler) handleUserRefs(w http.ResponseWriter, req *http.Request) { @@ -24,17 +24,17 @@ func (h *Handler) handleUserRefs(w http.ResponseWriter, req *http.Request) { } func (h *Handler) handleUserExtendedAccess(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() userID := chi.URLParam(req, "user_id") require.NoError(h.t, req.ParseForm()) require.Equal(h.t, "project", req.Form.Get("filter[resource_type]")) var ( - projectGrants = make([]*UserGrant, 0, len(h.store.userGrants)) + projectGrants = make([]*UserGrant, 0, len(h.userGrants)) projectIDs = make(uniqueMap) orgIDs = make(uniqueMap) ) - for _, g := range h.store.userGrants { + for _, g := range h.userGrants { if g.ResourceType == "project" && g.UserID == userID { projectGrants = append(projectGrants, g) projectIDs[g.ResourceID] = struct{}{} diff --git a/pkg/mockapi/variables.go b/pkg/mockapi/variables.go index 9082eda0..e496e0af 100644 --- a/pkg/mockapi/variables.go +++ b/pkg/mockapi/variables.go @@ -11,21 +11,21 @@ import ( ) func (h *Handler) handleListProjectVariables(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") - variables := h.store.projectVariables[projectID] + variables := h.projectVariables[projectID] // Sort variables in descending order by created date. slices.SortFunc(variables, func(a, b *Variable) int { return -timeCompare(a.CreatedAt, b.CreatedAt) }) _ = json.NewEncoder(w).Encode(variables) } func (h *Handler) handleGetProjectVariable(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") variableName, _ := url.PathUnescape(chi.URLParam(req, "name")) - for _, v := range h.store.projectVariables[projectID] { + for _, v := range h.projectVariables[projectID] { if variableName == v.Name { _ = json.NewEncoder(w).Encode(v) return @@ -35,8 +35,8 @@ func (h *Handler) handleGetProjectVariable(w http.ResponseWriter, req *http.Requ } func (h *Handler) handleCreateProjectVariable(w http.ResponseWriter, req *http.Request) { - h.store.Lock() - defer h.store.Unlock() + h.Lock() + defer h.Unlock() projectID := chi.URLParam(req, "project_id") @@ -52,17 +52,17 @@ func (h *Handler) handleCreateProjectVariable(w http.ResponseWriter, req *http.R "#edit=/projects/"+projectID+"/variables/"+newVar.Name, ) - for _, v := range h.store.projectVariables[projectID] { + for _, v := range h.projectVariables[projectID] { if newVar.Name == v.Name { w.WriteHeader(http.StatusConflict) return } } - if h.store.projectVariables[projectID] == nil { - h.store.projectVariables = make(map[string][]*Variable) + if h.projectVariables[projectID] == nil { + h.projectVariables = make(map[string][]*Variable) } - h.store.projectVariables[projectID] = append(h.store.projectVariables[projectID], &newVar) + h.projectVariables[projectID] = append(h.projectVariables[projectID], &newVar) _ = json.NewEncoder(w).Encode(map[string]any{ "_embedded": map[string]any{"entity": newVar}, @@ -70,13 +70,13 @@ func (h *Handler) handleCreateProjectVariable(w http.ResponseWriter, req *http.R } func (h *Handler) handlePatchProjectVariable(w http.ResponseWriter, req *http.Request) { - h.store.Lock() - defer h.store.Unlock() + h.Lock() + defer h.Unlock() projectID := chi.URLParam(req, "project_id") variableName, _ := url.PathUnescape(chi.URLParam(req, "name")) var key = -1 - for k, v := range h.store.projectVariables[projectID] { + for k, v := range h.projectVariables[projectID] { if v.Name == variableName { key = k break @@ -85,35 +85,35 @@ func (h *Handler) handlePatchProjectVariable(w http.ResponseWriter, req *http.Re if key == -1 { w.WriteHeader(http.StatusNotFound) } - patched := *h.store.projectVariables[projectID][key] + patched := *h.projectVariables[projectID][key] err := json.NewDecoder(req.Body).Decode(&patched) if err != nil { w.WriteHeader(http.StatusBadRequest) return } patched.UpdatedAt = time.Now() - h.store.projectVariables[projectID][key] = &patched + h.projectVariables[projectID][key] = &patched _ = json.NewEncoder(w).Encode(&patched) } func (h *Handler) handleListEnvLevelVariables(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") environmentID, _ := url.PathUnescape(chi.URLParam(req, "environment_id")) - variables := h.store.envLevelVariables[projectID][environmentID] + variables := h.envLevelVariables[projectID][environmentID] // Sort variables in descending order by created date. slices.SortFunc(variables, func(a, b *EnvLevelVariable) int { return -timeCompare(a.CreatedAt, b.CreatedAt) }) _ = json.NewEncoder(w).Encode(variables) } func (h *Handler) handleGetEnvLevelVariable(w http.ResponseWriter, req *http.Request) { - h.store.RLock() - defer h.store.RUnlock() + h.RLock() + defer h.RUnlock() projectID := chi.URLParam(req, "project_id") environmentID, _ := url.PathUnescape(chi.URLParam(req, "environment_id")) variableName, _ := url.PathUnescape(chi.URLParam(req, "name")) - for _, v := range h.store.envLevelVariables[projectID][environmentID] { + for _, v := range h.envLevelVariables[projectID][environmentID] { if variableName == v.Name { _ = json.NewEncoder(w).Encode(v) return @@ -123,8 +123,8 @@ func (h *Handler) handleGetEnvLevelVariable(w http.ResponseWriter, req *http.Req } func (h *Handler) handleCreateEnvLevelVariable(w http.ResponseWriter, req *http.Request) { - h.store.Lock() - defer h.store.Unlock() + h.Lock() + defer h.Unlock() projectID := chi.URLParam(req, "project_id") environmentID, _ := url.PathUnescape(chi.URLParam(req, "environment_id")) @@ -141,21 +141,21 @@ func (h *Handler) handleCreateEnvLevelVariable(w http.ResponseWriter, req *http. "#edit=/projects/"+projectID+"/environments/"+environmentID+"/variables/"+newVar.Name, ) - for _, v := range h.store.envLevelVariables[projectID][environmentID] { + for _, v := range h.envLevelVariables[projectID][environmentID] { if newVar.Name == v.Name { w.WriteHeader(http.StatusConflict) return } } - if h.store.envLevelVariables == nil { - h.store.envLevelVariables = make(map[string]map[string][]*EnvLevelVariable) + if h.envLevelVariables == nil { + h.envLevelVariables = make(map[string]map[string][]*EnvLevelVariable) } - if h.store.envLevelVariables[projectID] == nil { - h.store.envLevelVariables[projectID] = make(map[string][]*EnvLevelVariable) + if h.envLevelVariables[projectID] == nil { + h.envLevelVariables[projectID] = make(map[string][]*EnvLevelVariable) } - h.store.envLevelVariables[projectID][environmentID] = append( - h.store.envLevelVariables[projectID][environmentID], + h.envLevelVariables[projectID][environmentID] = append( + h.envLevelVariables[projectID][environmentID], &newVar, ) @@ -165,13 +165,13 @@ func (h *Handler) handleCreateEnvLevelVariable(w http.ResponseWriter, req *http. } func (h *Handler) handlePatchEnvLevelVariable(w http.ResponseWriter, req *http.Request) { - h.store.Lock() - defer h.store.Unlock() + h.Lock() + defer h.Unlock() projectID := chi.URLParam(req, "project_id") environmentID, _ := url.PathUnescape(chi.URLParam(req, "environment_id")) variableName, _ := url.PathUnescape(chi.URLParam(req, "name")) var key = -1 - for k, v := range h.store.envLevelVariables[projectID][environmentID] { + for k, v := range h.envLevelVariables[projectID][environmentID] { if variableName == v.Name { key = k break @@ -180,13 +180,13 @@ func (h *Handler) handlePatchEnvLevelVariable(w http.ResponseWriter, req *http.R if key == -1 { w.WriteHeader(http.StatusNotFound) } - patched := *h.store.envLevelVariables[projectID][environmentID][key] + patched := *h.envLevelVariables[projectID][environmentID][key] err := json.NewDecoder(req.Body).Decode(&patched) if err != nil { w.WriteHeader(http.StatusBadRequest) return } patched.UpdatedAt = time.Now() - h.store.envLevelVariables[projectID][environmentID][key] = &patched + h.envLevelVariables[projectID][environmentID][key] = &patched _ = json.NewEncoder(w).Encode(&patched) }