From 65a1b416e8d0483a6ba5b6c66373f80856b14519 Mon Sep 17 00:00:00 2001 From: Ansgar Schulte <1299623+ansgarschulte@users.noreply.github.com> Date: Tue, 16 Jan 2024 17:34:37 +0100 Subject: [PATCH 1/3] feat: collection discovery --- CHANGELOG.md | 8 ++ README.md | 10 +- .../templates/_helpers.tpl | 8 ++ .../templates/deployment.yaml | 5 + .../templates/secret.yaml | 14 +++ .../steadybit-extension-postman/values.yaml | 5 + config/specification.go | 1 + e2e/integration_test.go | 15 ++- extpostman/action_run.go | 63 +++++++----- extpostman/action_run_test.go | 27 +++-- extpostman/collection_api.go | 55 +++++++++++ extpostman/common.go | 1 + extpostman/discovery.go | 99 +++++++++++++++++++ extpostman/environment_api.go | 83 ++++++++++++++++ go.mod | 23 +++-- go.sum | 46 ++++++--- main.go | 26 ++++- 17 files changed, 421 insertions(+), 68 deletions(-) create mode 100644 charts/steadybit-extension-postman/templates/_helpers.tpl create mode 100644 charts/steadybit-extension-postman/templates/secret.yaml create mode 100644 extpostman/collection_api.go create mode 100644 extpostman/discovery.go create mode 100644 extpostman/environment_api.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 419d874..c6ed85d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## v2.0.0 + +- Breaking Changes +- Configure ApiKey in the extension configuration +- Discovery of Postman Collections +- Support for Postman Environments to select the correct environment for the collection by name +- Use a Postman Collection a target for the action + ## v1.5.8 - Update dependencies diff --git a/README.md b/README.md index 066f865..6ef91b6 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,13 @@ Learn about the capabilities of this extension in our [Reliability Hub](https:// ## Configuration - +Postman_Api_Key ## Configuration -| Environment Variable | Helm value | Meaning | Required | Default | -|---------------------------------------|--------------------------|-----------------------------------------------------------|----------|---------| -| `HTTPS_PROXY` | via extraEnv variables | Configure the proxy to be used for Postman communication. | no | | +| Environment Variable | Helm value | Meaning | Required | Default | +|----------------------|------------------------|-------------------------------------------------------------|----------|---------| +| `HTTPS_PROXY` | via extraEnv variables | Configure the proxy to be used for Postman communication. | no | | +| `POSTMAN_API_KEY` | postman.apiKey | Configure the api-key to be used for Postman communication. | yes | | The extension supports all environment variables provided by [steadybit/extension-kit](https://github.com/steadybit/extension-kit#environment-variables). @@ -46,6 +47,7 @@ helm upgrade steadybit-extension-postman \ --timeout 5m0s \ --create-namespace \ --namespace steadybit-extension \ + --set postman.apiKey= \ steadybit-extension-postman/steadybit-extension-postman ``` diff --git a/charts/steadybit-extension-postman/templates/_helpers.tpl b/charts/steadybit-extension-postman/templates/_helpers.tpl new file mode 100644 index 0000000..dd7e379 --- /dev/null +++ b/charts/steadybit-extension-postman/templates/_helpers.tpl @@ -0,0 +1,8 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Expand the name of the chart. +*/}} +{{- define "postman.secret.name" -}} +{{- default "steadybit-extension-postman" .Values.postman.existingSecret -}} +{{- end -}} diff --git a/charts/steadybit-extension-postman/templates/deployment.yaml b/charts/steadybit-extension-postman/templates/deployment.yaml index 8708e47..05e3a95 100644 --- a/charts/steadybit-extension-postman/templates/deployment.yaml +++ b/charts/steadybit-extension-postman/templates/deployment.yaml @@ -49,6 +49,11 @@ spec: memory: {{ .Values.resources.limits.memory }} cpu: {{ .Values.resources.limits.cpu }} env: + - name: POSTMAN_API_KEY + valueFrom: + secretKeyRef: + name: {{ include "postman.secret.name" . }} + key: apiKey {{- include "extensionlib.deployment.env" (list .) | nindent 12 }} {{- with .Values.extraEnv }} {{- toYaml . | nindent 12 }} diff --git a/charts/steadybit-extension-postman/templates/secret.yaml b/charts/steadybit-extension-postman/templates/secret.yaml new file mode 100644 index 0000000..cfa7534 --- /dev/null +++ b/charts/steadybit-extension-postman/templates/secret.yaml @@ -0,0 +1,14 @@ +{{- if not .Values.postman.existingSecret -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "postman.secret.name" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- range $key, $value := .Values.extraLabels }} + {{ $key }}: {{ $value }} + {{- end }} +type: Opaque +data: + apiKey: {{ .Values.postman.apiKey | b64enc | quote }} +{{- end }} diff --git a/charts/steadybit-extension-postman/values.yaml b/charts/steadybit-extension-postman/values.yaml index ddd8099..de7b8be 100644 --- a/charts/steadybit-extension-postman/values.yaml +++ b/charts/steadybit-extension-postman/values.yaml @@ -113,3 +113,8 @@ extraEnv: [] # - secretRef: # name: env-secrets extraEnvFrom: [] + +postman: + apiKey: "" + # postman.existingSecret -- If defined, will skip secret creation and instead assume that the referenced secret contains the apiKey + existingSecret: null diff --git a/config/specification.go b/config/specification.go index 3f8d49a..da7c685 100644 --- a/config/specification.go +++ b/config/specification.go @@ -5,4 +5,5 @@ package config type Specification struct { PostmanBaseUrl string `json:"postmanBaseUrl" split_words:"true" required:"false" default:"https://api.getpostman.com"` + PostmanApiKey string `json:"postmanApiKey" split_words:"true" required:"true"` } diff --git a/e2e/integration_test.go b/e2e/integration_test.go index 2b17ceb..519c091 100644 --- a/e2e/integration_test.go +++ b/e2e/integration_test.go @@ -5,6 +5,7 @@ package e2e import ( "fmt" + "github.com/steadybit/action-kit/go/action_kit_api/v2" "github.com/steadybit/action-kit/go/action_kit_test/e2e" "github.com/steadybit/extension-kit/extlogging" "github.com/stretchr/testify/require" @@ -26,6 +27,7 @@ func TestWithMinikube(t *testing.T) { ExtraArgs: func(m *e2e.Minikube) []string { return []string{ "--set", "logging.level=debug", + "--set", "STEADYBIT_EXTENSION_POSTMAN_API_KEY=testApiKey", "--set", "extraEnv[0].name=STEADYBIT_EXTENSION_POSTMAN_BASE_URL", "--set", fmt.Sprintf("extraEnv[0].value=%s:%s", "http://host.minikube.internal:", port), } @@ -42,14 +44,17 @@ func TestWithMinikube(t *testing.T) { func testRunPostman(t *testing.T, m *e2e.Minikube, e *e2e.Extension) { config := struct { - CollectionId string - ApiKey string }{ - CollectionId: "testCollectionId", - ApiKey: "testApiKey", } - exec, err := e.RunAction("com.steadybit.extension_postman.collection.run", nil, config, nil) + collectionId := "5f757f0d-de24-462c-867f-256bb696d2dd" + target := action_kit_api.Target{ + Attributes: map[string][]string{ + "postman.collection.id": {collectionId}, + }, + } + + exec, err := e.RunAction("com.steadybit.extension_postman.collection.run.v2", &target, config, nil) require.NoError(t, err) e2e.AssertLogContainsWithTimeout(t, m, e.Pod, "Starting newman!", 90*time.Second) e2e.AssertLogContainsWithTimeout(t, m, e.Pod, "Postman run completed successfully", 90*time.Second) diff --git a/extpostman/action_run.go b/extpostman/action_run.go index b7320fd..8667c44 100644 --- a/extpostman/action_run.go +++ b/extpostman/action_run.go @@ -35,9 +35,7 @@ type PostmanState struct { } type PostmanConfig struct { - CollectionId string - ApiKey string - EnvironmentId string + EnvironmentIdOrName string Environment []map[string]string Verbose bool Bail bool @@ -61,12 +59,28 @@ func (f PostmanAction) NewEmptyState() PostmanState { func (f PostmanAction) Describe() action_kit_api.ActionDescription { return action_kit_api.ActionDescription{ - Id: "com.steadybit.extension_postman.collection.run", + Id: targetID + ".run.v2", Label: "Postman", Description: "Integrate a Postman Collection via Postman Cloud API.", Version: extbuild.GetSemverVersionStringOrUnknown(), Kind: action_kit_api.Check, Icon: extutil.Ptr(icon), + TargetSelection: extutil.Ptr(action_kit_api.TargetSelection{ + // The target type this action is for + TargetType: targetID, + // You can provide a list of target templates to help the user select targets. + // A template can be used to pre-fill a selection + SelectionTemplates: extutil.Ptr([]action_kit_api.TargetSelectionTemplate{ + { + Label: "by collection name", + Query: "postman.collection.name=\"\"", + }, + { + Label: "by collection id", + Query: "postman.collection.id=\"\"", + }, + }), + }), TimeControl: action_kit_api.TimeControlInternal, Parameters: []action_kit_api.ActionParameter{ { @@ -78,23 +92,9 @@ func (f PostmanAction) Describe() action_kit_api.ActionDescription { Type: action_kit_api.Duration, }, { - Name: "apiKey", - Label: "API-Key", - Description: extutil.Ptr("Postman Cloud API Key"), - Required: extutil.Ptr(true), - Type: action_kit_api.Password, - }, - { - Name: "collectionId", - Label: "Collection ID", - Description: extutil.Ptr("UID of the Postman Collection"), - Required: extutil.Ptr(true), - Type: action_kit_api.String, - }, - { - Name: "environmentId", - Label: "Environment ID", - Description: extutil.Ptr("UID of the Postman Environment"), + Name: "environmentIdOrName", + Label: "Environment ID or Name", + Description: extutil.Ptr("UID or unique Name of the Postman Environment"), Required: extutil.Ptr(false), Type: action_kit_api.String, }, @@ -162,15 +162,28 @@ func (f PostmanAction) Prepare(_ context.Context, state *PostmanState, raw actio } config := config.Config + collectionIds := raw.Target.Attributes["postman.collection.id"] + if len(collectionIds) == 0 { + return nil, extension_kit.ToError("No collection id provided", nil) + } + if len(collectionIds) > 1 { + return nil, extension_kit.ToError("More than one collection id provided", nil) + } + var collectionId = collectionIds[0] + state.Timestamp = time.Now().Format(time.RFC3339) state.Command = []string{ "newman", "run", - fmt.Sprintf("%s/collections/%s?apikey=%s", config.PostmanBaseUrl, request.CollectionId, request.ApiKey), + fmt.Sprintf("%s/collections/%s?apikey=%s", config.PostmanBaseUrl, collectionId, config.PostmanApiKey), } - if request.EnvironmentId != "" { + if request.EnvironmentIdOrName != "" { + environmentId, error := GetPostEnvironmentId(request.EnvironmentIdOrName) + if error != nil { + return nil, extension_kit.ToError("Failed to get environment id.", error) + } state.Command = append(state.Command, "--environment") - state.Command = append(state.Command, fmt.Sprintf("%s/environments/%s?apikey=%s", config.PostmanBaseUrl, request.EnvironmentId, request.ApiKey)) + state.Command = append(state.Command, fmt.Sprintf("%s/environments/%s?apikey=%s", config.PostmanBaseUrl, environmentId, config.PostmanApiKey)) } if request.Environment != nil { for _, value := range request.Environment { @@ -205,7 +218,7 @@ func (f PostmanAction) Prepare(_ context.Context, state *PostmanState, raw actio state.Command = append(state.Command, "-n") state.Command = append(state.Command, fmt.Sprintf("%d", request.Iterations)) } - log.Info().Msgf("Prepared action. Command: %s", extutil.MaskString(strings.Join(state.Command, " "), request.ApiKey, 4)) + log.Info().Msgf("Prepared action. Command: %s", extutil.MaskString(strings.Join(state.Command, " "), config.PostmanApiKey, 4)) return nil, nil } diff --git a/extpostman/action_run_test.go b/extpostman/action_run_test.go index 8da53dd..12b7cab 100644 --- a/extpostman/action_run_test.go +++ b/extpostman/action_run_test.go @@ -14,18 +14,18 @@ import ( "github.com/steadybit/extension-postman/config" "github.com/steadybit/extension-postman/utils" "github.com/stretchr/testify/assert" + "os" "testing" ) func TestPrepareCollectionRun(t *testing.T) { + os.Setenv("STEADYBIT_EXTENSION_POSTMAN_API_KEY", "123456") config.ParseConfiguration() // Given requestBody := extutil.JsonMangle(action_kit_api.PrepareActionRequestBody{ Config: map[string]interface{}{ "duration": 60000, - "apiKey": "123456", - "collectionId": "645797", - "environmentId": "env1", + "EnvironmentIdOrName": "5f757f0d-de24-462c-867f-256bb696d2dd", "iterations": 2, "environment": []map[string]string{ {"key": "Test1", "value": "foo"}, @@ -36,7 +36,11 @@ func TestPrepareCollectionRun(t *testing.T) { "verbose": false, "bail": true, }, - Target: &action_kit_api.Target{}, + Target: &action_kit_api.Target{ + Attributes: map[string][]string{ + "postman.collection.id": {"645797"}, + }, + }, }) action := NewPostmanAction() state := action.NewEmptyState() @@ -48,25 +52,28 @@ func TestPrepareCollectionRun(t *testing.T) { assert.Nil(t, err) assert.Nil(t, result) assert.Equal(t, "newman", state.Command[0]) - assert.Equal(t, []string{"newman", "run", "https://api.getpostman.com/collections/645797?apikey=123456", "--environment", "https://api.getpostman.com/environments/env1?apikey=123456", "--env-var", "Test1=foo", "--env-var", "Test2=bar", "--bail", "--timeout", "30000", "--timeout-request", "30000", "--reporters", "cli,json-summary,htmlextra", "--reporter-summary-json-export", "--reporter-htmlextra-export", "--reporter-htmlextra-omitResponseBodies", "-n", "2"}, utils.RemoveAtIndex(utils.RemoveAtIndex(state.Command, 17), 18)) + assert.Equal(t, []string{"newman", "run", "https://api.getpostman.com/collections/645797?apikey=123456", "--environment", "https://api.getpostman.com/environments/5f757f0d-de24-462c-867f-256bb696d2dd?apikey=123456", "--env-var", "Test1=foo", "--env-var", "Test2=bar", "--bail", "--timeout", "30000", "--timeout-request", "30000", "--reporters", "cli,json-summary,htmlextra", "--reporter-summary-json-export", "--reporter-htmlextra-export", "--reporter-htmlextra-omitResponseBodies", "-n", "2"}, utils.RemoveAtIndex(utils.RemoveAtIndex(state.Command, 17), 18)) } func TestPrepareCollectionRunWithEmptyEnvironment(t *testing.T) { + os.Setenv("STEADYBIT_EXTENSION_POSTMAN_API_KEY", "123456") config.ParseConfiguration() // Given requestBody := extutil.JsonMangle(action_kit_api.PrepareActionRequestBody{ Config: map[string]interface{}{ "duration": 60000, - "apiKey": "123456", - "collectionId": "645797", - "environmentId": "env1", + "EnvironmentIdOrName": "5f757f0d-de24-462c-867f-256bb696d2dd", "iterations": 2, "environment": []map[string]string{}, "timeout": 30000, "timeoutRequest": 30000, "verbose": true, }, - Target: &action_kit_api.Target{}, + Target: &action_kit_api.Target{ + Attributes: map[string][]string{ + "postman.collection.id": {"645797"}, + }, + }, }) action := NewPostmanAction() state := action.NewEmptyState() @@ -78,5 +85,5 @@ func TestPrepareCollectionRunWithEmptyEnvironment(t *testing.T) { assert.Nil(t, err) assert.Nil(t, result) assert.Equal(t, "newman", state.Command[0]) - assert.Equal(t, []string{"newman", "run", "https://api.getpostman.com/collections/645797?apikey=123456", "--environment", "https://api.getpostman.com/environments/env1?apikey=123456", "--verbose", "--timeout", "30000", "--timeout-request", "30000", "--reporters", "cli,json-summary,htmlextra", "--reporter-summary-json-export", "--reporter-htmlextra-export", "--reporter-htmlextra-omitResponseBodies", "-n", "2"}, utils.RemoveAtIndex(utils.RemoveAtIndex(state.Command, 13), 14)) + assert.Equal(t, []string{"newman", "run", "https://api.getpostman.com/collections/645797?apikey=123456", "--environment", "https://api.getpostman.com/environments/5f757f0d-de24-462c-867f-256bb696d2dd?apikey=123456", "--verbose", "--timeout", "30000", "--timeout-request", "30000", "--reporters", "cli,json-summary,htmlextra", "--reporter-summary-json-export", "--reporter-htmlextra-export", "--reporter-htmlextra-omitResponseBodies", "-n", "2"}, utils.RemoveAtIndex(utils.RemoveAtIndex(state.Command, 13), 14)) } diff --git a/extpostman/collection_api.go b/extpostman/collection_api.go new file mode 100644 index 0000000..0741186 --- /dev/null +++ b/extpostman/collection_api.go @@ -0,0 +1,55 @@ +package extpostman + +import ( + "encoding/json" + "github.com/rs/zerolog/log" + "github.com/steadybit/extension-postman/config" + "io" + "net/http" + "net/url" +) + +type PostmanCollectionResult struct { + Collections []PostmanCollection `json:"collections"` +} +type PostmanCollection struct { + Id string `json:"id"` + Name string `json:"name"` +} +func GetPostmanCollections() []PostmanCollection { + var specification = config.Config + var apiKey = specification.PostmanApiKey + collectionsUrl, err := url.Parse(specification.PostmanBaseUrl) + if err != nil { + log.Error().Msgf("Failed to parse postman base url. Got error: %s", err) + return nil + } + collectionsUrl.Path += "/collections" + parameters := url.Values{} + parameters.Add("apikey", apiKey) + collectionsUrl.RawQuery = parameters.Encode() + + + response, err := http.Get(collectionsUrl.String()) + if err != nil { + log.Error().Msgf("Failed to get collections from postman api. Got error: %s", err) + return nil + } + + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + log.Error().Msgf("Failed to close response body. Got error: %s", err) + return + } + }(response.Body) + + var result PostmanCollectionResult + err = json.NewDecoder(response.Body).Decode(&result) + if err != nil { + log.Error().Msgf("Failed to decode response body. Got error: %s", err) + return nil + } + + return result.Collections +} diff --git a/extpostman/common.go b/extpostman/common.go index d6ef3c6..c122b76 100644 --- a/extpostman/common.go +++ b/extpostman/common.go @@ -4,5 +4,6 @@ package extpostman const ( + targetID = "com.steadybit.extension_postman.collection" icon = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTMuNTI3LjA5OUM2Ljk1NS0uNzQ0Ljk0MiAzLjkuMDk5IDEwLjQ3M2MtLjg0MyA2LjU3MiAzLjggMTIuNTg0IDEwLjM3MyAxMy40MjggNi41NzMuODQzIDEyLjU4Ny0zLjgwMSAxMy40MjgtMTAuMzc0QzI0Ljc0NCA2Ljk1NSAyMC4xMDEuOTQzIDEzLjUyNy4wOTl6bTIuNDcxIDcuNDg1YS44NTUuODU1IDAgMDAtLjU5My4yNWwtNC40NTMgNC40NTMtLjMwNy0uMzA3LS42NDMtLjY0M2M0LjM4OS00LjM3NiA1LjE4LTQuNDE4IDUuOTk2LTMuNzUzem0tNC44NjMgNC44NjFsNC40NC00LjQ0YS42Mi42MiAwIDExLjg0Ny45MDNsLTQuNjk5IDQuMTI1LS41ODgtLjU4OHptLjMzLjY5NGwtMS4xLjIzOGEuMDYuMDYgMCAwMS0uMDY3LS4wMzIuMDYuMDYgMCAwMS4wMS0uMDczbC42NDUtLjY0NS41MTIuNTEyem0tMi44MDMtLjQ1OWwxLjE3Mi0xLjE3Mi44NzkuODc4LTEuOTc5LjQyNmEuMDc0LjA3NCAwIDAxLS4wODUtLjAzOS4wNzIuMDcyIDAgMDEuMDEzLS4wOTN6bS0zLjY0NiA2LjA1OGEuMDc2LjA3NiAwIDAxLS4wNjktLjA4My4wNzcuMDc3IDAgMDEuMDIyLS4wNDZoLjAwMmwuOTQ2LS45NDYgMS4yMjIgMS4yMjItMi4xMjMtLjE0N3ptMi40MjUtMS4yNTZhLjIyOC4yMjggMCAwMC0uMTE3LjI1NmwuMjAzLjg2NWEuMTI1LjEyNSAwIDAxLS4yMTEuMTE3aC0uMDAzbC0uOTM0LS45MzQtLjI5NC0uMjk1IDMuNzYyLTMuNzU4IDEuODItLjM5My44NzQuODc0Yy0xLjI1NSAxLjEwMi0yLjk3MSAyLjIwMS01LjEgMy4yNjh6bTUuMjc5LTMuNDI4aC0uMDAybC0uODM5LS44MzkgNC42OTktNC4xMjVhLjk1Mi45NTIgMCAwMC4xMTktLjEyN2MtLjE0OCAxLjM0NS0yLjAyOSAzLjI0NS0zLjk3NyA1LjA5MXptMy42NTctNi40NmwtLjAwMy0uMDAyYTEuODIyIDEuODIyIDAgMDEyLjQ1OS0yLjY4NGwtMS42MSAxLjYxM2EuMTE5LjExOSAwIDAwMCAuMTY5bDEuMjQ3IDEuMjQ3YTEuODE3IDEuODE3IDAgMDEtMi4wOTMtLjM0M3ptMi41NzggMGExLjcxNCAxLjcxNCAwIDAxLS4yNzEuMjE4aC0uMDAxbC0xLjIwNy0xLjIwNyAxLjUzMy0xLjUzM2MuNjYxLjcyLjYzNyAxLjgzMi0uMDU0IDIuNTIyem0tLjEtMS41NDRhLjE0My4xNDMgMCAwMC0uMDUzLjE1Ny40MTYuNDE2IDAgMDEtLjA1My40NS4xNC4xNCAwIDAwLjAyMy4xOTcuMTQxLjE0MSAwIDAwLjA4NC4wMy4xNC4xNCAwIDAwLjEwNi0uMDUuNjkxLjY5MSAwIDAwLjA4Ny0uNzUxLjEzOC4xMzggMCAwMC0uMTk0LS4wMzN6IiBmaWxsPSJjdXJyZW50Q29sb3IiLz48L3N2Zz4=" ) diff --git a/extpostman/discovery.go b/extpostman/discovery.go new file mode 100644 index 0000000..dc81f25 --- /dev/null +++ b/extpostman/discovery.go @@ -0,0 +1,99 @@ +/* + * Copyright 2023 steadybit GmbH. All rights reserved. + */ + +package extpostman + +import ( + "context" + "github.com/steadybit/discovery-kit/go/discovery_kit_api" + "github.com/steadybit/discovery-kit/go/discovery_kit_commons" + "github.com/steadybit/discovery-kit/go/discovery_kit_sdk" + "github.com/steadybit/extension-kit/extbuild" + "github.com/steadybit/extension-kit/extutil" + "time" +) + +type collectionDiscovery struct { +} + +var ( + _ discovery_kit_sdk.TargetDescriber = (*collectionDiscovery)(nil) + _ discovery_kit_sdk.AttributeDescriber = (*collectionDiscovery)(nil) +) + +func NewPostmanCollectionDiscovery() discovery_kit_sdk.TargetDiscovery { + discovery := &collectionDiscovery{} + return discovery_kit_sdk.NewCachedTargetDiscovery(discovery, + discovery_kit_sdk.WithRefreshTargetsNow(), + discovery_kit_sdk.WithRefreshTargetsInterval(context.Background(), 1*time.Minute), + ) +} + +func (d *collectionDiscovery) Describe() discovery_kit_api.DiscoveryDescription { + return discovery_kit_api.DiscoveryDescription{ + Id: targetID, + RestrictTo: extutil.Ptr(discovery_kit_api.LEADER), + Discover: discovery_kit_api.DescribingEndpointReferenceWithCallInterval{ + CallInterval: extutil.Ptr("1m"), + }, + } +} + +func (d *collectionDiscovery) DescribeTarget() discovery_kit_api.TargetDescription { + return discovery_kit_api.TargetDescription{ + Id: targetID, + Version: extbuild.GetSemverVersionStringOrUnknown(), + Icon: extutil.Ptr(icon), + + // Labels used in the UI + Label: discovery_kit_api.PluralLabel{One: "Collection", Other: "Collections"}, + + // Category for the targets to appear in + Category: extutil.Ptr("postman"), + + // Specify attributes shown in table columns and to be used for sorting + Table: discovery_kit_api.Table{ + Columns: []discovery_kit_api.Column{ + {Attribute: "steadybit.label"}, + {Attribute: "postman.collection.id"}, + }, + OrderBy: []discovery_kit_api.OrderBy{ + { + Attribute: "steadybit.label", + Direction: "ASC", + }, + }, + }, + } +} + +func (d *collectionDiscovery) DescribeAttributes() []discovery_kit_api.AttributeDescription { + return []discovery_kit_api.AttributeDescription{ + { + Attribute: "postman.collection.id", + Label: discovery_kit_api.PluralLabel{ + One: "Collection Id", + Other: "Collection Ids", + }, + }, + } +} + +func (d *collectionDiscovery) DiscoverTargets(_ context.Context) ([]discovery_kit_api.Target, error) { + collections := GetPostmanCollections() + targets := make([]discovery_kit_api.Target, len(collections)) + for i, collection := range collections { + targets[i] = discovery_kit_api.Target{ + Id: collection.Id, + TargetType: targetID, + Label: collection.Name, + Attributes: map[string][]string{ + "steadybit.label": {collection.Name}, + "postman.collection.id": {collection.Id}, + "postman.collection.name": {collection.Name}, + }, + } + } + return discovery_kit_commons.ApplyAttributeExcludes(targets, []string{}), nil +} diff --git a/extpostman/environment_api.go b/extpostman/environment_api.go new file mode 100644 index 0000000..d9178d4 --- /dev/null +++ b/extpostman/environment_api.go @@ -0,0 +1,83 @@ +package extpostman + +import ( + "encoding/json" + "fmt" + "github.com/google/uuid" + "github.com/rs/zerolog/log" + "github.com/steadybit/extension-postman/config" + "io" + "net/http" + "net/url" +) + +type PostmanEnvironmentResult struct { + Environments []PostmanEnvironment `json:"Environments"` +} +type PostmanEnvironment struct { + Id string `json:"id"` + Name string `json:"name"` +} + +func GetPostEnvironmentId(environmentIdOrName string) (string, error) { + //check if uuid + environmentId, err := uuid.Parse(environmentIdOrName) + if err == nil { + return environmentId.String(), nil + } + + environments := GetPostmanEnvironments() + var uniqueEnvironmentId string + counter := 0 + for _, environment := range environments { + if environment.Name == environmentIdOrName { + counter++ + uniqueEnvironmentId = environment.Id + } + } + if counter > 1 { + return "", fmt.Errorf("found multiple environments with name '%s'", environmentIdOrName) + } + if uniqueEnvironmentId != "" { + return uniqueEnvironmentId, nil + } + + return "", fmt.Errorf("failed to find environment with name '%s'", environmentIdOrName) +} +func GetPostmanEnvironments() []PostmanEnvironment { + var specification = config.Config + var apiKey = specification.PostmanApiKey + EnvironmentsUrl, err := url.Parse(specification.PostmanBaseUrl) + if err != nil { + log.Error().Msgf("Failed to parse postman base url. Got error: %s", err) + return nil + } + EnvironmentsUrl.Path += "/environments" + parameters := url.Values{} + parameters.Add("apikey", apiKey) + EnvironmentsUrl.RawQuery = parameters.Encode() + + + response, err := http.Get(EnvironmentsUrl.String()) + if err != nil { + log.Error().Msgf("Failed to get Environments from postman api. Got error: %s", err) + return nil + } + + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + log.Error().Msgf("Failed to close response body. Got error: %s", err) + return + } + }(response.Body) + + var result PostmanEnvironmentResult + err = json.NewDecoder(response.Body).Decode(&result) + if err != nil { + log.Error().Msgf("Failed to decode response body. Got error: %s", err) + return nil + } + + return result.Environments +} diff --git a/go.mod b/go.mod index 687fdb0..371eb4f 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,18 @@ module github.com/steadybit/extension-postman go 1.21 require ( + github.com/google/uuid v1.5.0 github.com/kelseyhightower/envconfig v1.4.0 github.com/rs/zerolog v1.31.0 - github.com/steadybit/action-kit/go/action_kit_api/v2 v2.8.0 + github.com/steadybit/action-kit/go/action_kit_api/v2 v2.9.0 github.com/steadybit/action-kit/go/action_kit_sdk v1.1.8 github.com/steadybit/action-kit/go/action_kit_test v1.2.8 + github.com/steadybit/discovery-kit/go/discovery_kit_api v1.5.0 + github.com/steadybit/discovery-kit/go/discovery_kit_commons v0.1.0 + github.com/steadybit/discovery-kit/go/discovery_kit_sdk v1.0.4 github.com/steadybit/extension-kit v1.8.11 github.com/stretchr/testify v1.8.4 + ) require ( @@ -48,7 +53,6 @@ require ( github.com/gomarkdown/markdown v0.0.0-20231115200524-a660076da3fd // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.5.0 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/imdario/mergo v0.3.16 // indirect @@ -64,8 +68,8 @@ require ( github.com/kataras/tunnel v0.0.4 // indirect github.com/klauspost/compress v1.17.3 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect - github.com/labstack/echo/v4 v4.11.3 // indirect - github.com/labstack/gommon v0.4.1 // indirect + github.com/labstack/echo/v4 v4.11.4 // indirect + github.com/labstack/gommon v0.4.2 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mailgun/raymond/v2 v2.0.48 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -78,6 +82,7 @@ require ( github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/oapi-codegen/runtime v1.1.1 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -86,10 +91,9 @@ require ( github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/steadybit/discovery-kit/go/discovery_kit_api v1.5.0 // indirect github.com/steadybit/discovery-kit/go/discovery_kit_test v1.1.2 // indirect - github.com/tdewolff/minify/v2 v2.20.6 // indirect - github.com/tdewolff/parse/v2 v2.7.4 // indirect + github.com/tdewolff/minify/v2 v2.20.7 // indirect + github.com/tdewolff/parse/v2 v2.7.5 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect @@ -98,15 +102,16 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect github.com/yosssi/ace v0.0.5 // indirect + github.com/zmwangx/debounce v1.0.0 // indirect golang.org/x/arch v0.6.0 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect - golang.org/x/net v0.18.0 // indirect + golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.4.0 // indirect + golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index dcdc8ea..4dff954 100644 --- a/go.sum +++ b/go.sum @@ -110,6 +110,8 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJY github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -131,6 +133,8 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/kataras/blocks v0.0.8 h1:MrpVhoFTCR2v1iOOfGng5VJSILKeZZI+7NGfxEh3SUM= github.com/kataras/blocks v0.0.8/go.mod h1:9Jm5zx6BB+06NwA+OhTbHW1xkMOYxahnqTN5DveZ2Yg= @@ -161,10 +165,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.11.3 h1:Upyu3olaqSHkCjs1EJJwQ3WId8b8b1hxbogyommKktM= -github.com/labstack/echo/v4 v4.11.3/go.mod h1:UcGuQ8V6ZNRmSweBIJkPvGfwCMIlFmiqrPqiEBfPYws= -github.com/labstack/gommon v0.4.1 h1:gqEff0p/hTENGMABzezPoPSRtIh1Cvw0ueMOe0/dfOk= -github.com/labstack/gommon v0.4.1/go.mod h1:TyTrpPqxR5KMk8LKVtLmfMjeQ5FEkBYdxLYPw/WfrOM= +github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= +github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/madflojo/testcerts v1.1.1 h1:YsSHWV79nMNZK0mJtwXjKoYHjJEbLPFefR8TxmmWupY= @@ -197,6 +201,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= +github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= @@ -227,17 +233,25 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v1.13.1 h1:Ef7KhSmjZcK6AVf9YbJdvPYG9avaF0ZxudX+ThRdWfU= +github.com/smartystreets/assertions v1.13.1/go.mod h1:cXr/IwVfSo/RbCSPhoAPv73p3hlSdrBH/b3SdnW/LMY= +github.com/smartystreets/goconvey v1.8.0 h1:Oi49ha/2MURE0WexF052Z0m+BNSGirfjg5RL+JXWq3w= +github.com/smartystreets/goconvey v1.8.0/go.mod h1:EdX8jtrTIj26jmjCOVNMVSIYAtgexqXKHOXW2Dx9JLg= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= -github.com/steadybit/action-kit/go/action_kit_api/v2 v2.8.0 h1:mo+wf8we5LVnxgUuJvvN/DDVA42uZt6RLKCBJtkWL/4= -github.com/steadybit/action-kit/go/action_kit_api/v2 v2.8.0/go.mod h1:q9fyUhgf3LnhMRCzZ9tBjj8w2le5SUJi0vHw6A3PIKw= +github.com/steadybit/action-kit/go/action_kit_api/v2 v2.9.0 h1:8whTfgk0UpNVj/d0hrXmW+mgAN0HUAvaafMW+yPHbqA= +github.com/steadybit/action-kit/go/action_kit_api/v2 v2.9.0/go.mod h1:VvrWrWS4lFAmtlYW06wY1G8+L9gbw/Tq0HDceSN21M8= github.com/steadybit/action-kit/go/action_kit_sdk v1.1.8 h1:kcpEVZw0iv5bIE7GNmjC54XRKxUlwPkDsvfMGeudIrQ= github.com/steadybit/action-kit/go/action_kit_sdk v1.1.8/go.mod h1:h2E1gRdpIhWvfQy5XsRIfQi3AujlpdcXxt3tNU9829U= github.com/steadybit/action-kit/go/action_kit_test v1.2.8 h1:lMaDPHpewxRITmyIN3G+yjEOBH7gG/md1NgbMaON4pY= github.com/steadybit/action-kit/go/action_kit_test v1.2.8/go.mod h1:SVDSuExDu7RHVqartWSYa+jqGV08dvSwcEZzTFugBN4= github.com/steadybit/discovery-kit/go/discovery_kit_api v1.5.0 h1:kRDryl2fvjXiaVNvWtoN3JGQ+lVS59iR87OVSCTwtpc= github.com/steadybit/discovery-kit/go/discovery_kit_api v1.5.0/go.mod h1:vAMfjAw7zpu55b8fdl0QRa4NszbuK4Pg8/nj1iHIO68= +github.com/steadybit/discovery-kit/go/discovery_kit_commons v0.1.0 h1:g4PjxmmUdHKJQ4FJ9evrIHKm5qgN2r3Rd8AJjiZZ2kI= +github.com/steadybit/discovery-kit/go/discovery_kit_commons v0.1.0/go.mod h1:Gg/S2hwxxZsYoXaFvyLkpqHmir2GVrN8nE7FWki9afQ= +github.com/steadybit/discovery-kit/go/discovery_kit_sdk v1.0.4 h1:PDvRqFiELe0gwxwxL+Od/QCdZmUga8nuK3IYvvRIXyU= +github.com/steadybit/discovery-kit/go/discovery_kit_sdk v1.0.4/go.mod h1:VgaJTMZaNcVXUCrZvAHlO51s8vNfyhJPbTSOBp/jmCM= github.com/steadybit/discovery-kit/go/discovery_kit_test v1.1.2 h1:IrTUwb69FDwOt/8OvY1Lvhv+qGNmy+Eu53HEjmsj0TA= github.com/steadybit/discovery-kit/go/discovery_kit_test v1.1.2/go.mod h1:tr4oRjpqr2WOKwO4auJR+/m+YKA2EAUuvvpbz1faUxw= github.com/steadybit/extension-kit v1.8.11 h1:7X76rOpC8DXiS6R83rr70eLO09sDu0DHOzSmGEIBCeo= @@ -245,6 +259,8 @@ github.com/steadybit/extension-kit v1.8.11/go.mod h1:vT1jG8WMZuImhNDCoLX19ckmCuP github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= +github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -254,10 +270,10 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/tdewolff/minify/v2 v2.20.6 h1:R4+Iw1ZqJxrqH52WWHtCpukMuhmO/EasY8YlDiSxphw= -github.com/tdewolff/minify/v2 v2.20.6/go.mod h1:9t0EY9xySGt1vrP8iscmJfywQwDCQyQBYN6ge+9GwP0= -github.com/tdewolff/parse/v2 v2.7.4 h1:zrUn2CFg9+5llbUZcsycctFlNRyV1D5gFBZRxuGzdzk= -github.com/tdewolff/parse/v2 v2.7.4/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= +github.com/tdewolff/minify/v2 v2.20.7 h1:NUkuzJ9dvQUNJjSdmmrfELa/ZpnMdyMR/ZKU2bw7N/E= +github.com/tdewolff/minify/v2 v2.20.7/go.mod h1:bj2NpP3zoUhsPzE4oM4JYwuUyVCU/uMaCYZ6/riEjIo= +github.com/tdewolff/parse/v2 v2.7.5 h1:RdcN3Ja6zAMSvnxxO047xRoWexX3RrXKi3H6EQHzXto= +github.com/tdewolff/parse/v2 v2.7.5/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52 h1:gAQliwn+zJrkjAHVcBEYW/RFvd2St4yYimisvozAYlA= github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= @@ -290,6 +306,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zmwangx/debounce v1.0.0 h1:Dyf+WfLESjc2bqFKHgI1dZTW9oh6CJm8SBDkhXrwLB4= +github.com/zmwangx/debounce v1.0.0/go.mod h1:U+/QHt+bSMdUh8XKOb6U+MQV5Ew4eS8M3ua5WJ7Ns6I= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= @@ -318,8 +336,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -365,8 +383,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= -golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= diff --git a/main.go b/main.go index 8da0005..84a2eae 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,10 @@ package main import ( "github.com/rs/zerolog" + "github.com/steadybit/action-kit/go/action_kit_api/v2" "github.com/steadybit/action-kit/go/action_kit_sdk" + "github.com/steadybit/discovery-kit/go/discovery_kit_api" + "github.com/steadybit/discovery-kit/go/discovery_kit_sdk" "github.com/steadybit/extension-kit/extbuild" "github.com/steadybit/extension-kit/exthealth" "github.com/steadybit/extension-kit/exthttp" @@ -25,11 +28,32 @@ func main() { exthealth.StartProbes(8087) action_kit_sdk.RegisterCoverageEndpoints() + discovery_kit_sdk.Register(extpostman.NewPostmanCollectionDiscovery()) action_kit_sdk.RegisterAction(extpostman.NewPostmanAction()) action_kit_sdk.InstallSignalHandler() - exthttp.RegisterHttpHandler("/", exthttp.GetterAsHandler(action_kit_sdk.GetActionList)) + exthttp.RegisterHttpHandler("/", exthttp.GetterAsHandler(getExtensionList)) exthttp.Listen(exthttp.ListenOpts{ Port: 8086, }) } + + +// ExtensionListResponse exists to merge the possible root path responses supported by the +// various extension kits. In this case, the response for ActionKit, DiscoveryKit and EventKit. +type ExtensionListResponse struct { + action_kit_api.ActionList `json:",inline"` + discovery_kit_api.DiscoveryList `json:",inline"` +} + +func getExtensionList() ExtensionListResponse { + return ExtensionListResponse{ + // See this document to learn more about the action list: + // https://github.com/steadybit/action-kit/blob/main/docs/action-api.md#action-list + ActionList: action_kit_sdk.GetActionList(), + + // See this document to learn more about the discovery list: + // https://github.com/steadybit/discovery-kit/blob/main/docs/discovery-api.md#index-response + DiscoveryList: discovery_kit_sdk.GetDiscoveryList(), + } +} From 44c568f6a4d320ce2f01d61108503a200e7f9a97 Mon Sep 17 00:00:00 2001 From: Ansgar Schulte <1299623+ansgarschulte@users.noreply.github.com> Date: Tue, 16 Jan 2024 21:17:43 +0100 Subject: [PATCH 2/3] fix: e2e test --- charts/steadybit-extension-postman/templates/deployment.yaml | 2 +- e2e/integration_test.go | 3 +-- e2e/mock_postman_server_test.go | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/steadybit-extension-postman/templates/deployment.yaml b/charts/steadybit-extension-postman/templates/deployment.yaml index 05e3a95..eeaedaa 100644 --- a/charts/steadybit-extension-postman/templates/deployment.yaml +++ b/charts/steadybit-extension-postman/templates/deployment.yaml @@ -49,7 +49,7 @@ spec: memory: {{ .Values.resources.limits.memory }} cpu: {{ .Values.resources.limits.cpu }} env: - - name: POSTMAN_API_KEY + - name: STEADYBIT_EXTENSION_POSTMAN_API_KEY valueFrom: secretKeyRef: name: {{ include "postman.secret.name" . }} diff --git a/e2e/integration_test.go b/e2e/integration_test.go index 519c091..366c2f4 100644 --- a/e2e/integration_test.go +++ b/e2e/integration_test.go @@ -27,7 +27,7 @@ func TestWithMinikube(t *testing.T) { ExtraArgs: func(m *e2e.Minikube) []string { return []string{ "--set", "logging.level=debug", - "--set", "STEADYBIT_EXTENSION_POSTMAN_API_KEY=testApiKey", + "--set", "postman.apiKey=testApiKey", "--set", "extraEnv[0].name=STEADYBIT_EXTENSION_POSTMAN_BASE_URL", "--set", fmt.Sprintf("extraEnv[0].value=%s:%s", "http://host.minikube.internal:", port), } @@ -47,7 +47,6 @@ func testRunPostman(t *testing.T, m *e2e.Minikube, e *e2e.Extension) { }{ } - collectionId := "5f757f0d-de24-462c-867f-256bb696d2dd" target := action_kit_api.Target{ Attributes: map[string][]string{ "postman.collection.id": {collectionId}, diff --git a/e2e/mock_postman_server_test.go b/e2e/mock_postman_server_test.go index cae54ca..43e66ff 100644 --- a/e2e/mock_postman_server_test.go +++ b/e2e/mock_postman_server_test.go @@ -9,6 +9,7 @@ import ( "strings" ) +const collectionId = "5f757f0d-de24-462c-867f-256bb696d2dd" func createMockPostmanServer() *httptest.Server { listener, err := net.Listen("tcp", "0.0.0.0:0") if err != nil { @@ -18,7 +19,7 @@ func createMockPostmanServer() *httptest.Server { Listener: listener, Config: &http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Info().Str("path", r.URL.Path).Str("method", r.Method).Str("query", r.URL.RawQuery).Msg("Request received") - if strings.Contains(r.URL.Path, "collections/testCollectionId") { + if strings.Contains(r.URL.Path, "collections/" + collectionId) { w.WriteHeader(http.StatusOK) w.Write(getCollection()) } else { From 760861381ba8d8701872e92d145b75432923039d Mon Sep 17 00:00:00 2001 From: Ansgar Schulte <1299623+ansgarschulte@users.noreply.github.com> Date: Wed, 17 Jan 2024 13:54:39 +0100 Subject: [PATCH 3/3] test: add e2e tests --- README.md | 8 +- charts/steadybit-extension-postman/Chart.yaml | 4 +- .../__snapshot__/deployment_test.yaml.snap | 45 ++++++++++ e2e/integration_test.go | 83 ++++++++++++++++++- e2e/mock_postman_server_test.go | 31 ++++++- extpostman/action_run.go | 14 ++-- extpostman/action_run_test.go | 18 ++-- extpostman/collection_api.go | 4 +- extpostman/common.go | 4 +- extpostman/discovery.go | 6 +- extpostman/environment_api.go | 10 ++- go.mod | 2 +- main.go | 1 - 13 files changed, 194 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 6ef91b6..2bfc899 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,10 @@ Learn about the capabilities of this extension in our [Reliability Hub](https:// Postman_Api_Key ## Configuration -| Environment Variable | Helm value | Meaning | Required | Default | -|----------------------|------------------------|-------------------------------------------------------------|----------|---------| -| `HTTPS_PROXY` | via extraEnv variables | Configure the proxy to be used for Postman communication. | no | | -| `POSTMAN_API_KEY` | postman.apiKey | Configure the api-key to be used for Postman communication. | yes | | +| Environment Variable | Helm value | Meaning | Required | Default | +|---------------------------------------|------------------------|-------------------------------------------------------------|----------|---------| +| `HTTPS_PROXY` | via extraEnv variables | Configure the proxy to be used for Postman communication. | no | | +| `STEADYBIT_EXTENSION_POSTMAN_API_KEY` | postman.apiKey | Configure the api-key to be used for Postman communication. | yes | | The extension supports all environment variables provided by [steadybit/extension-kit](https://github.com/steadybit/extension-kit#environment-variables). diff --git a/charts/steadybit-extension-postman/Chart.yaml b/charts/steadybit-extension-postman/Chart.yaml index 297cd78..d162b1a 100644 --- a/charts/steadybit-extension-postman/Chart.yaml +++ b/charts/steadybit-extension-postman/Chart.yaml @@ -1,13 +1,15 @@ apiVersion: v2 name: steadybit-extension-postman description: Steadybit Postman extension Helm chart for Kubernetes. -version: 1.6.27 +version: 1.6.28 appVersion: latest home: https://www.steadybit.com/ icon: https://steadybit-website-assets.s3.amazonaws.com/logo-symbol-transparent.png maintainers: - email: daniel.reuter@steadybit.com name: reuda + - email: ansgar.schulte@steadybit.com + name: ansgarschulte sources: - https://github.com/steadybit/extension-postman annotations: diff --git a/charts/steadybit-extension-postman/tests/__snapshot__/deployment_test.yaml.snap b/charts/steadybit-extension-postman/tests/__snapshot__/deployment_test.yaml.snap index 3751fa7..dfa8fb9 100644 --- a/charts/steadybit-extension-postman/tests/__snapshot__/deployment_test.yaml.snap +++ b/charts/steadybit-extension-postman/tests/__snapshot__/deployment_test.yaml.snap @@ -28,6 +28,11 @@ manifest should match snapshot using podAnnotations and Labels: spec: containers: - env: + - name: STEADYBIT_EXTENSION_POSTMAN_API_KEY + valueFrom: + secretKeyRef: + key: apiKey + name: steadybit-extension-postman - name: STEADYBIT_LOG_LEVEL value: INFO - name: STEADYBIT_LOG_FORMAT @@ -104,6 +109,11 @@ manifest should match snapshot with TLS: spec: containers: - env: + - name: STEADYBIT_EXTENSION_POSTMAN_API_KEY + valueFrom: + secretKeyRef: + key: apiKey + name: steadybit-extension-postman - name: STEADYBIT_LOG_LEVEL value: INFO - name: STEADYBIT_LOG_FORMAT @@ -191,6 +201,11 @@ manifest should match snapshot with extra env vars: spec: containers: - env: + - name: STEADYBIT_EXTENSION_POSTMAN_API_KEY + valueFrom: + secretKeyRef: + key: apiKey + name: steadybit-extension-postman - name: STEADYBIT_LOG_LEVEL value: INFO - name: STEADYBIT_LOG_FORMAT @@ -276,6 +291,11 @@ manifest should match snapshot with extra labels: spec: containers: - env: + - name: STEADYBIT_EXTENSION_POSTMAN_API_KEY + valueFrom: + secretKeyRef: + key: apiKey + name: steadybit-extension-postman - name: STEADYBIT_LOG_LEVEL value: INFO - name: STEADYBIT_LOG_FORMAT @@ -352,6 +372,11 @@ manifest should match snapshot with mutual TLS: spec: containers: - env: + - name: STEADYBIT_EXTENSION_POSTMAN_API_KEY + valueFrom: + secretKeyRef: + key: apiKey + name: steadybit-extension-postman - name: STEADYBIT_LOG_LEVEL value: INFO - name: STEADYBIT_LOG_FORMAT @@ -448,6 +473,11 @@ manifest should match snapshot with mutual TLS using containerPaths: spec: containers: - env: + - name: STEADYBIT_EXTENSION_POSTMAN_API_KEY + valueFrom: + secretKeyRef: + key: apiKey + name: steadybit-extension-postman - name: STEADYBIT_LOG_LEVEL value: INFO - name: STEADYBIT_LOG_FORMAT @@ -530,6 +560,11 @@ manifest should match snapshot with podSecurityContext: spec: containers: - env: + - name: STEADYBIT_EXTENSION_POSTMAN_API_KEY + valueFrom: + secretKeyRef: + key: apiKey + name: steadybit-extension-postman - name: STEADYBIT_LOG_LEVEL value: INFO - name: STEADYBIT_LOG_FORMAT @@ -608,6 +643,11 @@ manifest should match snapshot with priority class: spec: containers: - env: + - name: STEADYBIT_EXTENSION_POSTMAN_API_KEY + valueFrom: + secretKeyRef: + key: apiKey + name: steadybit-extension-postman - name: STEADYBIT_LOG_LEVEL value: INFO - name: STEADYBIT_LOG_FORMAT @@ -685,6 +725,11 @@ manifest should match snapshot without TLS: spec: containers: - env: + - name: STEADYBIT_EXTENSION_POSTMAN_API_KEY + valueFrom: + secretKeyRef: + key: apiKey + name: steadybit-extension-postman - name: STEADYBIT_LOG_LEVEL value: INFO - name: STEADYBIT_LOG_FORMAT diff --git a/e2e/integration_test.go b/e2e/integration_test.go index 366c2f4..d5a3386 100644 --- a/e2e/integration_test.go +++ b/e2e/integration_test.go @@ -4,10 +4,15 @@ package e2e import ( + "context" "fmt" + "github.com/rs/zerolog/log" "github.com/steadybit/action-kit/go/action_kit_api/v2" "github.com/steadybit/action-kit/go/action_kit_test/e2e" + "github.com/steadybit/discovery-kit/go/discovery_kit_api" + "github.com/steadybit/discovery-kit/go/discovery_kit_test/validate" "github.com/steadybit/extension-kit/extlogging" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "strings" "testing" @@ -29,22 +34,97 @@ func TestWithMinikube(t *testing.T) { "--set", "logging.level=debug", "--set", "postman.apiKey=testApiKey", "--set", "extraEnv[0].name=STEADYBIT_EXTENSION_POSTMAN_BASE_URL", - "--set", fmt.Sprintf("extraEnv[0].value=%s:%s", "http://host.minikube.internal:", port), + "--set", fmt.Sprintf("extraEnv[0].value=%s:%s", "http://host.minikube.internal", port), } }, } e2e.WithDefaultMinikube(t, &extFactory, []e2e.WithMinikubeTestCase{ + { + Name: "validate discovery", + Test: validateDiscovery, + }, + { + Name: "target discovery", + Test: testDiscovery, + }, { Name: "run postman", Test: testRunPostman, }, + { + Name: "run postman with env name", + Test: testRunPostmanWithEnvName, + }, + { + Name: "run postman with env id", + Test: testRunPostmanWithEnvId, + }, + }) +} + +func validateDiscovery(t *testing.T, _ *e2e.Minikube, e *e2e.Extension) { + assert.NoError(t, validate.ValidateEndpointReferences("/", e.Client)) +} + +func testDiscovery(t *testing.T, _ *e2e.Minikube, e *e2e.Extension) { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + target, err := e2e.PollForTarget(ctx, e, "com.steadybit.extension_postman.collection", func(target discovery_kit_api.Target) bool { + log.Info().Msgf("Checking target: %s", target) + return e2e.HasAttribute(target, "steadybit.label", "shopping-demo") }) + + require.NoError(t, err) + assert.Equal(t, target.TargetType, "com.steadybit.extension_postman.collection") + assert.Equal(t, target.Attributes["postman.collection.id"], []string{collectionId}) + assert.Equal(t, target.Attributes["postman.collection.name"], []string{"shopping-demo"}) } func testRunPostman(t *testing.T, m *e2e.Minikube, e *e2e.Extension) { config := struct { + }{} + + target := action_kit_api.Target{ + Attributes: map[string][]string{ + "postman.collection.id": {collectionId}, + }, + } + + exec, err := e.RunAction("com.steadybit.extension_postman.collection.run.v2", &target, config, nil) + require.NoError(t, err) + e2e.AssertLogContainsWithTimeout(t, m, e.Pod, "Starting newman!", 90*time.Second) + e2e.AssertLogContainsWithTimeout(t, m, e.Pod, "Postman run completed successfully", 90*time.Second) + require.NoError(t, exec.Cancel()) +} + +func testRunPostmanWithEnvId(t *testing.T, m *e2e.Minikube, e *e2e.Extension) { + config := struct { + EnvironmentIdOrName string + }{ + EnvironmentIdOrName: "70cb2138-3443-4c33-a45c-73477a5fd903", + } + + target := action_kit_api.Target{ + Attributes: map[string][]string{ + "postman.collection.id": {collectionId}, + }, + } + + exec, err := e.RunAction("com.steadybit.extension_postman.collection.run.v2", &target, config, nil) + require.NoError(t, err) + e2e.AssertLogContainsWithTimeout(t, m, e.Pod, "--environment", 90*time.Second) + e2e.AssertLogContainsWithTimeout(t, m, e.Pod, "Starting newman!", 90*time.Second) + e2e.AssertLogContainsWithTimeout(t, m, e.Pod, "Postman run completed successfully", 90*time.Second) + require.NoError(t, exec.Cancel()) +} + +func testRunPostmanWithEnvName(t *testing.T, m *e2e.Minikube, e *e2e.Extension) { + config := struct { + EnvironmentIdOrName string }{ + EnvironmentIdOrName: "dev", } target := action_kit_api.Target{ @@ -55,6 +135,7 @@ func testRunPostman(t *testing.T, m *e2e.Minikube, e *e2e.Extension) { exec, err := e.RunAction("com.steadybit.extension_postman.collection.run.v2", &target, config, nil) require.NoError(t, err) + e2e.AssertLogContainsWithTimeout(t, m, e.Pod, "--environment", 90*time.Second) e2e.AssertLogContainsWithTimeout(t, m, e.Pod, "Starting newman!", 90*time.Second) e2e.AssertLogContainsWithTimeout(t, m, e.Pod, "Postman run completed successfully", 90*time.Second) require.NoError(t, exec.Cancel()) diff --git a/e2e/mock_postman_server_test.go b/e2e/mock_postman_server_test.go index 43e66ff..6b7d979 100644 --- a/e2e/mock_postman_server_test.go +++ b/e2e/mock_postman_server_test.go @@ -10,6 +10,7 @@ import ( ) const collectionId = "5f757f0d-de24-462c-867f-256bb696d2dd" + func createMockPostmanServer() *httptest.Server { listener, err := net.Listen("tcp", "0.0.0.0:0") if err != nil { @@ -19,9 +20,15 @@ func createMockPostmanServer() *httptest.Server { Listener: listener, Config: &http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Info().Str("path", r.URL.Path).Str("method", r.Method).Str("query", r.URL.RawQuery).Msg("Request received") - if strings.Contains(r.URL.Path, "collections/" + collectionId) { + if strings.Contains(r.URL.Path, "collections/"+collectionId) { w.WriteHeader(http.StatusOK) w.Write(getCollection()) + } else if strings.Contains(r.URL.Path, "collections") { + w.WriteHeader(http.StatusOK) + w.Write(getCollections()) + } else if strings.Contains(r.URL.Path, "environments") { + w.WriteHeader(http.StatusOK) + w.Write(getEnvironments()) } else { w.WriteHeader(http.StatusBadRequest) } @@ -36,3 +43,25 @@ func getCollection() []byte { log.Info().Msg("Return collection") return []byte(`{"collection":{"info":{"_postman_id":"1c89f353-9e9d-4daf-9442-bc64f4c1b29b","name":"Simple Get","schema":"https://schema.getpostman.com/json/collection/v2.1.0/collection.json","updatedAt":"2023-09-14T11:22:30.000Z","uid":"21222108-1c89f353-9e9d-4daf-9442-bc64f4c1b29b"},"item":[{"name":"Is google online","event":[{"listen":"test","script":{"id":"13df8fb5-f68d-4822-93b4-a6a67c512420","exec":["pm.test(\"Body matches string\", function () {"," pm.expect(pm.response.text()).to.include(\"Google\");","});"],"type":"text/javascript"}}],"id":"fd6c6e49-dbf2-4f21-92ef-c0a2bf10b426","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":{"raw":"https://www.google.de","protocol":"https","host":["www","google","de"]}},"response":[],"uid":"21222108-fd6c6e49-dbf2-4f21-92ef-c0a2bf10b426"}]}}`) } + +func getCollections() []byte { + log.Info().Msg("Return collection") + return []byte(`{ + "collections": [ + { + "id": "5f757f0d-de24-462c-867f-256bb696d2dd", + "name": "shopping-demo", + "owner": "1111111", + "createdAt": "2022-06-01T13:20:10.000Z", + "updatedAt": "2023-03-10T13:26:48.000Z", + "uid": "1111111-5f757f0d-de24-462c-867f-256bb696d2dd", + "isPublic": false + } + ] +}`) +} + +func getEnvironments() []byte { + log.Info().Msg("Return environments") + return []byte(`{"environments":[{"id":"70cb2138-3443-4c33-a45c-73477a5fd903","name":"dev","createdAt":"2022-10-04T14:02:50.000Z","updatedAt":"2022-10-05T11:28:57.000Z","owner":"123456","uid":"21211108-11cb2538-1111-1111-a45c-11177a5fd903","isPublic":false}]}`) +} diff --git a/extpostman/action_run.go b/extpostman/action_run.go index 8667c44..be64011 100644 --- a/extpostman/action_run.go +++ b/extpostman/action_run.go @@ -35,13 +35,13 @@ type PostmanState struct { } type PostmanConfig struct { - EnvironmentIdOrName string - Environment []map[string]string - Verbose bool - Bail bool - Timeout int - TimeoutRequest int - Iterations int + EnvironmentIdOrName string + Environment []map[string]string + Verbose bool + Bail bool + Timeout int + TimeoutRequest int + Iterations int } func NewPostmanAction() action_kit_sdk.Action[PostmanState] { diff --git a/extpostman/action_run_test.go b/extpostman/action_run_test.go index 12b7cab..b2468b4 100644 --- a/extpostman/action_run_test.go +++ b/extpostman/action_run_test.go @@ -24,9 +24,9 @@ func TestPrepareCollectionRun(t *testing.T) { // Given requestBody := extutil.JsonMangle(action_kit_api.PrepareActionRequestBody{ Config: map[string]interface{}{ - "duration": 60000, + "duration": 60000, "EnvironmentIdOrName": "5f757f0d-de24-462c-867f-256bb696d2dd", - "iterations": 2, + "iterations": 2, "environment": []map[string]string{ {"key": "Test1", "value": "foo"}, {"key": "Test2", "value": "bar"}, @@ -61,13 +61,13 @@ func TestPrepareCollectionRunWithEmptyEnvironment(t *testing.T) { // Given requestBody := extutil.JsonMangle(action_kit_api.PrepareActionRequestBody{ Config: map[string]interface{}{ - "duration": 60000, - "EnvironmentIdOrName": "5f757f0d-de24-462c-867f-256bb696d2dd", - "iterations": 2, - "environment": []map[string]string{}, - "timeout": 30000, - "timeoutRequest": 30000, - "verbose": true, + "duration": 60000, + "EnvironmentIdOrName": "5f757f0d-de24-462c-867f-256bb696d2dd", + "iterations": 2, + "environment": []map[string]string{}, + "timeout": 30000, + "timeoutRequest": 30000, + "verbose": true, }, Target: &action_kit_api.Target{ Attributes: map[string][]string{ diff --git a/extpostman/collection_api.go b/extpostman/collection_api.go index 0741186..469af73 100644 --- a/extpostman/collection_api.go +++ b/extpostman/collection_api.go @@ -13,9 +13,10 @@ type PostmanCollectionResult struct { Collections []PostmanCollection `json:"collections"` } type PostmanCollection struct { - Id string `json:"id"` + Id string `json:"id"` Name string `json:"name"` } + func GetPostmanCollections() []PostmanCollection { var specification = config.Config var apiKey = specification.PostmanApiKey @@ -29,7 +30,6 @@ func GetPostmanCollections() []PostmanCollection { parameters.Add("apikey", apiKey) collectionsUrl.RawQuery = parameters.Encode() - response, err := http.Get(collectionsUrl.String()) if err != nil { log.Error().Msgf("Failed to get collections from postman api. Got error: %s", err) diff --git a/extpostman/common.go b/extpostman/common.go index c122b76..dda3cec 100644 --- a/extpostman/common.go +++ b/extpostman/common.go @@ -4,6 +4,6 @@ package extpostman const ( - targetID = "com.steadybit.extension_postman.collection" - icon = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTMuNTI3LjA5OUM2Ljk1NS0uNzQ0Ljk0MiAzLjkuMDk5IDEwLjQ3M2MtLjg0MyA2LjU3MiAzLjggMTIuNTg0IDEwLjM3MyAxMy40MjggNi41NzMuODQzIDEyLjU4Ny0zLjgwMSAxMy40MjgtMTAuMzc0QzI0Ljc0NCA2Ljk1NSAyMC4xMDEuOTQzIDEzLjUyNy4wOTl6bTIuNDcxIDcuNDg1YS44NTUuODU1IDAgMDAtLjU5My4yNWwtNC40NTMgNC40NTMtLjMwNy0uMzA3LS42NDMtLjY0M2M0LjM4OS00LjM3NiA1LjE4LTQuNDE4IDUuOTk2LTMuNzUzem0tNC44NjMgNC44NjFsNC40NC00LjQ0YS42Mi42MiAwIDExLjg0Ny45MDNsLTQuNjk5IDQuMTI1LS41ODgtLjU4OHptLjMzLjY5NGwtMS4xLjIzOGEuMDYuMDYgMCAwMS0uMDY3LS4wMzIuMDYuMDYgMCAwMS4wMS0uMDczbC42NDUtLjY0NS41MTIuNTEyem0tMi44MDMtLjQ1OWwxLjE3Mi0xLjE3Mi44NzkuODc4LTEuOTc5LjQyNmEuMDc0LjA3NCAwIDAxLS4wODUtLjAzOS4wNzIuMDcyIDAgMDEuMDEzLS4wOTN6bS0zLjY0NiA2LjA1OGEuMDc2LjA3NiAwIDAxLS4wNjktLjA4My4wNzcuMDc3IDAgMDEuMDIyLS4wNDZoLjAwMmwuOTQ2LS45NDYgMS4yMjIgMS4yMjItMi4xMjMtLjE0N3ptMi40MjUtMS4yNTZhLjIyOC4yMjggMCAwMC0uMTE3LjI1NmwuMjAzLjg2NWEuMTI1LjEyNSAwIDAxLS4yMTEuMTE3aC0uMDAzbC0uOTM0LS45MzQtLjI5NC0uMjk1IDMuNzYyLTMuNzU4IDEuODItLjM5My44NzQuODc0Yy0xLjI1NSAxLjEwMi0yLjk3MSAyLjIwMS01LjEgMy4yNjh6bTUuMjc5LTMuNDI4aC0uMDAybC0uODM5LS44MzkgNC42OTktNC4xMjVhLjk1Mi45NTIgMCAwMC4xMTktLjEyN2MtLjE0OCAxLjM0NS0yLjAyOSAzLjI0NS0zLjk3NyA1LjA5MXptMy42NTctNi40NmwtLjAwMy0uMDAyYTEuODIyIDEuODIyIDAgMDEyLjQ1OS0yLjY4NGwtMS42MSAxLjYxM2EuMTE5LjExOSAwIDAwMCAuMTY5bDEuMjQ3IDEuMjQ3YTEuODE3IDEuODE3IDAgMDEtMi4wOTMtLjM0M3ptMi41NzggMGExLjcxNCAxLjcxNCAwIDAxLS4yNzEuMjE4aC0uMDAxbC0xLjIwNy0xLjIwNyAxLjUzMy0xLjUzM2MuNjYxLjcyLjYzNyAxLjgzMi0uMDU0IDIuNTIyem0tLjEtMS41NDRhLjE0My4xNDMgMCAwMC0uMDUzLjE1Ny40MTYuNDE2IDAgMDEtLjA1My40NS4xNC4xNCAwIDAwLjAyMy4xOTcuMTQxLjE0MSAwIDAwLjA4NC4wMy4xNC4xNCAwIDAwLjEwNi0uMDUuNjkxLjY5MSAwIDAwLjA4Ny0uNzUxLjEzOC4xMzggMCAwMC0uMTk0LS4wMzN6IiBmaWxsPSJjdXJyZW50Q29sb3IiLz48L3N2Zz4=" + targetID = "com.steadybit.extension_postman.collection" + icon = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTMuNTI3LjA5OUM2Ljk1NS0uNzQ0Ljk0MiAzLjkuMDk5IDEwLjQ3M2MtLjg0MyA2LjU3MiAzLjggMTIuNTg0IDEwLjM3MyAxMy40MjggNi41NzMuODQzIDEyLjU4Ny0zLjgwMSAxMy40MjgtMTAuMzc0QzI0Ljc0NCA2Ljk1NSAyMC4xMDEuOTQzIDEzLjUyNy4wOTl6bTIuNDcxIDcuNDg1YS44NTUuODU1IDAgMDAtLjU5My4yNWwtNC40NTMgNC40NTMtLjMwNy0uMzA3LS42NDMtLjY0M2M0LjM4OS00LjM3NiA1LjE4LTQuNDE4IDUuOTk2LTMuNzUzem0tNC44NjMgNC44NjFsNC40NC00LjQ0YS42Mi42MiAwIDExLjg0Ny45MDNsLTQuNjk5IDQuMTI1LS41ODgtLjU4OHptLjMzLjY5NGwtMS4xLjIzOGEuMDYuMDYgMCAwMS0uMDY3LS4wMzIuMDYuMDYgMCAwMS4wMS0uMDczbC42NDUtLjY0NS41MTIuNTEyem0tMi44MDMtLjQ1OWwxLjE3Mi0xLjE3Mi44NzkuODc4LTEuOTc5LjQyNmEuMDc0LjA3NCAwIDAxLS4wODUtLjAzOS4wNzIuMDcyIDAgMDEuMDEzLS4wOTN6bS0zLjY0NiA2LjA1OGEuMDc2LjA3NiAwIDAxLS4wNjktLjA4My4wNzcuMDc3IDAgMDEuMDIyLS4wNDZoLjAwMmwuOTQ2LS45NDYgMS4yMjIgMS4yMjItMi4xMjMtLjE0N3ptMi40MjUtMS4yNTZhLjIyOC4yMjggMCAwMC0uMTE3LjI1NmwuMjAzLjg2NWEuMTI1LjEyNSAwIDAxLS4yMTEuMTE3aC0uMDAzbC0uOTM0LS45MzQtLjI5NC0uMjk1IDMuNzYyLTMuNzU4IDEuODItLjM5My44NzQuODc0Yy0xLjI1NSAxLjEwMi0yLjk3MSAyLjIwMS01LjEgMy4yNjh6bTUuMjc5LTMuNDI4aC0uMDAybC0uODM5LS44MzkgNC42OTktNC4xMjVhLjk1Mi45NTIgMCAwMC4xMTktLjEyN2MtLjE0OCAxLjM0NS0yLjAyOSAzLjI0NS0zLjk3NyA1LjA5MXptMy42NTctNi40NmwtLjAwMy0uMDAyYTEuODIyIDEuODIyIDAgMDEyLjQ1OS0yLjY4NGwtMS42MSAxLjYxM2EuMTE5LjExOSAwIDAwMCAuMTY5bDEuMjQ3IDEuMjQ3YTEuODE3IDEuODE3IDAgMDEtMi4wOTMtLjM0M3ptMi41NzggMGExLjcxNCAxLjcxNCAwIDAxLS4yNzEuMjE4aC0uMDAxbC0xLjIwNy0xLjIwNyAxLjUzMy0xLjUzM2MuNjYxLjcyLjYzNyAxLjgzMi0uMDU0IDIuNTIyem0tLjEtMS41NDRhLjE0My4xNDMgMCAwMC0uMDUzLjE1Ny40MTYuNDE2IDAgMDEtLjA1My40NS4xNC4xNCAwIDAwLjAyMy4xOTcuMTQxLjE0MSAwIDAwLjA4NC4wMy4xNC4xNCAwIDAwLjEwNi0uMDUuNjkxLjY5MSAwIDAwLjA4Ny0uNzUxLjEzOC4xMzggMCAwMC0uMTk0LS4wMzN6IiBmaWxsPSJjdXJyZW50Q29sb3IiLz48L3N2Zz4=" ) diff --git a/extpostman/discovery.go b/extpostman/discovery.go index dc81f25..ec93700 100644 --- a/extpostman/discovery.go +++ b/extpostman/discovery.go @@ -89,9 +89,9 @@ func (d *collectionDiscovery) DiscoverTargets(_ context.Context) ([]discovery_ki TargetType: targetID, Label: collection.Name, Attributes: map[string][]string{ - "steadybit.label": {collection.Name}, - "postman.collection.id": {collection.Id}, - "postman.collection.name": {collection.Name}, + "steadybit.label": {collection.Name}, + "postman.collection.id": {collection.Id}, + "postman.collection.name": {collection.Name}, }, } } diff --git a/extpostman/environment_api.go b/extpostman/environment_api.go index d9178d4..672a1aa 100644 --- a/extpostman/environment_api.go +++ b/extpostman/environment_api.go @@ -12,25 +12,28 @@ import ( ) type PostmanEnvironmentResult struct { - Environments []PostmanEnvironment `json:"Environments"` + Environments []PostmanEnvironment `json:"environments"` } type PostmanEnvironment struct { - Id string `json:"id"` + Id string `json:"id"` Name string `json:"name"` } func GetPostEnvironmentId(environmentIdOrName string) (string, error) { - //check if uuid + log.Info().Msgf("Searching for environment with id or name '%s'", environmentIdOrName) environmentId, err := uuid.Parse(environmentIdOrName) if err == nil { + log.Info().Msgf("Found environment id '%s'", environmentId.String()) return environmentId.String(), nil } environments := GetPostmanEnvironments() + log.Info().Msgf("Found %d environments", len(environments)) var uniqueEnvironmentId string counter := 0 for _, environment := range environments { if environment.Name == environmentIdOrName { + log.Info().Msgf("Found environment with name '%s' and id '%s'", environment.Name, environment.Id) counter++ uniqueEnvironmentId = environment.Id } @@ -57,7 +60,6 @@ func GetPostmanEnvironments() []PostmanEnvironment { parameters.Add("apikey", apiKey) EnvironmentsUrl.RawQuery = parameters.Encode() - response, err := http.Get(EnvironmentsUrl.String()) if err != nil { log.Error().Msgf("Failed to get Environments from postman api. Got error: %s", err) diff --git a/go.mod b/go.mod index 371eb4f..1033374 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/steadybit/discovery-kit/go/discovery_kit_api v1.5.0 github.com/steadybit/discovery-kit/go/discovery_kit_commons v0.1.0 github.com/steadybit/discovery-kit/go/discovery_kit_sdk v1.0.4 + github.com/steadybit/discovery-kit/go/discovery_kit_test v1.1.2 github.com/steadybit/extension-kit v1.8.11 github.com/stretchr/testify v1.8.4 @@ -91,7 +92,6 @@ require ( github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/steadybit/discovery-kit/go/discovery_kit_test v1.1.2 // indirect github.com/tdewolff/minify/v2 v2.20.7 // indirect github.com/tdewolff/parse/v2 v2.7.5 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect diff --git a/main.go b/main.go index 84a2eae..77f1cfa 100644 --- a/main.go +++ b/main.go @@ -38,7 +38,6 @@ func main() { }) } - // ExtensionListResponse exists to merge the possible root path responses supported by the // various extension kits. In this case, the response for ActionKit, DiscoveryKit and EventKit. type ExtensionListResponse struct {