From 582d76cb0f198ee2939b372391ea7f6c6f056df1 Mon Sep 17 00:00:00 2001 From: chrisghill Date: Mon, 12 Jan 2026 12:51:47 -0700 Subject: [PATCH 1/2] update artifact pull/create to use payload --- cmd/artifact.go | 12 ++-- cmd/templates/artifact.get.md.tmpl | 4 +- pkg/api/artifact.go | 8 +-- pkg/api/artifact_test.go | 39 +++++++++-- pkg/api/artifacts_test.go | 41 ------------ pkg/api/genqlient.graphql | 7 +- pkg/api/schema.graphql | 46 ++++++++++--- pkg/api/zz_generated.go | 103 ++++++++++------------------- pkg/artifact/types.go | 5 +- pkg/commands/artifact/import.go | 2 +- 10 files changed, 125 insertions(+), 142 deletions(-) delete mode 100644 pkg/api/artifacts_test.go diff --git a/cmd/artifact.go b/cmd/artifact.go index 4417006a..7340bb1d 100644 --- a/cmd/artifact.go +++ b/cmd/artifact.go @@ -176,11 +176,11 @@ func runArtifactDownload(cmd *cobra.Command, args []string) error { } func renderArtifact(artifact *api.Artifact) error { - specsJSON := "{}" - if artifact.Specs != nil { - specsBytes, err := json.MarshalIndent(artifact.Specs, "", " ") + prettyPayload := "{}" + if artifact.Payload != nil { + payloadBytes, err := json.MarshalIndent(artifact.Payload, "", " ") if err == nil { - specsJSON = string(specsBytes) + prettyPayload = string(payloadBytes) } } @@ -200,7 +200,7 @@ func renderArtifact(artifact *api.Artifact) error { Type string Field string Origin string - SpecsJSON string + Payload string Formats []string CreatedAt string UpdatedAt string @@ -212,7 +212,7 @@ func renderArtifact(artifact *api.Artifact) error { Type: artifact.Type, Field: artifact.Field, Origin: artifact.Origin, - SpecsJSON: specsJSON, + Payload: prettyPayload, Formats: artifact.Formats, CreatedAt: artifact.CreatedAt.Format("2006-01-02 15:04:05"), UpdatedAt: artifact.UpdatedAt.Format("2006-01-02 15:04:05"), diff --git a/cmd/templates/artifact.get.md.tmpl b/cmd/templates/artifact.get.md.tmpl index 259b8dae..7e1015ee 100644 --- a/cmd/templates/artifact.get.md.tmpl +++ b/cmd/templates/artifact.get.md.tmpl @@ -18,8 +18,8 @@ {{if .Formats}}**Available Formats:** {{range $i, $f := .Formats}}{{if $i}}, {{end}}{{$f}}{{end}}{{end}} -{{if ne .SpecsJSON "{}"}}## Specs +{{if ne .Payload "{}"}}## Payload ```json -{{.SpecsJSON}} +{{.Payload}} ``` {{end}} diff --git a/pkg/api/artifact.go b/pkg/api/artifact.go index bc10aff6..3a635adb 100644 --- a/pkg/api/artifact.go +++ b/pkg/api/artifact.go @@ -17,7 +17,7 @@ type Artifact struct { Name string `json:"name"` Type string `json:"type"` Field string `json:"field,omitempty"` - Specs map[string]any `json:"specs,omitempty"` + Payload map[string]any `json:"payload,omitempty"` Formats []string `json:"formats,omitempty"` CreatedAt time.Time `json:"createdAt,omitempty"` UpdatedAt time.Time `json:"updatedAt,omitempty"` @@ -34,8 +34,8 @@ type ArtifactPackage struct { Slug string `json:"slug"` } -func CreateArtifact(ctx context.Context, mdClient *client.Client, artifactName string, artifactType string, artifactData map[string]any, artifactSpecs map[string]any) (*Artifact, error) { - response, err := createArtifact(ctx, mdClient.GQL, mdClient.Config.OrganizationID, artifactName, artifactSpecs, artifactType, artifactData) +func CreateArtifact(ctx context.Context, mdClient *client.Client, artifactName string, artifactType string, artifactPayload map[string]any) (*Artifact, error) { + response, err := createArtifact(ctx, mdClient.GQL, mdClient.Config.OrganizationID, artifactName, artifactType, artifactPayload) if err != nil { return nil, err } @@ -75,7 +75,7 @@ func (response *getArtifactResponse) toArtifact() *Artifact { Name: response.Artifact.Name, Type: response.Artifact.Type, Field: response.Artifact.Field, - Specs: response.Artifact.Specs, + Payload: response.Artifact.Payload, Formats: response.Artifact.Formats, CreatedAt: response.Artifact.CreatedAt, UpdatedAt: response.Artifact.UpdatedAt, diff --git a/pkg/api/artifact_test.go b/pkg/api/artifact_test.go index edfaa6c7..a62433ba 100644 --- a/pkg/api/artifact_test.go +++ b/pkg/api/artifact_test.go @@ -12,6 +12,37 @@ import ( "github.com/massdriver-cloud/massdriver-sdk-go/massdriver/config" ) +func TestCreateArtifact(t *testing.T) { + gqlClient := gqlmock.NewClientWithSingleJSONResponse(map[string]any{ + "data": map[string]any{ + "createArtifact": map[string]any{ + "result": map[string]any{ + "id": "artifact-id", + "name": "artifact-name", + }, + "successful": true, + }, + }, + }) + mdClient := client.Client{ + GQL: gqlClient, + } + + got, err := api.CreateArtifact(t.Context(), &mdClient, "artifact-name", "artifact-type", map[string]any{}) + if err != nil { + t.Fatal(err) + } + + want := &api.Artifact{ + Name: "artifact-name", + ID: "artifact-id", + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("Wanted %v but got %v", want, got) + } +} + func TestGetArtifact(t *testing.T) { type test struct { name string @@ -26,7 +57,7 @@ func TestGetArtifact(t *testing.T) { "name": "my-artifact", "type": "aws-s3", "field": "bucket", - "specs": map[string]any{ + "payload": map[string]any{ "bucket": "my-bucket", }, "formats": []string{"json", "yaml"}, @@ -48,7 +79,7 @@ func TestGetArtifact(t *testing.T) { Name: "my-artifact", Type: "aws-s3", Field: "bucket", - Specs: map[string]any{ + Payload: map[string]any{ "bucket": "my-bucket", }, Formats: []string{"json", "yaml"}, @@ -100,8 +131,8 @@ func TestGetArtifact(t *testing.T) { if got.Origin != tc.want.Origin { t.Errorf("got Origin %v, want %v", got.Origin, tc.want.Origin) } - if !reflect.DeepEqual(got.Specs, tc.want.Specs) { - t.Errorf("got Specs %v, want %v", got.Specs, tc.want.Specs) + if !reflect.DeepEqual(got.Payload, tc.want.Payload) { + t.Errorf("got Payload %v, want %v", got.Payload, tc.want.Payload) } if !reflect.DeepEqual(got.Formats, tc.want.Formats) { t.Errorf("got Formats %v, want %v", got.Formats, tc.want.Formats) diff --git a/pkg/api/artifacts_test.go b/pkg/api/artifacts_test.go deleted file mode 100644 index d1ced0d3..00000000 --- a/pkg/api/artifacts_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package api_test - -import ( - "reflect" - "testing" - - "github.com/massdriver-cloud/mass/pkg/api" - "github.com/massdriver-cloud/mass/pkg/gqlmock" - "github.com/massdriver-cloud/massdriver-sdk-go/massdriver/client" -) - -func TestCreateArtifact(t *testing.T) { - gqlClient := gqlmock.NewClientWithSingleJSONResponse(map[string]any{ - "data": map[string]any{ - "createArtifact": map[string]any{ - "result": map[string]any{ - "id": "artifact-id", - "name": "artifact-name", - }, - "successful": true, - }, - }, - }) - mdClient := client.Client{ - GQL: gqlClient, - } - - got, err := api.CreateArtifact(t.Context(), &mdClient, "artifact-name", "artifact-type", map[string]any{}, map[string]any{}) - if err != nil { - t.Fatal(err) - } - - want := &api.Artifact{ - Name: "artifact-name", - ID: "artifact-id", - } - - if !reflect.DeepEqual(got, want) { - t.Errorf("Wanted %v but got %v", want, got) - } -} diff --git a/pkg/api/genqlient.graphql b/pkg/api/genqlient.graphql index 2384db4f..d5d91674 100644 --- a/pkg/api/genqlient.graphql +++ b/pkg/api/genqlient.graphql @@ -1,12 +1,11 @@ # ARTIFACTS -mutation createArtifact($organizationId: ID!, $artifactName: String!, $artifactSpecs: JSON!, $artifactType: String! $artifactData: JSON!) { +mutation createArtifact($organizationId: ID!, $artifactName: String!, $artifactType: String! $artifactPayload: JSON!) { createArtifact( organizationId: $organizationId, name: $artifactName, - specs: $artifactSpecs, type: $artifactType, - data: $artifactData + payload: $artifactPayload ) { result { name @@ -54,7 +53,7 @@ query getArtifact($organizationId: ID!, $id: ID!) { name type field - specs + payload formats createdAt updatedAt diff --git a/pkg/api/schema.graphql b/pkg/api/schema.graphql index aec9e414..5f8c9f3d 100644 --- a/pkg/api/schema.graphql +++ b/pkg/api/schema.graphql @@ -217,7 +217,7 @@ type RootQueryType { integrationTypes: [IntegrationType] "List all integrations enabled for an organization" - integrations(organizationId: ID!): [Integration] + integrations(organizationId: ID!): [IntegrationConfig] environment( organizationId: ID! @@ -375,7 +375,22 @@ type RootMutationType { revokeGroupAccess(organizationId: ID!, groupId: ID!, permission: PermissionRevokeInput!): ProjectPayload "Create an artifact" - createArtifact(organizationId: ID!, name: String!, type: String!, specs: JSON!, data: JSON!): ArtifactPayload + createArtifact( + organizationId: ID! + + name: String! + + type: String! + + "[Deprecated] Use payload instead. Required when payload is not provided." + specs: JSON + + "[Deprecated] Use payload instead. Required when payload is not provided." + data: JSON + + "Artifact payload containing all artifact data. Provide this OR both data and specs." + payload: JSON + ): ArtifactPayload "Update an artifact" updateArtifact(organizationId: ID!, id: ID!, params: ArtifactUpdateParams!): ArtifactPayload @@ -478,7 +493,7 @@ type RootMutationType { enableIntegration(organizationId: ID!, integrationTypeId: String!, config: JSON!, auth: JSON!): IntegrationPayload "Disable an integration for an organization" - disableIntegration(organizationId: ID!, integrationTypeId: String!): Boolean + disableIntegration(organizationId: ID!, integrationConfigId: ID!): IntegrationConfig "Create an environment" createEnvironment(organizationId: ID!, projectId: ID!, name: String!, slug: String!, description: String): EnvironmentPayload @@ -1690,6 +1705,11 @@ type EnvironmentPayload { result: Environment } +enum IntegrationStatus { + DISABLED + ENABLED +} + type IntegrationType { name: String! id: String! @@ -1697,12 +1717,13 @@ type IntegrationType { authSchema: JSON! } -type Integration { +type IntegrationConfig { id: ID! organizationId: ID! integrationType: String! config: JSON! - auth: JSON! + status: IntegrationStatus! + resources: [String!]! createdAt: DateTime! updatedAt: DateTime! } @@ -1715,7 +1736,7 @@ type IntegrationPayload { messages: [ValidationMessage] "The object created\/updated\/deleted by the mutation. May be null if mutation failed." - result: Integration + result: IntegrationConfig } "A connection between two nodes in the diagram" @@ -2795,14 +2816,19 @@ input ArtifactsInput { filter: ArtifactsFilters } -"Allowed params used in updated artifacts. Provisioned artifacts can only have their name updated. Imported artifacts can update specs, data, or name" +"Allowed params used in updated artifacts. Provisioned artifacts can only have their name updated. Imported artifacts can update specs, data, payload, or name. Use payload for new integrations; data\/specs are deprecated." input ArtifactUpdateParams { "The new name of the artifact" name: String + "[Deprecated] Use payload instead. Artifact specs for backward compatibility." specs: JSON + "[Deprecated] Use payload instead. Artifact data for backward compatibility." data: JSON + + "Artifact payload containing all artifact data." + payload: JSON } type Artifact { @@ -2818,7 +2844,11 @@ type Artifact { "The bundle's artifact field (output field) that produced this artifact." field: String - specs: JSON + "Artifact specs for backward compatibility." + specs: JSON @deprecated(reason: "Use payload instead") + + "Complete artifact payload containing all artifact data. Fields marked with $md.sensitive in the artifact definition will be masked as [SENSITIVE]. Use downloadArtifact to retrieve unmasked values. See https:\/\/docs.massdriver.cloud\/json-schema-cheat-sheet\/massdriver-annotations for more details." + payload: JSON packageId: ID @deprecated(reason: "Use package{id} instead") diff --git a/pkg/api/zz_generated.go b/pkg/api/zz_generated.go index 0f0615c1..fde7f657 100644 --- a/pkg/api/zz_generated.go +++ b/pkg/api/zz_generated.go @@ -348,11 +348,10 @@ func (v *__containerRepositoryInput) GetInput() ContainerRepositoryInput { retur // __createArtifactInput is used internally by genqlient type __createArtifactInput struct { - OrganizationId string `json:"organizationId"` - ArtifactName string `json:"artifactName"` - ArtifactSpecs map[string]any `json:"-"` - ArtifactType string `json:"artifactType"` - ArtifactData map[string]any `json:"-"` + OrganizationId string `json:"organizationId"` + ArtifactName string `json:"artifactName"` + ArtifactType string `json:"artifactType"` + ArtifactPayload map[string]any `json:"-"` } // GetOrganizationId returns __createArtifactInput.OrganizationId, and is useful for accessing the field via an interface. @@ -361,14 +360,11 @@ func (v *__createArtifactInput) GetOrganizationId() string { return v.Organizati // GetArtifactName returns __createArtifactInput.ArtifactName, and is useful for accessing the field via an interface. func (v *__createArtifactInput) GetArtifactName() string { return v.ArtifactName } -// GetArtifactSpecs returns __createArtifactInput.ArtifactSpecs, and is useful for accessing the field via an interface. -func (v *__createArtifactInput) GetArtifactSpecs() map[string]any { return v.ArtifactSpecs } - // GetArtifactType returns __createArtifactInput.ArtifactType, and is useful for accessing the field via an interface. func (v *__createArtifactInput) GetArtifactType() string { return v.ArtifactType } -// GetArtifactData returns __createArtifactInput.ArtifactData, and is useful for accessing the field via an interface. -func (v *__createArtifactInput) GetArtifactData() map[string]any { return v.ArtifactData } +// GetArtifactPayload returns __createArtifactInput.ArtifactPayload, and is useful for accessing the field via an interface. +func (v *__createArtifactInput) GetArtifactPayload() map[string]any { return v.ArtifactPayload } func (v *__createArtifactInput) UnmarshalJSON(b []byte) error { @@ -378,8 +374,7 @@ func (v *__createArtifactInput) UnmarshalJSON(b []byte) error { var firstPass struct { *__createArtifactInput - ArtifactSpecs json.RawMessage `json:"artifactSpecs"` - ArtifactData json.RawMessage `json:"artifactData"` + ArtifactPayload json.RawMessage `json:"artifactPayload"` graphql.NoUnmarshalJSON } firstPass.__createArtifactInput = v @@ -390,27 +385,14 @@ func (v *__createArtifactInput) UnmarshalJSON(b []byte) error { } { - dst := &v.ArtifactSpecs - src := firstPass.ArtifactSpecs + dst := &v.ArtifactPayload + src := firstPass.ArtifactPayload if len(src) != 0 && string(src) != "null" { err = scalars.UnmarshalJSON( src, dst) if err != nil { return fmt.Errorf( - "unable to unmarshal __createArtifactInput.ArtifactSpecs: %w", err) - } - } - } - - { - dst := &v.ArtifactData - src := firstPass.ArtifactData - if len(src) != 0 && string(src) != "null" { - err = scalars.UnmarshalJSON( - src, dst) - if err != nil { - return fmt.Errorf( - "unable to unmarshal __createArtifactInput.ArtifactData: %w", err) + "unable to unmarshal __createArtifactInput.ArtifactPayload: %w", err) } } } @@ -422,11 +404,9 @@ type __premarshal__createArtifactInput struct { ArtifactName string `json:"artifactName"` - ArtifactSpecs json.RawMessage `json:"artifactSpecs"` - ArtifactType string `json:"artifactType"` - ArtifactData json.RawMessage `json:"artifactData"` + ArtifactPayload json.RawMessage `json:"artifactPayload"` } func (v *__createArtifactInput) MarshalJSON() ([]byte, error) { @@ -442,29 +422,17 @@ func (v *__createArtifactInput) __premarshalJSON() (*__premarshal__createArtifac retval.OrganizationId = v.OrganizationId retval.ArtifactName = v.ArtifactName - { - - dst := &retval.ArtifactSpecs - src := v.ArtifactSpecs - var err error - *dst, err = scalars.MarshalJSON( - &src) - if err != nil { - return nil, fmt.Errorf( - "unable to marshal __createArtifactInput.ArtifactSpecs: %w", err) - } - } retval.ArtifactType = v.ArtifactType { - dst := &retval.ArtifactData - src := v.ArtifactData + dst := &retval.ArtifactPayload + src := v.ArtifactPayload var err error *dst, err = scalars.MarshalJSON( &src) if err != nil { return nil, fmt.Errorf( - "unable to marshal __createArtifactInput.ArtifactData: %w", err) + "unable to marshal __createArtifactInput.ArtifactPayload: %w", err) } } return &retval, nil @@ -1895,8 +1863,9 @@ type getArtifactArtifact struct { Name string `json:"name"` Type string `json:"type"` // The bundle's artifact field (output field) that produced this artifact. - Field string `json:"field"` - Specs map[string]any `json:"-"` + Field string `json:"field"` + // Complete artifact payload containing all artifact data. Fields marked with $md.sensitive in the artifact definition will be masked as [SENSITIVE]. Use downloadArtifact to retrieve unmasked values. See https://docs.massdriver.cloud/json-schema-cheat-sheet/massdriver-annotations for more details. + Payload map[string]any `json:"-"` // Download formats supported for this artifact Formats []string `json:"formats"` CreatedAt time.Time `json:"createdAt"` @@ -1921,8 +1890,8 @@ func (v *getArtifactArtifact) GetType() string { return v.Type } // GetField returns getArtifactArtifact.Field, and is useful for accessing the field via an interface. func (v *getArtifactArtifact) GetField() string { return v.Field } -// GetSpecs returns getArtifactArtifact.Specs, and is useful for accessing the field via an interface. -func (v *getArtifactArtifact) GetSpecs() map[string]any { return v.Specs } +// GetPayload returns getArtifactArtifact.Payload, and is useful for accessing the field via an interface. +func (v *getArtifactArtifact) GetPayload() map[string]any { return v.Payload } // GetFormats returns getArtifactArtifact.Formats, and is useful for accessing the field via an interface. func (v *getArtifactArtifact) GetFormats() []string { return v.Formats } @@ -1952,7 +1921,7 @@ func (v *getArtifactArtifact) UnmarshalJSON(b []byte) error { var firstPass struct { *getArtifactArtifact - Specs json.RawMessage `json:"specs"` + Payload json.RawMessage `json:"payload"` graphql.NoUnmarshalJSON } firstPass.getArtifactArtifact = v @@ -1963,14 +1932,14 @@ func (v *getArtifactArtifact) UnmarshalJSON(b []byte) error { } { - dst := &v.Specs - src := firstPass.Specs + dst := &v.Payload + src := firstPass.Payload if len(src) != 0 && string(src) != "null" { err = scalars.UnmarshalJSON( src, dst) if err != nil { return fmt.Errorf( - "unable to unmarshal getArtifactArtifact.Specs: %w", err) + "unable to unmarshal getArtifactArtifact.Payload: %w", err) } } } @@ -1986,7 +1955,7 @@ type __premarshalgetArtifactArtifact struct { Field string `json:"field"` - Specs json.RawMessage `json:"specs"` + Payload json.RawMessage `json:"payload"` Formats []string `json:"formats"` @@ -2018,14 +1987,14 @@ func (v *getArtifactArtifact) __premarshalJSON() (*__premarshalgetArtifactArtifa retval.Field = v.Field { - dst := &retval.Specs - src := v.Specs + dst := &retval.Payload + src := v.Payload var err error *dst, err = scalars.MarshalJSON( &src) if err != nil { return nil, fmt.Errorf( - "unable to marshal getArtifactArtifact.Specs: %w", err) + "unable to marshal getArtifactArtifact.Payload: %w", err) } } retval.Formats = v.Formats @@ -4876,8 +4845,8 @@ func containerRepository( // The query or mutation executed by createArtifact. const createArtifact_Operation = ` -mutation createArtifact ($organizationId: ID!, $artifactName: String!, $artifactSpecs: JSON!, $artifactType: String!, $artifactData: JSON!) { - createArtifact(organizationId: $organizationId, name: $artifactName, specs: $artifactSpecs, type: $artifactType, data: $artifactData) { +mutation createArtifact ($organizationId: ID!, $artifactName: String!, $artifactType: String!, $artifactPayload: JSON!) { + createArtifact(organizationId: $organizationId, name: $artifactName, type: $artifactType, payload: $artifactPayload) { result { name id @@ -4895,19 +4864,17 @@ func createArtifact( client graphql.Client, organizationId string, artifactName string, - artifactSpecs map[string]any, artifactType string, - artifactData map[string]any, + artifactPayload map[string]any, ) (*createArtifactResponse, error) { req := &graphql.Request{ OpName: "createArtifact", Query: createArtifact_Operation, Variables: &__createArtifactInput{ - OrganizationId: organizationId, - ArtifactName: artifactName, - ArtifactSpecs: artifactSpecs, - ArtifactType: artifactType, - ArtifactData: artifactData, + OrganizationId: organizationId, + ArtifactName: artifactName, + ArtifactType: artifactType, + ArtifactPayload: artifactPayload, }, } var err error @@ -5504,7 +5471,7 @@ query getArtifact ($organizationId: ID!, $id: ID!) { name type field - specs + payload formats createdAt updatedAt diff --git a/pkg/artifact/types.go b/pkg/artifact/types.go index 85118b14..72cbb4d9 100644 --- a/pkg/artifact/types.go +++ b/pkg/artifact/types.go @@ -1,6 +1,3 @@ package artifact -type Artifact struct { - Data map[string]any `json:"data"` - Specs map[string]any `json:"specs"` -} +type Artifact map[string]any diff --git a/pkg/commands/artifact/import.go b/pkg/commands/artifact/import.go index cbfff1f8..c29de100 100644 --- a/pkg/commands/artifact/import.go +++ b/pkg/commands/artifact/import.go @@ -31,7 +31,7 @@ func RunImport(ctx context.Context, mdClient *client.Client, artifactName string } fmt.Printf("Creating artifact %s of type %s...\n", artifactName, artifactType) - resp, createErr := api.CreateArtifact(ctx, mdClient, artifactName, artifactType, artifact.Data, artifact.Specs) + resp, createErr := api.CreateArtifact(ctx, mdClient, artifactName, artifactType, artifact) if createErr != nil { return "", createErr } From 4ecf6b642ba0aa354d292dd075802fda215c3349 Mon Sep 17 00:00:00 2001 From: chrisghill Date: Mon, 12 Jan 2026 13:52:58 -0700 Subject: [PATCH 2/2] PR suggestions --- pkg/api/genqlient.graphql | 2 +- pkg/api/schema.graphql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/api/genqlient.graphql b/pkg/api/genqlient.graphql index d5d91674..6f03b3de 100644 --- a/pkg/api/genqlient.graphql +++ b/pkg/api/genqlient.graphql @@ -1,6 +1,6 @@ # ARTIFACTS -mutation createArtifact($organizationId: ID!, $artifactName: String!, $artifactType: String! $artifactPayload: JSON!) { +mutation createArtifact($organizationId: ID!, $artifactName: String!, $artifactType: String!, $artifactPayload: JSON!) { createArtifact( organizationId: $organizationId, name: $artifactName, diff --git a/pkg/api/schema.graphql b/pkg/api/schema.graphql index 5f8c9f3d..fd9c2646 100644 --- a/pkg/api/schema.graphql +++ b/pkg/api/schema.graphql @@ -493,7 +493,7 @@ type RootMutationType { enableIntegration(organizationId: ID!, integrationTypeId: String!, config: JSON!, auth: JSON!): IntegrationPayload "Disable an integration for an organization" - disableIntegration(organizationId: ID!, integrationConfigId: ID!): IntegrationConfig + disableIntegration(organizationId: ID!, integrationConfigId: ID!): IntegrationPayload "Create an environment" createEnvironment(organizationId: ID!, projectId: ID!, name: String!, slug: String!, description: String): EnvironmentPayload