From 2e29513c12a41714ab076f3128004634936739e1 Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Fri, 8 Nov 2024 14:10:27 +0530 Subject: [PATCH 01/19] feat: add support for include_tags for contracts --- go.mod | 2 +- go.sum | 4 +- internal/api/contract.go | 6 +- internal/service/contract/errors.go | 4 + .../contract/resource_cosmo_contract.go | 100 ++++++++++++++---- 5 files changed, 93 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index a6d8d9d..5272a94 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/hashicorp/terraform-plugin-go v0.23.0 github.com/hashicorp/terraform-plugin-log v0.9.0 github.com/hashicorp/terraform-plugin-testing v1.10.0 - github.com/wundergraph/cosmo/connect-go v0.0.0-20240916094337-a4c4cae55557 + github.com/wundergraph/cosmo/connect-go v0.0.0-20241104193239-b78c5917d64b ) require ( diff --git a/go.sum b/go.sum index 37819ab..8ce691b 100644 --- a/go.sum +++ b/go.sum @@ -196,8 +196,8 @@ github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IU github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/wundergraph/cosmo/connect-go v0.0.0-20240916094337-a4c4cae55557 h1:hzZKQsFVJZ6JqOlTWT73P7GNY2vkDV3J+3oYX0SN/iY= -github.com/wundergraph/cosmo/connect-go v0.0.0-20240916094337-a4c4cae55557/go.mod h1:RLepGeaXdENMlePq4geGzaDV895QuJZ+mUFLzG5ra9E= +github.com/wundergraph/cosmo/connect-go v0.0.0-20241104193239-b78c5917d64b h1:N6CQBlWN7B8cOIVPNxZxkmgOUrSeaZebdhmdGxmg3/8= +github.com/wundergraph/cosmo/connect-go v0.0.0-20241104193239-b78c5917d64b/go.mod h1:RLepGeaXdENMlePq4geGzaDV895QuJZ+mUFLzG5ra9E= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= diff --git a/internal/api/contract.go b/internal/api/contract.go index 75c172a..758947f 100644 --- a/internal/api/contract.go +++ b/internal/api/contract.go @@ -8,7 +8,7 @@ import ( platformv1 "github.com/wundergraph/cosmo/connect-go/gen/proto/wg/cosmo/platform/v1" ) -func (p *PlatformClient) CreateContract(ctx context.Context, name, namespace, sourceGraphName, routingUrl, admissionWebhookUrl, admissionWebhookSecret string, excludeTags []string, readme string) (*platformv1.CreateContractResponse, *ApiError) { +func (p *PlatformClient) CreateContract(ctx context.Context, name, namespace, sourceGraphName, routingUrl, admissionWebhookUrl, admissionWebhookSecret string, excludeTags []string, includeTags []string, readme string) (*platformv1.CreateContractResponse, *ApiError) { request := connect.NewRequest(&platformv1.CreateContractRequest{ Name: name, Namespace: namespace, @@ -18,6 +18,7 @@ func (p *PlatformClient) CreateContract(ctx context.Context, name, namespace, so ExcludeTags: excludeTags, Readme: &readme, AdmissionWebhookSecret: &admissionWebhookSecret, + IncludeTags: includeTags, }) response, err := p.Client.CreateContract(ctx, request) @@ -37,11 +38,12 @@ func (p *PlatformClient) CreateContract(ctx context.Context, name, namespace, so return response.Msg, nil } -func (p *PlatformClient) UpdateContract(ctx context.Context, name, namespace string, excludeTags []string) (*platformv1.UpdateContractResponse, *ApiError) { +func (p *PlatformClient) UpdateContract(ctx context.Context, name, namespace string, excludeTags []string, includeTags []string) (*platformv1.UpdateContractResponse, *ApiError) { request := connect.NewRequest(&platformv1.UpdateContractRequest{ Name: name, Namespace: namespace, ExcludeTags: excludeTags, + IncludeTags: includeTags, }) response, err := p.Client.UpdateContract(ctx, request) diff --git a/internal/service/contract/errors.go b/internal/service/contract/errors.go index d668338..8c54162 100644 --- a/internal/service/contract/errors.go +++ b/internal/service/contract/errors.go @@ -12,3 +12,7 @@ const ( ErrUnexpectedDataSourceType = "Unexpected Data Source Configure Type" ErrUnexpectedResourceType = "Unexpected Resource Configure Type" ) + +const ( + DebugCreate = "create-contract" +) diff --git a/internal/service/contract/resource_cosmo_contract.go b/internal/service/contract/resource_cosmo_contract.go index d55d1ad..8d7f341 100644 --- a/internal/service/contract/resource_cosmo_contract.go +++ b/internal/service/contract/resource_cosmo_contract.go @@ -3,6 +3,9 @@ package contract import ( "context" "fmt" + "github.com/wundergraph/cosmo/connect-go/gen/proto/wg/cosmo/common" + platformv1 "github.com/wundergraph/cosmo/connect-go/gen/proto/wg/cosmo/platform/v1" + "strings" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -28,6 +31,7 @@ type contractResourceModel struct { SourceGraphName types.String `tfsdk:"source"` Namespace types.String `tfsdk:"namespace"` ExcludeTags types.List `tfsdk:"exclude_tags"` + IncludeTags types.List `tfsdk:"include_tags"` Readme types.String `tfsdk:"readme"` AdmissionWebhookUrl types.String `tfsdk:"admission_webhook_url"` AdmissionWebhookSecret types.String `tfsdk:"admission_webhook_secret"` @@ -68,6 +72,10 @@ For more information, refer to the Cosmo Documentation at https://cosmo-docs.wun Optional: true, ElementType: types.StringType, }, + "include_tags": schema.ListAttribute{ + Optional: true, + ElementType: types.StringType, + }, "readme": schema.StringAttribute{ Optional: true, }, @@ -109,31 +117,24 @@ func (r *contractResource) Create(ctx context.Context, req resource.CreateReques return } - excludeTags, err := utils.ConvertLabelMatchers(data.ExcludeTags) - if err != nil { - utils.AddDiagnosticError(resp, - ErrCreatingContract, - "Could not create contract: "+err.Error(), - ) - return - } - _, apiError := r.client.CreateContract(ctx, data.Name.ValueString(), data.Namespace.ValueString(), data.SourceGraphName.ValueString(), data.RoutingURL.ValueString(), data.AdmissionWebhookUrl.ValueString(), data.AdmissionWebhookSecret.ValueString(), excludeTags, data.Readme.ValueString()) + response, apiError := r.createAndFetchContract(ctx, data, resp) if apiError != nil { - if api.IsContractCompositionFailedError(apiError) || api.IsSubgraphCompositionFailedError(apiError) { - utils.AddDiagnosticWarning(resp, - ErrCreatingContract, - "Contract composition failed: "+apiError.Error(), - ) - } else { + if !api.IsSubgraphCompositionFailedError(apiError) { utils.AddDiagnosticError(resp, ErrCreatingContract, - "Could not create contract: "+apiError.Error(), + apiError.Error(), ) return } } - data.Id = data.Name + graph := response.Graph + data.Id = types.StringValue(graph.GetId()) + data.Name = types.StringValue(graph.GetName()) + data.Namespace = types.StringValue(graph.GetNamespace()) + data.RoutingURL = types.StringValue(graph.GetRoutingURL()) + + utils.LogAction(ctx, DebugCreate, data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -192,7 +193,16 @@ func (r *contractResource) Update(ctx context.Context, req resource.UpdateReques return } - _, apiError := r.client.UpdateContract(ctx, data.Name.ValueString(), data.Namespace.ValueString(), excludeTags) + includeTags, err := utils.ConvertLabelMatchers(data.IncludeTags) + if err != nil { + utils.AddDiagnosticError(resp, + ErrCreatingContract, + "Could not create contract: "+err.Error(), + ) + return + } + + _, apiError := r.client.UpdateContract(ctx, data.Name.ValueString(), data.Namespace.ValueString(), excludeTags, includeTags) if apiError != nil { if api.IsContractCompositionFailedError(apiError) || api.IsSubgraphCompositionFailedError(apiError) { utils.AddDiagnosticWarning(resp, @@ -245,3 +255,57 @@ func (r *contractResource) Delete(ctx context.Context, req resource.DeleteReques func (r *contractResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } + +func (r *contractResource) createAndFetchContract(ctx context.Context, data contractResourceModel, resp *resource.CreateResponse) (*platformv1.GetFederatedGraphByNameResponse, *api.ApiError) { + excludeTags, err := utils.ConvertLabelMatchers(data.ExcludeTags) + if err != nil { + utils.AddDiagnosticError(resp, + ErrCreatingContract, + "Could not create contract: "+err.Error(), + ) + return nil, &api.ApiError{Err: err, Reason: "CreateContract", Status: common.EnumStatusCode_ERR} + } + + includeTags, err := utils.ConvertLabelMatchers(data.IncludeTags) + if err != nil { + utils.AddDiagnosticError(resp, + ErrCreatingContract, + "Could not create contract: "+err.Error(), + ) + return nil, &api.ApiError{Err: err, Reason: "CreateContract", Status: common.EnumStatusCode_ERR} + } + + utils.DebugAction(ctx, DebugCreate, data.Name.ValueString(), data.Namespace.ValueString(), map[string]interface{}{ + "routing_url": data.RoutingURL.ValueString(), + "excludeTags": strings.Join(excludeTags, ","), + "includeTags": strings.Join(includeTags, ","), + }) + + _, apiError := r.client.CreateContract(ctx, data.Name.ValueString(), data.Namespace.ValueString(), data.SourceGraphName.ValueString(), data.RoutingURL.ValueString(), data.AdmissionWebhookUrl.ValueString(), data.AdmissionWebhookSecret.ValueString(), excludeTags, includeTags, data.Readme.ValueString()) + if apiError != nil { + if api.IsContractCompositionFailedError(apiError) || api.IsSubgraphCompositionFailedError(apiError) { + utils.AddDiagnosticWarning(resp, + ErrCreatingContract, + "Contract composition failed: "+apiError.Error(), + ) + } else { + utils.AddDiagnosticError(resp, + ErrCreatingContract, + "Could not create contract: "+apiError.Error(), + ) + return nil, apiError + } + } + + response, apiError := r.client.GetFederatedGraph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) + if apiError != nil { + return nil, apiError + } + + utils.DebugAction(ctx, DebugCreate, data.Name.ValueString(), data.Namespace.ValueString(), map[string]interface{}{ + "id": response.Graph.GetId(), + "graph": response.Graph, + }) + + return response, nil +} From 3b0b8b60f38f9c792508dd21266e76d7c5b2e1da Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Fri, 8 Nov 2024 14:13:28 +0530 Subject: [PATCH 02/19] fix: ci --- docs/resources/contract.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/resources/contract.md b/docs/resources/contract.md index 47e1e39..22e1477 100644 --- a/docs/resources/contract.md +++ b/docs/resources/contract.md @@ -40,6 +40,7 @@ resource "cosmo_contract" "test" { - `admission_webhook_secret` (String) - `admission_webhook_url` (String) - `exclude_tags` (List of String) +- `include_tags` (List of String) - `readme` (String) ### Read-Only From 399e3ee7778601ca56306a7335c1a4d548cb1af4 Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Wed, 13 Nov 2024 14:22:26 +0530 Subject: [PATCH 03/19] fix: handle errors in the provider --- .../contract/resource_cosmo_contract.go | 130 +++++++++++--- .../resource_cosmo_federated_graph.go | 114 +++++++++---- .../monograph/resource_cosmo_monograph.go | 31 ++-- .../subgraph/resource_cosmo_subgraph.go | 160 +++++++++++++----- 4 files changed, 323 insertions(+), 112 deletions(-) diff --git a/internal/service/contract/resource_cosmo_contract.go b/internal/service/contract/resource_cosmo_contract.go index 8d7f341..cab0707 100644 --- a/internal/service/contract/resource_cosmo_contract.go +++ b/internal/service/contract/resource_cosmo_contract.go @@ -3,6 +3,7 @@ package contract import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/wundergraph/cosmo/connect-go/gen/proto/wg/cosmo/common" platformv1 "github.com/wundergraph/cosmo/connect-go/gen/proto/wg/cosmo/platform/v1" "strings" @@ -30,12 +31,12 @@ type contractResourceModel struct { Name types.String `tfsdk:"name"` SourceGraphName types.String `tfsdk:"source"` Namespace types.String `tfsdk:"namespace"` + RoutingURL types.String `tfsdk:"routing_url"` ExcludeTags types.List `tfsdk:"exclude_tags"` IncludeTags types.List `tfsdk:"include_tags"` Readme types.String `tfsdk:"readme"` AdmissionWebhookUrl types.String `tfsdk:"admission_webhook_url"` AdmissionWebhookSecret types.String `tfsdk:"admission_webhook_secret"` - RoutingURL types.String `tfsdk:"routing_url"` } func (r *contractResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -52,6 +53,9 @@ For more information, refer to the Cosmo Documentation at https://cosmo-docs.wun Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "name": schema.StringAttribute{ Required: true, @@ -120,10 +124,7 @@ func (r *contractResource) Create(ctx context.Context, req resource.CreateReques response, apiError := r.createAndFetchContract(ctx, data, resp) if apiError != nil { if !api.IsSubgraphCompositionFailedError(apiError) { - utils.AddDiagnosticError(resp, - ErrCreatingContract, - apiError.Error(), - ) + // returning only for a non composition error, as the resource exists otherwise return } } @@ -134,6 +135,26 @@ func (r *contractResource) Create(ctx context.Context, req resource.CreateReques data.Namespace = types.StringValue(graph.GetNamespace()) data.RoutingURL = types.StringValue(graph.GetRoutingURL()) + var responseExcludeTags []attr.Value + for _, tag := range graph.Contract.GetExcludeTags() { + responseExcludeTags = append(responseExcludeTags, types.StringValue(tag)) + } + data.ExcludeTags = types.ListValueMust(types.StringType, responseExcludeTags) + + var responseIncludeTags []attr.Value + for _, tag := range graph.Contract.IncludeTags { + responseIncludeTags = append(responseIncludeTags, types.StringValue(tag)) + } + data.IncludeTags = types.ListValueMust(types.StringType, responseIncludeTags) + + if graph.Readme != nil { + data.Readme = types.StringValue(*graph.Readme) + } + + if graph.AdmissionWebhookUrl != nil { + data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) + } + utils.LogAction(ctx, DebugCreate, data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) @@ -148,7 +169,7 @@ func (r *contractResource) Read(ctx context.Context, req resource.ReadRequest, r return } - apiResponse, apiError := r.client.GetFederatedGraph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) + response, apiError := r.client.GetFederatedGraph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) if apiError != nil { if api.IsNotFoundError(apiError) { utils.AddDiagnosticWarning(resp, @@ -165,12 +186,32 @@ func (r *contractResource) Read(ctx context.Context, req resource.ReadRequest, r return } - graph := apiResponse.Graph + graph := response.Graph data.Id = types.StringValue(graph.GetId()) data.Name = types.StringValue(graph.GetName()) data.Namespace = types.StringValue(graph.GetNamespace()) data.RoutingURL = types.StringValue(graph.GetRoutingURL()) + var responseExcludeTags []attr.Value + for _, tag := range graph.Contract.GetExcludeTags() { + responseExcludeTags = append(responseExcludeTags, types.StringValue(tag)) + } + data.ExcludeTags = types.ListValueMust(types.StringType, responseExcludeTags) + + var responseIncludeTags []attr.Value + for _, tag := range graph.Contract.IncludeTags { + responseIncludeTags = append(responseIncludeTags, types.StringValue(tag)) + } + data.IncludeTags = types.ListValueMust(types.StringType, responseIncludeTags) + + if graph.Readme != nil { + data.Readme = types.StringValue(*graph.Readme) + } + + if graph.AdmissionWebhookUrl != nil { + data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) + } + utils.LogAction(ctx, "read", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) @@ -202,20 +243,53 @@ func (r *contractResource) Update(ctx context.Context, req resource.UpdateReques return } + if len(includeTags) > 0 && len(excludeTags) > 0 { + utils.AddDiagnosticError(resp, ErrUpdatingContract, "a contract cannot have both the include and exclude tags") + return + } + _, apiError := r.client.UpdateContract(ctx, data.Name.ValueString(), data.Namespace.ValueString(), excludeTags, includeTags) if apiError != nil { - if api.IsContractCompositionFailedError(apiError) || api.IsSubgraphCompositionFailedError(apiError) { - utils.AddDiagnosticWarning(resp, - ErrUpdatingContract, - apiError.Error(), - ) - } else { - utils.AddDiagnosticError(resp, - ErrUpdatingContract, - apiError.Error(), - ) - return - } + utils.AddDiagnosticError(resp, + ErrUpdatingContract, + apiError.Error(), + ) + return + } + + response, apiError := r.client.GetFederatedGraph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) + if apiError != nil { + utils.AddDiagnosticError(resp, + ErrRetrievingContract, + apiError.Error(), + ) + return + } + + graph := response.Graph + data.Id = types.StringValue(graph.GetId()) + data.Name = types.StringValue(graph.GetName()) + data.Namespace = types.StringValue(graph.GetNamespace()) + data.RoutingURL = types.StringValue(graph.GetRoutingURL()) + + var responseExcludeTags []attr.Value + for _, tag := range graph.Contract.GetExcludeTags() { + responseExcludeTags = append(responseExcludeTags, types.StringValue(tag)) + } + data.ExcludeTags = types.ListValueMust(types.StringType, responseExcludeTags) + + var responseIncludeTags []attr.Value + for _, tag := range graph.Contract.IncludeTags { + responseIncludeTags = append(responseIncludeTags, types.StringValue(tag)) + } + data.IncludeTags = types.ListValueMust(types.StringType, responseIncludeTags) + + if graph.Readme != nil { + data.Readme = types.StringValue(*graph.Readme) + } + + if graph.AdmissionWebhookUrl != nil { + data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) } resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) @@ -231,13 +305,8 @@ func (r *contractResource) Delete(ctx context.Context, req resource.DeleteReques apiError := r.client.DeleteContract(ctx, data.Name.ValueString(), data.Namespace.ValueString()) if apiError != nil { - if api.IsContractCompositionFailedError(apiError) || api.IsSubgraphCompositionFailedError(apiError) { - utils.AddDiagnosticWarning(resp, - ErrDeletingContract, - apiError.Error(), - ) - } else if api.IsNotFoundError(apiError) { - utils.AddDiagnosticWarning(resp, + if api.IsNotFoundError(apiError) { + utils.AddDiagnosticError(resp, ErrDeletingContract, apiError.Error(), ) @@ -250,6 +319,8 @@ func (r *contractResource) Delete(ctx context.Context, req resource.DeleteReques return } } + + utils.LogAction(ctx, "deleted contract", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) } func (r *contractResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { @@ -275,6 +346,11 @@ func (r *contractResource) createAndFetchContract(ctx context.Context, data cont return nil, &api.ApiError{Err: err, Reason: "CreateContract", Status: common.EnumStatusCode_ERR} } + if len(includeTags) > 0 && len(excludeTags) > 0 { + utils.AddDiagnosticError(resp, ErrCreatingContract, "a contract cannot have both the include and exclude tags") + return nil, &api.ApiError{Err: err, Reason: "CreateContract", Status: common.EnumStatusCode_ERR} + } + utils.DebugAction(ctx, DebugCreate, data.Name.ValueString(), data.Namespace.ValueString(), map[string]interface{}{ "routing_url": data.RoutingURL.ValueString(), "excludeTags": strings.Join(excludeTags, ","), @@ -284,7 +360,7 @@ func (r *contractResource) createAndFetchContract(ctx context.Context, data cont _, apiError := r.client.CreateContract(ctx, data.Name.ValueString(), data.Namespace.ValueString(), data.SourceGraphName.ValueString(), data.RoutingURL.ValueString(), data.AdmissionWebhookUrl.ValueString(), data.AdmissionWebhookSecret.ValueString(), excludeTags, includeTags, data.Readme.ValueString()) if apiError != nil { if api.IsContractCompositionFailedError(apiError) || api.IsSubgraphCompositionFailedError(apiError) { - utils.AddDiagnosticWarning(resp, + utils.AddDiagnosticError(resp, ErrCreatingContract, "Contract composition failed: "+apiError.Error(), ) diff --git a/internal/service/federated-graph/resource_cosmo_federated_graph.go b/internal/service/federated-graph/resource_cosmo_federated_graph.go index 1edec55..e3d6771 100644 --- a/internal/service/federated-graph/resource_cosmo_federated_graph.go +++ b/internal/service/federated-graph/resource_cosmo_federated_graph.go @@ -39,11 +39,11 @@ type FederatedGraphResourceModel struct { Id types.String `tfsdk:"id"` Name types.String `tfsdk:"name"` Namespace types.String `tfsdk:"namespace"` - Readme types.String `tfsdk:"readme"` RoutingURL types.String `tfsdk:"routing_url"` + LabelMatchers types.List `tfsdk:"label_matchers"` AdmissionWebhookUrl types.String `tfsdk:"admission_webhook_url"` AdmissionWebhookSecret types.String `tfsdk:"admission_webhook_secret"` - LabelMatchers types.List `tfsdk:"label_matchers"` + Readme types.String `tfsdk:"readme"` } func (r *FederatedGraphResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -138,10 +138,6 @@ func (r *FederatedGraphResource) Create(ctx context.Context, req resource.Create response, apiError := r.createFederatedGraph(ctx, data, resp) if apiError != nil { if !api.IsSubgraphCompositionFailedError(apiError) { - utils.AddDiagnosticError(resp, - ErrCreatingGraph, - apiError.Error(), - ) return } } @@ -152,6 +148,20 @@ func (r *FederatedGraphResource) Create(ctx context.Context, req resource.Create data.Namespace = types.StringValue(graph.GetNamespace()) data.RoutingURL = types.StringValue(graph.GetRoutingURL()) + var responseLabelMatchers []attr.Value + for _, matcher := range graph.LabelMatchers { + responseLabelMatchers = append(responseLabelMatchers, types.StringValue(matcher)) + } + data.LabelMatchers = types.ListValueMust(types.StringType, responseLabelMatchers) + + if graph.Readme != nil { + data.Readme = types.StringValue(*graph.Readme) + } + + if graph.AdmissionWebhookUrl != nil { + data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) + } + utils.LogAction(ctx, DebugCreate, data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) @@ -190,11 +200,19 @@ func (r *FederatedGraphResource) Read(ctx context.Context, req resource.ReadRequ data.Namespace = types.StringValue(graph.GetNamespace()) data.RoutingURL = types.StringValue(graph.GetRoutingURL()) - var labelMatchers []attr.Value + var responseLabelMatchers []attr.Value for _, matcher := range graph.LabelMatchers { - labelMatchers = append(labelMatchers, types.StringValue(matcher)) + responseLabelMatchers = append(responseLabelMatchers, types.StringValue(matcher)) + } + data.LabelMatchers = types.ListValueMust(types.StringType, responseLabelMatchers) + + if graph.Readme != nil { + data.Readme = types.StringValue(*graph.Readme) + } + + if graph.AdmissionWebhookUrl != nil { + data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) } - data.LabelMatchers = types.ListValueMust(types.StringType, labelMatchers) utils.LogAction(ctx, "read", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) @@ -219,7 +237,7 @@ func (r *FederatedGraphResource) Update(ctx context.Context, req resource.Update return } - graph := platformv1.FederatedGraph{ + updatedGraph := platformv1.FederatedGraph{ Name: data.Name.ValueString(), Namespace: data.Namespace.ValueString(), RoutingURL: data.RoutingURL.ValueString(), @@ -233,23 +251,45 @@ func (r *FederatedGraphResource) Update(ctx context.Context, req resource.Update admissionWebhookSecret = data.AdmissionWebhookSecret.ValueStringPointer() } - _, apiError := r.client.UpdateFederatedGraph(ctx, admissionWebhookSecret, &graph) + _, apiError := r.client.UpdateFederatedGraph(ctx, admissionWebhookSecret, &updatedGraph) if apiError != nil { - if api.IsSubgraphCompositionFailedError(apiError) { - utils.AddDiagnosticWarning(resp, - ErrCompositionError, - apiError.Error(), - ) - } else { - utils.AddDiagnosticError(resp, - ErrUpdatingGraph, - apiError.Error(), - ) - return - } + utils.AddDiagnosticError(resp, + ErrUpdatingGraph, + apiError.Error(), + ) + return } - utils.LogAction(ctx, "updated", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) + utils.LogAction(ctx, "updated federated graph", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) + + response, apiError := r.client.GetFederatedGraph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) + if apiError != nil { + utils.AddDiagnosticError(resp, + ErrRetrievingGraph, + apiError.Error(), + ) + return + } + + graph := response.Graph + data.Id = types.StringValue(graph.GetId()) + data.Name = types.StringValue(graph.GetName()) + data.Namespace = types.StringValue(graph.GetNamespace()) + data.RoutingURL = types.StringValue(graph.GetRoutingURL()) + + var responseLabelMatchers []attr.Value + for _, matcher := range graph.LabelMatchers { + responseLabelMatchers = append(responseLabelMatchers, types.StringValue(matcher)) + } + data.LabelMatchers = types.ListValueMust(types.StringType, responseLabelMatchers) + + if graph.Readme != nil { + data.Readme = types.StringValue(*graph.Readme) + } + + if graph.AdmissionWebhookUrl != nil { + data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) + } resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -270,14 +310,22 @@ func (r *FederatedGraphResource) Delete(ctx context.Context, req resource.Delete apiError := r.client.DeleteFederatedGraph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) if apiError != nil { - utils.AddDiagnosticError(resp, - ErrDeletingGraph, - apiError.Error(), - ) - return + if api.IsNotFoundError(apiError) { + utils.AddDiagnosticError(resp, + ErrDeletingGraph, + apiError.Error(), + ) + resp.State.RemoveResource(ctx) + } else { + utils.AddDiagnosticError(resp, + ErrDeletingGraph, + apiError.Error(), + ) + return + } } - utils.LogAction(ctx, "deleted", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) + utils.LogAction(ctx, "deleted federated graph", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) } func (r *FederatedGraphResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { @@ -313,8 +361,12 @@ func (r *FederatedGraphResource) createFederatedGraph(ctx context.Context, data _, apiError := r.client.CreateFederatedGraph(ctx, admissionWebhookSecret, &apiGraph) if apiError != nil { if api.IsSubgraphCompositionFailedError(apiError) { - utils.AddDiagnosticWarning(resp, ErrCompositionError, apiError.Error()) + utils.AddDiagnosticError(resp, ErrCreatingGraph, apiError.Error()) } else { + utils.AddDiagnosticError(resp, + ErrCreatingGraph, + "Could not create federated graph: "+apiError.Error(), + ) return nil, apiError } } diff --git a/internal/service/monograph/resource_cosmo_monograph.go b/internal/service/monograph/resource_cosmo_monograph.go index 2b79107..081adff 100644 --- a/internal/service/monograph/resource_cosmo_monograph.go +++ b/internal/service/monograph/resource_cosmo_monograph.go @@ -54,6 +54,9 @@ For more information on monographs, please refer to the [Cosmo Documentation](ht "id": schema.StringAttribute{ Computed: true, MarkdownDescription: "The unique identifier of the monograph resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "name": schema.StringAttribute{ Required: true, @@ -181,7 +184,7 @@ func (r *MonographResource) Create(ctx context.Context, req resource.CreateReque data.Readme = types.StringValue(*monograph.Readme) } - utils.LogAction(ctx, "created", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) + utils.LogAction(ctx, "created monograph", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -220,7 +223,7 @@ func (r *MonographResource) Read(ctx context.Context, req resource.ReadRequest, data.Readme = types.StringValue(*monograph.Readme) } - utils.LogAction(ctx, "read", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) + utils.LogAction(ctx, "read monograph", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -254,6 +257,8 @@ func (r *MonographResource) Update(ctx context.Context, req resource.UpdateReque return } + utils.LogAction(ctx, "updated monograph", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) + monograph, err := r.client.GetMonograph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) if err != nil { utils.AddDiagnosticError(resp, @@ -266,8 +271,6 @@ func (r *MonographResource) Update(ctx context.Context, req resource.UpdateReque data.Id = types.StringValue(monograph.GetId()) data.Name = types.StringValue(monograph.GetName()) - utils.LogAction(ctx, "updated", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -281,14 +284,22 @@ func (r *MonographResource) Delete(ctx context.Context, req resource.DeleteReque apiError := r.client.DeleteMonograph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) if apiError != nil { - utils.AddDiagnosticError(resp, - ErrDeletingMonograph, - apiError.Error(), - ) - return + if api.IsNotFoundError(apiError) { + utils.AddDiagnosticError(resp, + ErrDeletingMonograph, + apiError.Error(), + ) + resp.State.RemoveResource(ctx) + } else { + utils.AddDiagnosticError(resp, + ErrDeletingMonograph, + apiError.Error(), + ) + return + } } - utils.LogAction(ctx, "deleted", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) + utils.LogAction(ctx, "deleted monograph", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) } func (r *MonographResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { diff --git a/internal/service/subgraph/resource_cosmo_subgraph.go b/internal/service/subgraph/resource_cosmo_subgraph.go index 2a81815..ee1f7a6 100644 --- a/internal/service/subgraph/resource_cosmo_subgraph.go +++ b/internal/service/subgraph/resource_cosmo_subgraph.go @@ -79,6 +79,9 @@ For more information on subgraphs, please refer to the [Cosmo Documentation](htt "id": schema.StringAttribute{ Computed: true, MarkdownDescription: "The unique identifier of the subgraph resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "name": schema.StringAttribute{ Required: true, @@ -164,15 +167,22 @@ func (r *SubgraphResource) Create(ctx context.Context, req resource.CreateReques subgraph, apiError := r.createAndPublishSubgraph(ctx, data, resp) if apiError != nil { - if api.IsSubgraphCompositionFailedError(apiError) { - utils.AddDiagnosticWarning(resp, ErrSubgraphCompositionFailed, apiError.Error()) - } else if api.IsInvalidSubgraphSchemaError(apiError) { - utils.AddDiagnosticError(resp, ErrPublishingSubgraph, apiError.Error()) + if !api.IsSubgraphCompositionFailedError(apiError) { return - } else { - utils.AddDiagnosticError(resp, ErrPublishingSubgraph, apiError.Error()) + } + } + + subgraphSchema, apiError := r.client.GetSubgraphSchema(ctx, subgraph.Name, subgraph.Namespace) + if apiError != nil { + if api.IsNotFoundError(apiError) { + utils.AddDiagnosticWarning(resp, + ErrSubgraphNotFound, + fmt.Sprintf("Subgraph '%s' not found will be recreated %s", data.Name.ValueString(), apiError.Error()), + ) + resp.State.RemoveResource(ctx) return } + utils.AddDiagnosticError(resp, ErrRetrievingSubgraph, fmt.Sprintf("Could not fetch subgraph '%s': %s", data.Name.ValueString(), apiError.Error())) return } @@ -180,8 +190,27 @@ func (r *SubgraphResource) Create(ctx context.Context, req resource.CreateReques data.Name = types.StringValue(subgraph.GetName()) data.Namespace = types.StringValue(subgraph.GetNamespace()) data.RoutingURL = types.StringValue(subgraph.GetRoutingURL()) + data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) + data.SubscriptionProtocol = types.StringValue(subgraph.GetSubscriptionProtocol()) + data.WebsocketSubprotocol = types.StringValue(subgraph.GetWebsocketSubprotocol()) + data.IsEventDrivenGraph = types.BoolValue(subgraph.GetIsEventDrivenGraph()) + labels := map[string]attr.Value{} + for _, label := range subgraph.GetLabels() { + if label != nil { + labels[label.GetKey()] = types.StringValue(label.GetValue()) + } + } + mapValue, _ := types.MapValueFrom(ctx, types.StringType, labels) + data.Labels = mapValue + if subgraph.Readme != nil { + data.Readme = types.StringValue(subgraph.GetReadme()) + } + + if len(subgraphSchema) > 0 { + data.Schema = types.StringValue(subgraphSchema) + } - utils.LogAction(ctx, "created", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) + utils.LogAction(ctx, "created subgraph", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -232,7 +261,7 @@ func (r *SubgraphResource) Read(ctx context.Context, req resource.ReadRequest, r } } - schema, apiError := r.client.GetSubgraphSchema(ctx, subgraph.Name, subgraph.Namespace) + subgraphSchema, apiError := r.client.GetSubgraphSchema(ctx, subgraph.Name, subgraph.Namespace) if apiError != nil { if api.IsNotFoundError(apiError) { utils.AddDiagnosticWarning(resp, @@ -258,12 +287,21 @@ func (r *SubgraphResource) Read(ctx context.Context, req resource.ReadRequest, r data.Name = types.StringValue(subgraph.GetName()) data.Namespace = types.StringValue(subgraph.GetNamespace()) data.RoutingURL = types.StringValue(subgraph.GetRoutingURL()) - if len(schema) > 0 { - data.Schema = types.StringValue(schema) - } + data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) + data.SubscriptionProtocol = types.StringValue(subgraph.GetSubscriptionProtocol()) + data.WebsocketSubprotocol = types.StringValue(subgraph.GetWebsocketSubprotocol()) + data.IsEventDrivenGraph = types.BoolValue(subgraph.GetIsEventDrivenGraph()) data.Labels = mapValue - utils.LogAction(ctx, "read", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) + if subgraph.Readme != nil { + data.Readme = types.StringValue(subgraph.GetReadme()) + } + + if len(subgraphSchema) > 0 { + data.Schema = types.StringValue(subgraphSchema) + } + + utils.LogAction(ctx, "read subgraph", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -300,6 +338,13 @@ func (r *SubgraphResource) Update(ctx context.Context, req resource.UpdateReques ErrSubgraphCompositionFailed, apiErr.Error(), ) + } else if api.IsNotFoundError(apiErr) { + utils.AddDiagnosticError(resp, + ErrUpdatingSubgraph, + apiErr.Error(), + ) + resp.State.RemoveResource(ctx) + return } else { utils.AddDiagnosticError(resp, ErrUpdatingSubgraph, @@ -309,6 +354,22 @@ func (r *SubgraphResource) Update(ctx context.Context, req resource.UpdateReques } } + if data.Schema.ValueString() != "" { + _, apiError := r.publishSubgraphSchema(ctx, data) + if apiError != nil { + if api.IsNotFoundError(apiErr) { + utils.AddDiagnosticError(resp, + ErrUpdatingSubgraph, + apiErr.Error(), + ) + resp.State.RemoveResource(ctx) + return + } else if !api.IsSubgraphCompositionFailedError(apiError) { + return + } + } + } + subgraph, err := r.client.GetSubgraph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) if err != nil { utils.AddDiagnosticError(resp, @@ -318,32 +379,45 @@ func (r *SubgraphResource) Update(ctx context.Context, req resource.UpdateReques return } - if data.Schema.ValueString() != "" { - hasChanged, apiError := r.publishSubgraphSchema(ctx, data) - if apiError != nil { - if api.IsSubgraphCompositionFailedError(apiError) { - utils.AddDiagnosticWarning(resp, ErrPublishingSubgraph, apiError.Error()) - } else if api.IsInvalidSubgraphSchemaError(apiError) { - utils.AddDiagnosticError(resp, ErrPublishingSubgraph, apiError.Error()) - return - } else { - utils.AddDiagnosticError(resp, ErrPublishingSubgraph, apiError.Error()) - return - } - } - - if hasChanged { + subgraphSchema, apiError := r.client.GetSubgraphSchema(ctx, subgraph.Name, subgraph.Namespace) + if apiError != nil { + if api.IsNotFoundError(apiError) { utils.AddDiagnosticWarning(resp, - ErrSubgraphSchemaChanged, - "The schema has changed", + ErrSubgraphNotFound, + fmt.Sprintf("Subgraph '%s' not found will be recreated %s", data.Name.ValueString(), apiError.Error()), ) + resp.State.RemoveResource(ctx) + return } + utils.AddDiagnosticError(resp, ErrRetrievingSubgraph, fmt.Sprintf("Could not fetch subgraph '%s': %s", data.Name.ValueString(), apiError.Error())) + return } + responseLabels := map[string]attr.Value{} + for _, label := range subgraph.GetLabels() { + if label != nil { + responseLabels[label.GetKey()] = types.StringValue(label.GetValue()) + } + } + mapValue, diags := types.MapValueFrom(ctx, types.StringType, responseLabels) + resp.Diagnostics.Append(diags...) data.Id = types.StringValue(subgraph.GetId()) data.Name = types.StringValue(subgraph.GetName()) data.Namespace = types.StringValue(subgraph.GetNamespace()) data.RoutingURL = types.StringValue(subgraph.GetRoutingURL()) + data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) + data.SubscriptionProtocol = types.StringValue(subgraph.GetSubscriptionProtocol()) + data.WebsocketSubprotocol = types.StringValue(subgraph.GetWebsocketSubprotocol()) + data.IsEventDrivenGraph = types.BoolValue(subgraph.GetIsEventDrivenGraph()) + data.Labels = mapValue + + if subgraph.Readme != nil { + data.Readme = types.StringValue(subgraph.GetReadme()) + } + + if len(subgraphSchema) > 0 { + data.Schema = types.StringValue(subgraphSchema) + } utils.LogAction(ctx, "updated", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) @@ -365,7 +439,12 @@ func (r *SubgraphResource) Delete(ctx context.Context, req resource.DeleteReques ErrDeletingSubgraph, apiErr.Error(), ) - return + } else if api.IsNotFoundError(apiErr) { + utils.AddDiagnosticError(resp, + ErrDeletingSubgraph, + apiErr.Error(), + ) + resp.State.RemoveResource(ctx) } else { utils.AddDiagnosticError(resp, ErrDeletingSubgraph, @@ -375,7 +454,7 @@ func (r *SubgraphResource) Delete(ctx context.Context, req resource.DeleteReques } } - utils.LogAction(ctx, "deleted", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) + utils.LogAction(ctx, "deleted subgraph", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) } func (r *SubgraphResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { @@ -402,16 +481,11 @@ func (r *SubgraphResource) createAndPublishSubgraph(ctx context.Context, data Su return nil, apiErr } - subgraph, apiErr := r.client.GetSubgraph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) - if apiErr != nil { - return nil, apiErr - } - if data.Schema.ValueString() != "" { - hasChanged, apiError := r.publishSubgraphSchema(ctx, data) + _, apiError := r.publishSubgraphSchema(ctx, data) if apiError != nil { if api.IsSubgraphCompositionFailedError(apiError) { - utils.AddDiagnosticWarning(resp, ErrSubgraphCompositionFailed, apiError.Error()) + utils.AddDiagnosticError(resp, ErrSubgraphCompositionFailed, apiError.Error()) } else if api.IsInvalidSubgraphSchemaError(apiError) { utils.AddDiagnosticError(resp, ErrPublishingSubgraph, apiError.Error()) return nil, apiError @@ -420,13 +494,11 @@ func (r *SubgraphResource) createAndPublishSubgraph(ctx context.Context, data Su return nil, apiError } } + } - if hasChanged { - utils.AddDiagnosticWarning(resp, - ErrSubgraphSchemaChanged, - "The schema has changed", - ) - } + subgraph, apiErr := r.client.GetSubgraph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) + if apiErr != nil { + return nil, apiErr } return subgraph, nil From 9395d6f45f6329471d3a1a53239374cc6cd229bd Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Wed, 13 Nov 2024 14:44:01 +0530 Subject: [PATCH 04/19] fix: tests --- internal/service/subgraph/resource_cosmo_subgraph.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/service/subgraph/resource_cosmo_subgraph.go b/internal/service/subgraph/resource_cosmo_subgraph.go index ee1f7a6..ef1aca9 100644 --- a/internal/service/subgraph/resource_cosmo_subgraph.go +++ b/internal/service/subgraph/resource_cosmo_subgraph.go @@ -355,7 +355,7 @@ func (r *SubgraphResource) Update(ctx context.Context, req resource.UpdateReques } if data.Schema.ValueString() != "" { - _, apiError := r.publishSubgraphSchema(ctx, data) + apiError := r.publishSubgraphSchema(ctx, data) if apiError != nil { if api.IsNotFoundError(apiErr) { utils.AddDiagnosticError(resp, @@ -482,7 +482,7 @@ func (r *SubgraphResource) createAndPublishSubgraph(ctx context.Context, data Su } if data.Schema.ValueString() != "" { - _, apiError := r.publishSubgraphSchema(ctx, data) + apiError := r.publishSubgraphSchema(ctx, data) if apiError != nil { if api.IsSubgraphCompositionFailedError(apiError) { utils.AddDiagnosticError(resp, ErrSubgraphCompositionFailed, apiError.Error()) @@ -504,15 +504,15 @@ func (r *SubgraphResource) createAndPublishSubgraph(ctx context.Context, data Su return subgraph, nil } -func (r *SubgraphResource) publishSubgraphSchema(ctx context.Context, data SubgraphResourceModel) (bool, *api.ApiError) { +func (r *SubgraphResource) publishSubgraphSchema(ctx context.Context, data SubgraphResourceModel) *api.ApiError { apiResponse, apiError := r.client.PublishSubgraph(ctx, data.Name.ValueString(), data.Namespace.ValueString(), data.Schema.ValueString()) if apiError != nil { - return false, apiError + return apiError } if apiResponse != nil && apiResponse.HasChanged != nil && *apiResponse.HasChanged { - return true, nil + return nil } - return false, nil + return nil } From 7eb041ef6de5bc10a275ff3329233937044d0a20 Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Thu, 14 Nov 2024 17:35:23 +0530 Subject: [PATCH 05/19] fix: tests --- .../contract/data_source_cosmo_contract.go | 33 ++++++-- .../data_source_cosmo_contract_test.go | 30 +++++-- .../contract/resource_cosmo_contract.go | 83 ++++++++++++------- .../contract/resource_cosmo_contract_test.go | 36 ++++++-- .../data_source_cosmo_federated_graph.go | 4 + .../data_source_cosmo_federated_graph_test.go | 4 + .../resource_cosmo_federated_graph.go | 23 +++-- .../subgraph/data_source_cosmo_subgraph.go | 5 ++ .../subgraph/resource_cosmo_subgraph.go | 48 ++++++++--- .../subgraph/resource_cosmo_subgraph_test.go | 1 - 10 files changed, 195 insertions(+), 72 deletions(-) diff --git a/internal/service/contract/data_source_cosmo_contract.go b/internal/service/contract/data_source_cosmo_contract.go index 42ef513..f0e911a 100644 --- a/internal/service/contract/data_source_cosmo_contract.go +++ b/internal/service/contract/data_source_cosmo_contract.go @@ -29,6 +29,8 @@ type contractDataSourceModel struct { AdmissionWebhookUrl types.String `tfsdk:"admission_webhook_url"` AdmissionWebhookSecret types.String `tfsdk:"admission_webhook_secret"` LabelMatchers types.Map `tfsdk:"label_matchers"` + ExcludeTags types.List `tfsdk:"exclude_tags"` + IncludeTags types.List `tfsdk:"include_tags"` } func (d *contractDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { @@ -72,6 +74,14 @@ func (d *contractDataSource) Schema(ctx context.Context, req datasource.SchemaRe MarkdownDescription: "The URL for the federated graph.", Computed: true, }, + "exclude_tags": schema.ListAttribute{ + Computed: true, + ElementType: types.StringType, + }, + "include_tags": schema.ListAttribute{ + Computed: true, + ElementType: types.StringType, + }, }, } } @@ -124,22 +134,35 @@ func (d *contractDataSource) Read(ctx context.Context, req datasource.ReadReques } graph := apiResponse.Graph - data.Id = types.StringValue(graph.GetId()) data.Name = types.StringValue(graph.GetName()) data.Namespace = types.StringValue(graph.GetNamespace()) data.RoutingURL = types.StringValue(graph.GetRoutingURL()) - labelMatchers := make(map[string]attr.Value) - for _, labelMatcher := range graph.GetLabelMatchers() { - labelMatchers[labelMatcher] = types.StringValue(labelMatcher) + if graph.Contract != nil && len(graph.Contract.GetExcludeTags()) > 0 { + var responseExcludeTags []attr.Value + for _, tag := range graph.Contract.GetExcludeTags() { + responseExcludeTags = append(responseExcludeTags, types.StringValue(tag)) + } + data.ExcludeTags = types.ListValueMust(types.StringType, responseExcludeTags) + } + + if graph.Contract != nil && len(graph.Contract.GetIncludeTags()) > 0 { + var responseIncludeTags []attr.Value + for _, tag := range graph.Contract.IncludeTags { + responseIncludeTags = append(responseIncludeTags, types.StringValue(tag)) + } + data.IncludeTags = types.ListValueMust(types.StringType, responseIncludeTags) } - data.LabelMatchers = types.MapValueMust(types.StringType, labelMatchers) if graph.Readme != nil { data.Readme = types.StringValue(*graph.Readme) } + if graph.GetAdmissionWebhookUrl() != "" { + data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) + } + tflog.Trace(ctx, "Read contract data source", map[string]interface{}{ "id": data.Id.ValueString(), }) diff --git a/internal/service/contract/data_source_cosmo_contract_test.go b/internal/service/contract/data_source_cosmo_contract_test.go index e8dacb3..49ff792 100644 --- a/internal/service/contract/data_source_cosmo_contract_test.go +++ b/internal/service/contract/data_source_cosmo_contract_test.go @@ -13,12 +13,16 @@ func TestAccContractDataSource(t *testing.T) { name := acctest.RandomWithPrefix("test-contract") namespace := acctest.RandomWithPrefix("test-namespace") + subgraphName := acctest.RandomWithPrefix("test-subgraph") + subgraphRoutingURL := "https://subgraph-standalone-example.com" + subgraphSchema := acceptance.TestAccValidSubgraphSchema + resource.Test(t, resource.TestCase{ PreCheck: func() { acceptance.TestAccPreCheck(t) }, ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccContractDataSourceConfig(namespace, name), + Config: testAccContractDataSourceConfig(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("data.cosmo_contract.test", "namespace", namespace), @@ -28,27 +32,41 @@ func TestAccContractDataSource(t *testing.T) { ResourceName: "data.cosmo_contract.test", RefreshState: true, }, + { + Config: testAccContractDataSourceConfig(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, name), + Destroy: true, + }, }, }) } -func testAccContractDataSourceConfig(namespace, name string) string { +func testAccContractDataSourceConfig(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, name string) string { return fmt.Sprintf(` resource "cosmo_namespace" "test" { name = "%s" } -resource "cosmo_monograph" "source_graph" { +resource "cosmo_federated_graph" "source_graph" { name = "source-graph" namespace = cosmo_namespace.test.name routing_url = "https://example.com" - graph_url = "https://example.com" + depends_on = [cosmo_subgraph.test] +} + +resource "cosmo_subgraph" "test" { + name = "%s" + namespace = cosmo_namespace.test.name + routing_url = "%s" + schema = <<-EOT + %s + EOT + labels = {} } resource "cosmo_contract" "test" { name = "%s" namespace = cosmo_namespace.test.name - source = cosmo_monograph.source_graph.name + source = cosmo_federated_graph.source_graph.name routing_url = "https://example.com" readme = "Initial readme content" } @@ -57,5 +75,5 @@ data "cosmo_contract" "test" { name = cosmo_contract.test.name namespace = cosmo_contract.test.namespace } -`, namespace, name) +`, namespace, subgraphName, subgraphRoutingURL, subgraphSchema, name) } diff --git a/internal/service/contract/resource_cosmo_contract.go b/internal/service/contract/resource_cosmo_contract.go index cab0707..6f3aa27 100644 --- a/internal/service/contract/resource_cosmo_contract.go +++ b/internal/service/contract/resource_cosmo_contract.go @@ -135,23 +135,27 @@ func (r *contractResource) Create(ctx context.Context, req resource.CreateReques data.Namespace = types.StringValue(graph.GetNamespace()) data.RoutingURL = types.StringValue(graph.GetRoutingURL()) - var responseExcludeTags []attr.Value - for _, tag := range graph.Contract.GetExcludeTags() { - responseExcludeTags = append(responseExcludeTags, types.StringValue(tag)) + if graph.Contract != nil && len(graph.Contract.GetExcludeTags()) > 0 { + var responseExcludeTags []attr.Value + for _, tag := range graph.Contract.GetExcludeTags() { + responseExcludeTags = append(responseExcludeTags, types.StringValue(tag)) + } + data.ExcludeTags = types.ListValueMust(types.StringType, responseExcludeTags) } - data.ExcludeTags = types.ListValueMust(types.StringType, responseExcludeTags) - var responseIncludeTags []attr.Value - for _, tag := range graph.Contract.IncludeTags { - responseIncludeTags = append(responseIncludeTags, types.StringValue(tag)) + if graph.Contract != nil && len(graph.Contract.GetIncludeTags()) > 0 { + var responseIncludeTags []attr.Value + for _, tag := range graph.Contract.IncludeTags { + responseIncludeTags = append(responseIncludeTags, types.StringValue(tag)) + } + data.IncludeTags = types.ListValueMust(types.StringType, responseIncludeTags) } - data.IncludeTags = types.ListValueMust(types.StringType, responseIncludeTags) if graph.Readme != nil { data.Readme = types.StringValue(*graph.Readme) } - if graph.AdmissionWebhookUrl != nil { + if graph.GetAdmissionWebhookUrl() != "" { data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) } @@ -192,23 +196,27 @@ func (r *contractResource) Read(ctx context.Context, req resource.ReadRequest, r data.Namespace = types.StringValue(graph.GetNamespace()) data.RoutingURL = types.StringValue(graph.GetRoutingURL()) - var responseExcludeTags []attr.Value - for _, tag := range graph.Contract.GetExcludeTags() { - responseExcludeTags = append(responseExcludeTags, types.StringValue(tag)) + if graph.Contract != nil && len(graph.Contract.GetExcludeTags()) > 0 { + var responseExcludeTags []attr.Value + for _, tag := range graph.Contract.GetExcludeTags() { + responseExcludeTags = append(responseExcludeTags, types.StringValue(tag)) + } + data.ExcludeTags = types.ListValueMust(types.StringType, responseExcludeTags) } - data.ExcludeTags = types.ListValueMust(types.StringType, responseExcludeTags) - var responseIncludeTags []attr.Value - for _, tag := range graph.Contract.IncludeTags { - responseIncludeTags = append(responseIncludeTags, types.StringValue(tag)) + if graph.Contract != nil && len(graph.Contract.GetIncludeTags()) > 0 { + var responseIncludeTags []attr.Value + for _, tag := range graph.Contract.IncludeTags { + responseIncludeTags = append(responseIncludeTags, types.StringValue(tag)) + } + data.IncludeTags = types.ListValueMust(types.StringType, responseIncludeTags) } - data.IncludeTags = types.ListValueMust(types.StringType, responseIncludeTags) if graph.Readme != nil { data.Readme = types.StringValue(*graph.Readme) } - if graph.AdmissionWebhookUrl != nil { + if graph.GetAdmissionWebhookUrl() != "" { data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) } @@ -250,11 +258,18 @@ func (r *contractResource) Update(ctx context.Context, req resource.UpdateReques _, apiError := r.client.UpdateContract(ctx, data.Name.ValueString(), data.Namespace.ValueString(), excludeTags, includeTags) if apiError != nil { - utils.AddDiagnosticError(resp, - ErrUpdatingContract, - apiError.Error(), - ) - return + if api.IsContractCompositionFailedError(apiError) || api.IsSubgraphCompositionFailedError(apiError) { + utils.AddDiagnosticError(resp, + ErrUpdatingContract, + apiError.Error(), + ) + } else { + utils.AddDiagnosticError(resp, + ErrUpdatingContract, + apiError.Error(), + ) + return + } } response, apiError := r.client.GetFederatedGraph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) @@ -272,23 +287,27 @@ func (r *contractResource) Update(ctx context.Context, req resource.UpdateReques data.Namespace = types.StringValue(graph.GetNamespace()) data.RoutingURL = types.StringValue(graph.GetRoutingURL()) - var responseExcludeTags []attr.Value - for _, tag := range graph.Contract.GetExcludeTags() { - responseExcludeTags = append(responseExcludeTags, types.StringValue(tag)) + if graph.Contract != nil && len(graph.Contract.GetExcludeTags()) > 0 { + var responseExcludeTags []attr.Value + for _, tag := range graph.Contract.GetExcludeTags() { + responseExcludeTags = append(responseExcludeTags, types.StringValue(tag)) + } + data.ExcludeTags = types.ListValueMust(types.StringType, responseExcludeTags) } - data.ExcludeTags = types.ListValueMust(types.StringType, responseExcludeTags) - var responseIncludeTags []attr.Value - for _, tag := range graph.Contract.IncludeTags { - responseIncludeTags = append(responseIncludeTags, types.StringValue(tag)) + if graph.Contract != nil && len(graph.Contract.GetIncludeTags()) > 0 { + var responseIncludeTags []attr.Value + for _, tag := range graph.Contract.IncludeTags { + responseIncludeTags = append(responseIncludeTags, types.StringValue(tag)) + } + data.IncludeTags = types.ListValueMust(types.StringType, responseIncludeTags) } - data.IncludeTags = types.ListValueMust(types.StringType, responseIncludeTags) if graph.Readme != nil { data.Readme = types.StringValue(*graph.Readme) } - if graph.AdmissionWebhookUrl != nil { + if graph.GetAdmissionWebhookUrl() != "" { data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) } diff --git a/internal/service/contract/resource_cosmo_contract_test.go b/internal/service/contract/resource_cosmo_contract_test.go index 2e17db2..a8a7c44 100644 --- a/internal/service/contract/resource_cosmo_contract_test.go +++ b/internal/service/contract/resource_cosmo_contract_test.go @@ -16,45 +16,65 @@ func TestAccContractResource(t *testing.T) { readme := "Initial readme content" federatedGraphName := acctest.RandomWithPrefix("test-federated-graph") - federatedGraphroutingURL := "https://example.com:3000" + federatedGraphRoutingURL := "https://example.com:3000" - graphUrl := "http://example.com/graphql" + subgraphName := acctest.RandomWithPrefix("test-subgraph") + subgraphRoutingURL := "https://subgraph-standalone-example.com" + subgraphSchema := acceptance.TestAccValidSubgraphSchema resource.Test(t, resource.TestCase{ PreCheck: func() { acceptance.TestAccPreCheck(t) }, ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphroutingURL, graphUrl, name, readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), resource.TestCheckResourceAttr("cosmo_contract.test", "readme", readme), ), }, + { + ResourceName: "cosmo_contract.test", + RefreshState: true, + }, + { + Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, readme), + Destroy: true, + }, }, }) } -func testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphroutingURL, graphUrl, contractName, contractReadme string) string { +func testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractReadme string) string { return fmt.Sprintf(` resource "cosmo_namespace" "test" { name = "%s" } -resource "cosmo_monograph" "test" { +resource "cosmo_federated_graph" "test" { name = "%s" namespace = cosmo_namespace.test.name routing_url = "%s" - graph_url = "%s" + depends_on = [cosmo_subgraph.test] +} + +resource "cosmo_subgraph" "test" { + name = "%s" + namespace = cosmo_namespace.test.name + routing_url = "%s" + schema = <<-EOT + %s + EOT + labels = {} } resource "cosmo_contract" "test" { name = "%s" namespace = cosmo_namespace.test.name - source = cosmo_monograph.test.name + source = cosmo_federated_graph.test.name routing_url = "http://localhost:3003" readme = "%s" } -`, namespace, federatedGraphName, federatedGraphroutingURL, graphUrl, contractName, contractReadme) +`, namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractReadme) } diff --git a/internal/service/federated-graph/data_source_cosmo_federated_graph.go b/internal/service/federated-graph/data_source_cosmo_federated_graph.go index 82fbf8f..375d566 100644 --- a/internal/service/federated-graph/data_source_cosmo_federated_graph.go +++ b/internal/service/federated-graph/data_source_cosmo_federated_graph.go @@ -131,6 +131,10 @@ func (d *FederatedGraphDataSource) Read(ctx context.Context, req datasource.Read data.Readme = types.StringValue(*graph.Readme) } + if graph.GetAdmissionWebhookUrl() != "" { + data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) + } + tflog.Trace(ctx, "Read federated graph data source", map[string]interface{}{ "id": data.Id.ValueString(), }) diff --git a/internal/service/federated-graph/data_source_cosmo_federated_graph_test.go b/internal/service/federated-graph/data_source_cosmo_federated_graph_test.go index ceb1e89..2d5da9d 100644 --- a/internal/service/federated-graph/data_source_cosmo_federated_graph_test.go +++ b/internal/service/federated-graph/data_source_cosmo_federated_graph_test.go @@ -28,6 +28,10 @@ func TestAccFederatedGraphDataSource(t *testing.T) { ResourceName: "data.cosmo_federated_graph.test", RefreshState: true, }, + { + Config: testAccFederatedGraphDataSourceConfig(namespace, name), + Destroy: true, + }, }, }) } diff --git a/internal/service/federated-graph/resource_cosmo_federated_graph.go b/internal/service/federated-graph/resource_cosmo_federated_graph.go index e3d6771..e59e6c1 100644 --- a/internal/service/federated-graph/resource_cosmo_federated_graph.go +++ b/internal/service/federated-graph/resource_cosmo_federated_graph.go @@ -158,7 +158,7 @@ func (r *FederatedGraphResource) Create(ctx context.Context, req resource.Create data.Readme = types.StringValue(*graph.Readme) } - if graph.AdmissionWebhookUrl != nil { + if graph.GetAdmissionWebhookUrl() != "" { data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) } @@ -210,7 +210,7 @@ func (r *FederatedGraphResource) Read(ctx context.Context, req resource.ReadRequ data.Readme = types.StringValue(*graph.Readme) } - if graph.AdmissionWebhookUrl != nil { + if graph.GetAdmissionWebhookUrl() != "" { data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) } @@ -253,11 +253,18 @@ func (r *FederatedGraphResource) Update(ctx context.Context, req resource.Update _, apiError := r.client.UpdateFederatedGraph(ctx, admissionWebhookSecret, &updatedGraph) if apiError != nil { - utils.AddDiagnosticError(resp, - ErrUpdatingGraph, - apiError.Error(), - ) - return + if api.IsSubgraphCompositionFailedError(apiError) { + utils.AddDiagnosticError(resp, + ErrCompositionError, + apiError.Error(), + ) + } else { + utils.AddDiagnosticError(resp, + ErrUpdatingGraph, + apiError.Error(), + ) + return + } } utils.LogAction(ctx, "updated federated graph", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) @@ -287,7 +294,7 @@ func (r *FederatedGraphResource) Update(ctx context.Context, req resource.Update data.Readme = types.StringValue(*graph.Readme) } - if graph.AdmissionWebhookUrl != nil { + if graph.GetAdmissionWebhookUrl() != "" { data.AdmissionWebhookUrl = types.StringValue(*graph.AdmissionWebhookUrl) } diff --git a/internal/service/subgraph/data_source_cosmo_subgraph.go b/internal/service/subgraph/data_source_cosmo_subgraph.go index 4e95edb..7bc9228 100644 --- a/internal/service/subgraph/data_source_cosmo_subgraph.go +++ b/internal/service/subgraph/data_source_cosmo_subgraph.go @@ -179,6 +179,11 @@ func (d *SubgraphDataSource) Read(ctx context.Context, req datasource.ReadReques data.IsFeatureSubgraph = types.BoolValue(subgraph.GetIsFeatureSubgraph()) data.SubscriptionProtocol = types.StringValue(subgraph.GetSubscriptionProtocol()) data.WebsocketSubprotocol = types.StringValue(subgraph.GetWebsocketSubprotocol()) + data.IsEventDrivenGraph = types.BoolValue(subgraph.GetIsEventDrivenGraph()) + + if subgraph.GetSubscriptionUrl() != "" { + data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) + } tflog.Trace(ctx, "Read subgraph data source", map[string]interface{}{ "id": data.Id.ValueString(), diff --git a/internal/service/subgraph/resource_cosmo_subgraph.go b/internal/service/subgraph/resource_cosmo_subgraph.go index ef1aca9..a933360 100644 --- a/internal/service/subgraph/resource_cosmo_subgraph.go +++ b/internal/service/subgraph/resource_cosmo_subgraph.go @@ -3,6 +3,7 @@ package subgraph import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" @@ -110,6 +111,8 @@ For more information on subgraphs, please refer to the [Cosmo Documentation](htt Validators: []validator.String{ stringvalidator.OneOf(api.GraphQLSubscriptionProtocolWS, api.GraphQLSubscriptionProtocolSSE, api.GraphQLSubscriptionProtocolSSEPost), }, + Computed: true, + Default: stringdefault.StaticString(api.GraphQLSubscriptionProtocolWS), }, "readme": schema.StringAttribute{ Optional: true, @@ -121,10 +124,14 @@ For more information on subgraphs, please refer to the [Cosmo Documentation](htt Validators: []validator.String{ stringvalidator.OneOf(api.GraphQLWebsocketSubprotocolDefault, api.GraphQLWebsocketSubprotocolGraphQLWS, api.GraphQLWebsocketSubprotocolGraphQLTransportWS), }, + Computed: true, + Default: stringdefault.StaticString(api.GraphQLWebsocketSubprotocolDefault), }, "is_event_driven_graph": schema.BoolAttribute{ Optional: true, MarkdownDescription: "Indicates if the subgraph is event-driven.", + Computed: true, + Default: booldefault.StaticBool(false), }, "is_feature_subgraph": schema.BoolAttribute{ Optional: true, @@ -190,7 +197,6 @@ func (r *SubgraphResource) Create(ctx context.Context, req resource.CreateReques data.Name = types.StringValue(subgraph.GetName()) data.Namespace = types.StringValue(subgraph.GetNamespace()) data.RoutingURL = types.StringValue(subgraph.GetRoutingURL()) - data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) data.SubscriptionProtocol = types.StringValue(subgraph.GetSubscriptionProtocol()) data.WebsocketSubprotocol = types.StringValue(subgraph.GetWebsocketSubprotocol()) data.IsEventDrivenGraph = types.BoolValue(subgraph.GetIsEventDrivenGraph()) @@ -202,6 +208,11 @@ func (r *SubgraphResource) Create(ctx context.Context, req resource.CreateReques } mapValue, _ := types.MapValueFrom(ctx, types.StringType, labels) data.Labels = mapValue + + if subgraph.GetSubscriptionUrl() != "" { + data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) + } + if subgraph.Readme != nil { data.Readme = types.StringValue(subgraph.GetReadme()) } @@ -287,12 +298,15 @@ func (r *SubgraphResource) Read(ctx context.Context, req resource.ReadRequest, r data.Name = types.StringValue(subgraph.GetName()) data.Namespace = types.StringValue(subgraph.GetNamespace()) data.RoutingURL = types.StringValue(subgraph.GetRoutingURL()) - data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) data.SubscriptionProtocol = types.StringValue(subgraph.GetSubscriptionProtocol()) data.WebsocketSubprotocol = types.StringValue(subgraph.GetWebsocketSubprotocol()) data.IsEventDrivenGraph = types.BoolValue(subgraph.GetIsEventDrivenGraph()) data.Labels = mapValue + if subgraph.GetSubscriptionUrl() != "" { + data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) + } + if subgraph.Readme != nil { data.Readme = types.StringValue(subgraph.GetReadme()) } @@ -355,16 +369,19 @@ func (r *SubgraphResource) Update(ctx context.Context, req resource.UpdateReques } if data.Schema.ValueString() != "" { - apiError := r.publishSubgraphSchema(ctx, data) - if apiError != nil { - if api.IsNotFoundError(apiErr) { + err := r.publishSubgraphSchema(ctx, data) + if err != nil { + if api.IsNotFoundError(err) { utils.AddDiagnosticError(resp, ErrUpdatingSubgraph, - apiErr.Error(), + err.Error(), ) resp.State.RemoveResource(ctx) return - } else if !api.IsSubgraphCompositionFailedError(apiError) { + } else if api.IsSubgraphCompositionFailedError(err) { + utils.AddDiagnosticError(resp, ErrSubgraphCompositionFailed, err.Error()) + } else { + utils.AddDiagnosticError(resp, ErrPublishingSubgraph, err.Error()) return } } @@ -405,12 +422,15 @@ func (r *SubgraphResource) Update(ctx context.Context, req resource.UpdateReques data.Name = types.StringValue(subgraph.GetName()) data.Namespace = types.StringValue(subgraph.GetNamespace()) data.RoutingURL = types.StringValue(subgraph.GetRoutingURL()) - data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) data.SubscriptionProtocol = types.StringValue(subgraph.GetSubscriptionProtocol()) data.WebsocketSubprotocol = types.StringValue(subgraph.GetWebsocketSubprotocol()) data.IsEventDrivenGraph = types.BoolValue(subgraph.GetIsEventDrivenGraph()) data.Labels = mapValue + if subgraph.GetSubscriptionUrl() != "" { + data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) + } + if subgraph.Readme != nil { data.Readme = types.StringValue(subgraph.GetReadme()) } @@ -484,11 +504,15 @@ func (r *SubgraphResource) createAndPublishSubgraph(ctx context.Context, data Su if data.Schema.ValueString() != "" { apiError := r.publishSubgraphSchema(ctx, data) if apiError != nil { - if api.IsSubgraphCompositionFailedError(apiError) { - utils.AddDiagnosticError(resp, ErrSubgraphCompositionFailed, apiError.Error()) - } else if api.IsInvalidSubgraphSchemaError(apiError) { - utils.AddDiagnosticError(resp, ErrPublishingSubgraph, apiError.Error()) + if api.IsNotFoundError(apiError) { + utils.AddDiagnosticError(resp, + ErrUpdatingSubgraph, + apiError.Error(), + ) + resp.State.RemoveResource(ctx) return nil, apiError + } else if api.IsSubgraphCompositionFailedError(apiError) { + utils.AddDiagnosticError(resp, ErrSubgraphCompositionFailed, apiError.Error()) } else { utils.AddDiagnosticError(resp, ErrPublishingSubgraph, apiError.Error()) return nil, apiError diff --git a/internal/service/subgraph/resource_cosmo_subgraph_test.go b/internal/service/subgraph/resource_cosmo_subgraph_test.go index cf0950c..79c338c 100644 --- a/internal/service/subgraph/resource_cosmo_subgraph_test.go +++ b/internal/service/subgraph/resource_cosmo_subgraph_test.go @@ -62,7 +62,6 @@ func TestAccStandaloneSubgraphResource(t *testing.T) { federatedGraphRoutingURL := "https://federated-graph-standalone-subgraph-example.com" subgraphName := acctest.RandomWithPrefix("test-subgraph") - routingURL := "https://subgraph-standalone-example.com" subgraphSchema := acceptance.TestAccValidSubgraphSchema From abea691732b32f4f70d379d0a3e80ee2051e5abc Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Thu, 14 Nov 2024 17:36:41 +0530 Subject: [PATCH 06/19] fix: ci --- docs/data-sources/contract.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/data-sources/contract.md b/docs/data-sources/contract.md index 7f1921c..502d84a 100644 --- a/docs/data-sources/contract.md +++ b/docs/data-sources/contract.md @@ -31,7 +31,9 @@ data "cosmo_subgraph" "test" { - `admission_webhook_secret` (String, Sensitive) The secret token used to authenticate the admission webhook requests. - `admission_webhook_url` (String) The URL for the admission webhook that will be triggered during graph operations. +- `exclude_tags` (List of String) - `id` (String) The unique identifier of the federated graph resource, automatically generated by the system. +- `include_tags` (List of String) - `label_matchers` (Map of String) A list of label matchers used to select the services that will form the federated graph. - `readme` (String) Readme content for the federated graph. - `routing_url` (String) The URL for the federated graph. From 108d13a0921123997e3ee977384abfc4597657fc Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Thu, 14 Nov 2024 19:10:52 +0530 Subject: [PATCH 07/19] feat: add publish monograph feature --- .../guides/cosmo-monograph-contract/main.tf | 1 + .../cosmo-monograph-contract/variables.tf | 4 ++ .../resources/cosmo_monograph/resource.tf | 1 + .../resources/cosmo_monograph/variables.tf | 4 ++ internal/api/monograph.go | 23 +++++++ internal/service/monograph/errors.go | 1 + .../monograph/resource_cosmo_monograph.go | 64 +++++++++++++++++-- 7 files changed, 93 insertions(+), 5 deletions(-) diff --git a/examples/guides/cosmo-monograph-contract/main.tf b/examples/guides/cosmo-monograph-contract/main.tf index 169320e..4173ddf 100644 --- a/examples/guides/cosmo-monograph-contract/main.tf +++ b/examples/guides/cosmo-monograph-contract/main.tf @@ -11,6 +11,7 @@ module "cosmo_monograph" { monograph_namespace = module.cosmo_namespace.name monograph_graph_url = var.monograph_graph_url monograph_routing_url = var.monograph_routing_url + monograph_schema = var.monograph_schema } module "cosmo_contract" { diff --git a/examples/guides/cosmo-monograph-contract/variables.tf b/examples/guides/cosmo-monograph-contract/variables.tf index b5e2980..953a14f 100644 --- a/examples/guides/cosmo-monograph-contract/variables.tf +++ b/examples/guides/cosmo-monograph-contract/variables.tf @@ -14,6 +14,10 @@ variable "monograph_routing_url" { default = "http://example.com/routing" } +variable "monograph_schema" { + default = "type Query{ a: String }" +} + variable "contract_name" { type = string default = "test" diff --git a/examples/resources/cosmo_monograph/resource.tf b/examples/resources/cosmo_monograph/resource.tf index 5ca4473..2b5359d 100644 --- a/examples/resources/cosmo_monograph/resource.tf +++ b/examples/resources/cosmo_monograph/resource.tf @@ -3,4 +3,5 @@ resource "cosmo_monograph" "example" { namespace = var.monograph_namespace graph_url = var.monograph_graph_url routing_url = var.monograph_routing_url + schema = var.monograph_schema } \ No newline at end of file diff --git a/examples/resources/cosmo_monograph/variables.tf b/examples/resources/cosmo_monograph/variables.tf index 60ed5e8..a9afb35 100644 --- a/examples/resources/cosmo_monograph/variables.tf +++ b/examples/resources/cosmo_monograph/variables.tf @@ -12,4 +12,8 @@ variable "monograph_graph_url" { variable "monograph_routing_url" { default = "http://example.com/routing" +} + +variable "monograph_schema" { + default = "type Query{ a: String }" } \ No newline at end of file diff --git a/internal/api/monograph.go b/internal/api/monograph.go index ea5d090..cc970f6 100644 --- a/internal/api/monograph.go +++ b/internal/api/monograph.go @@ -111,3 +111,26 @@ func (p PlatformClient) GetMonograph(ctx context.Context, name string, namespace return response.Msg.Graph, nil } + +func (p PlatformClient) PublishMonograph(ctx context.Context, name string, namespace string, schema string) *ApiError { + request := connect.NewRequest(&platformv1.PublishMonographRequest{ + Name: name, + Namespace: namespace, + Schema: schema, + }) + response, err := p.Client.PublishMonograph(ctx, request) + if err != nil { + return &ApiError{Err: err, Reason: "PublishMonograph", Status: common.EnumStatusCode_ERR} + } + + if response.Msg == nil { + return &ApiError{Err: ErrEmptyMsg, Reason: "PublishMonograph", Status: common.EnumStatusCode_ERR} + } + + apiError := handleErrorCodes(response.Msg.GetResponse().Code, response.Msg.String()) + if apiError != nil { + return apiError + } + + return nil +} diff --git a/internal/service/monograph/errors.go b/internal/service/monograph/errors.go index 04d41dd..d3fd061 100644 --- a/internal/service/monograph/errors.go +++ b/internal/service/monograph/errors.go @@ -3,6 +3,7 @@ package monograph const ( ErrInvalidMonographName = "Invalid Monograph Name" ErrCreatingMonograph = "Error Creating Monograph" + ErrPublishingMonograph = "Error Publishing Monograph" ErrCompositionError = "Composition Error" ErrRetrievingMonograph = "Error Retrieving Monograph" ErrInvalidResourceID = "Invalid Resource ID" diff --git a/internal/service/monograph/resource_cosmo_monograph.go b/internal/service/monograph/resource_cosmo_monograph.go index 081adff..995be6e 100644 --- a/internal/service/monograph/resource_cosmo_monograph.go +++ b/internal/service/monograph/resource_cosmo_monograph.go @@ -33,6 +33,7 @@ type MonographResourceModel struct { Readme types.String `tfsdk:"readme"` AdmissionWebhookURL types.String `tfsdk:"admission_webhook_url"` AdmissionWebhookSecret types.String `tfsdk:"admission_webhook_secret"` + Schema types.String `tfsdk:"schema"` } func NewMonographResource() resource.Resource { @@ -112,6 +113,10 @@ For more information on monographs, please refer to the [Cosmo Documentation](ht stringvalidator.OneOf(api.GraphQLSubscriptionProtocolWS, api.GraphQLSubscriptionProtocolSSE, api.GraphQLSubscriptionProtocolSSEPost), }, }, + "schema": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The schema for the subgraph.", + }, }, } } @@ -170,6 +175,26 @@ func (r *MonographResource) Create(ctx context.Context, req resource.CreateReque return } + if data.Schema.ValueString() != "" { + err := r.client.PublishMonograph(ctx, data.Name.ValueString(), data.Namespace.ValueString(), data.Schema.ValueString()) + if err != nil { + if api.IsNotFoundError(err) { + utils.AddDiagnosticError(resp, + ErrPublishingMonograph, + err.Error(), + ) + resp.State.RemoveResource(ctx) + return + } else { + utils.AddDiagnosticError(resp, + ErrPublishingMonograph, + err.Error(), + ) + return + } + } + } + monograph, apiError := r.client.GetMonograph(ctx, data.Name.ValueString(), data.Namespace.ValueString()) if apiError != nil { utils.AddDiagnosticError(resp, @@ -250,11 +275,40 @@ func (r *MonographResource) Update(ctx context.Context, req resource.UpdateReque data.AdmissionWebhookSecret.ValueString(), ) if err != nil { - utils.AddDiagnosticError(resp, - ErrUpdatingMonograph, - err.Error(), - ) - return + if api.IsNotFoundError(err) { + utils.AddDiagnosticError(resp, + ErrUpdatingMonograph, + err.Error(), + ) + resp.State.RemoveResource(ctx) + return + } else { + utils.AddDiagnosticError(resp, + ErrUpdatingMonograph, + err.Error(), + ) + return + } + } + + if data.Schema.ValueString() != "" { + err := r.client.PublishMonograph(ctx, data.Name.ValueString(), data.Namespace.ValueString(), data.Schema.ValueString()) + if err != nil { + if api.IsNotFoundError(err) { + utils.AddDiagnosticError(resp, + ErrUpdatingMonograph, + err.Error(), + ) + resp.State.RemoveResource(ctx) + return + } else { + utils.AddDiagnosticError(resp, + ErrUpdatingMonograph, + err.Error(), + ) + return + } + } } utils.LogAction(ctx, "updated monograph", data.Id.ValueString(), data.Name.ValueString(), data.Namespace.ValueString()) From 240c53576199462947493f9bf272fbb8ca93cc64 Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Thu, 14 Nov 2024 19:14:43 +0530 Subject: [PATCH 08/19] fix: ci --- docs/resources/monograph.md | 2 ++ examples/guides/cosmo-monograph-contract/main.tf | 2 +- examples/resources/cosmo_monograph/resource.tf | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/resources/monograph.md b/docs/resources/monograph.md index 28101a4..f48c40b 100644 --- a/docs/resources/monograph.md +++ b/docs/resources/monograph.md @@ -21,6 +21,7 @@ resource "cosmo_monograph" "example" { namespace = var.monograph_namespace graph_url = var.monograph_graph_url routing_url = var.monograph_routing_url + schema = var.monograph_schema } ``` @@ -39,6 +40,7 @@ resource "cosmo_monograph" "example" { - `admission_webhook_url` (String) The admission webhook URL for the monograph. - `namespace` (String) The namespace in which the monograph is located. - `readme` (String) The readme for the subgraph. +- `schema` (String) The schema for the subgraph. - `subscription_protocol` (String) The subscription protocol for the subgraph. - `subscription_url` (String) The subscription URL for the subgraph. - `websocket_subprotocol` (String) The websocket subprotocol for the subgraph. diff --git a/examples/guides/cosmo-monograph-contract/main.tf b/examples/guides/cosmo-monograph-contract/main.tf index 4173ddf..303f1f4 100644 --- a/examples/guides/cosmo-monograph-contract/main.tf +++ b/examples/guides/cosmo-monograph-contract/main.tf @@ -11,7 +11,7 @@ module "cosmo_monograph" { monograph_namespace = module.cosmo_namespace.name monograph_graph_url = var.monograph_graph_url monograph_routing_url = var.monograph_routing_url - monograph_schema = var.monograph_schema + monograph_schema = var.monograph_schema } module "cosmo_contract" { diff --git a/examples/resources/cosmo_monograph/resource.tf b/examples/resources/cosmo_monograph/resource.tf index 2b5359d..1a00bad 100644 --- a/examples/resources/cosmo_monograph/resource.tf +++ b/examples/resources/cosmo_monograph/resource.tf @@ -3,5 +3,5 @@ resource "cosmo_monograph" "example" { namespace = var.monograph_namespace graph_url = var.monograph_graph_url routing_url = var.monograph_routing_url - schema = var.monograph_schema + schema = var.monograph_schema } \ No newline at end of file From 5e075cd1a428b6da8727c2435cece39973540831 Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Fri, 15 Nov 2024 01:47:50 +0530 Subject: [PATCH 09/19] fix: delete contract when the source is a monograph --- docs/data-sources/contract.md | 1 + docs/resources/contract.md | 1 + internal/api/contract.go | 8 +++- .../contract/data_source_cosmo_contract.go | 6 +++ .../contract/resource_cosmo_contract.go | 10 ++++- .../contract/resource_cosmo_contract_test.go | 38 +++++++++++++++++++ 6 files changed, 61 insertions(+), 3 deletions(-) diff --git a/docs/data-sources/contract.md b/docs/data-sources/contract.md index 502d84a..8dc01f1 100644 --- a/docs/data-sources/contract.md +++ b/docs/data-sources/contract.md @@ -37,3 +37,4 @@ data "cosmo_subgraph" "test" { - `label_matchers` (Map of String) A list of label matchers used to select the services that will form the federated graph. - `readme` (String) Readme content for the federated graph. - `routing_url` (String) The URL for the federated graph. +- `supports_federation` (Boolean) SupportFederation defines if this contract's source graph is a federated graph or a monograph.. diff --git a/docs/resources/contract.md b/docs/resources/contract.md index 22e1477..ce80160 100644 --- a/docs/resources/contract.md +++ b/docs/resources/contract.md @@ -42,6 +42,7 @@ resource "cosmo_contract" "test" { - `exclude_tags` (List of String) - `include_tags` (List of String) - `readme` (String) +- `supports_federation` (Boolean) ### Read-Only diff --git a/internal/api/contract.go b/internal/api/contract.go index 758947f..21a9e69 100644 --- a/internal/api/contract.go +++ b/internal/api/contract.go @@ -63,8 +63,12 @@ func (p *PlatformClient) UpdateContract(ctx context.Context, name, namespace str return response.Msg, nil } -func (p *PlatformClient) DeleteContract(ctx context.Context, name, namespace string) *ApiError { - return p.DeleteFederatedGraph(ctx, name, namespace) +func (p *PlatformClient) DeleteContract(ctx context.Context, name, namespace string, supportsFederation bool) *ApiError { + if supportsFederation { + return p.DeleteFederatedGraph(ctx, name, namespace) + } else { + return p.DeleteMonograph(ctx, name, namespace) + } } func (p *PlatformClient) GetContract(ctx context.Context, name, namespace string) (*platformv1.GetFederatedGraphByNameResponse, *ApiError) { diff --git a/internal/service/contract/data_source_cosmo_contract.go b/internal/service/contract/data_source_cosmo_contract.go index f0e911a..b29b6f2 100644 --- a/internal/service/contract/data_source_cosmo_contract.go +++ b/internal/service/contract/data_source_cosmo_contract.go @@ -31,6 +31,7 @@ type contractDataSourceModel struct { LabelMatchers types.Map `tfsdk:"label_matchers"` ExcludeTags types.List `tfsdk:"exclude_tags"` IncludeTags types.List `tfsdk:"include_tags"` + SupportsFederation types.Bool `tfsdk:"supports_federation"` } func (d *contractDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { @@ -82,6 +83,10 @@ func (d *contractDataSource) Schema(ctx context.Context, req datasource.SchemaRe Computed: true, ElementType: types.StringType, }, + "supports_federation": schema.BoolAttribute{ + MarkdownDescription: "SupportFederation defines if this contract's source graph is a federated graph or a monograph..", + Computed: true, + }, }, } } @@ -138,6 +143,7 @@ func (d *contractDataSource) Read(ctx context.Context, req datasource.ReadReques data.Name = types.StringValue(graph.GetName()) data.Namespace = types.StringValue(graph.GetNamespace()) data.RoutingURL = types.StringValue(graph.GetRoutingURL()) + data.SupportsFederation = types.BoolValue(graph.GetSupportsFederation()) if graph.Contract != nil && len(graph.Contract.GetExcludeTags()) > 0 { var responseExcludeTags []attr.Value diff --git a/internal/service/contract/resource_cosmo_contract.go b/internal/service/contract/resource_cosmo_contract.go index 6f3aa27..f2bb4f9 100644 --- a/internal/service/contract/resource_cosmo_contract.go +++ b/internal/service/contract/resource_cosmo_contract.go @@ -37,6 +37,7 @@ type contractResourceModel struct { Readme types.String `tfsdk:"readme"` AdmissionWebhookUrl types.String `tfsdk:"admission_webhook_url"` AdmissionWebhookSecret types.String `tfsdk:"admission_webhook_secret"` + SupportsFederation types.Bool `tfsdk:"supports_federation"` } func (r *contractResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -92,6 +93,10 @@ For more information, refer to the Cosmo Documentation at https://cosmo-docs.wun "routing_url": schema.StringAttribute{ Required: true, }, + "supports_federation": schema.BoolAttribute{ + Optional: true, + Computed: true, + }, }, } } @@ -134,6 +139,7 @@ func (r *contractResource) Create(ctx context.Context, req resource.CreateReques data.Name = types.StringValue(graph.GetName()) data.Namespace = types.StringValue(graph.GetNamespace()) data.RoutingURL = types.StringValue(graph.GetRoutingURL()) + data.SupportsFederation = types.BoolValue(graph.GetSupportsFederation()) if graph.Contract != nil && len(graph.Contract.GetExcludeTags()) > 0 { var responseExcludeTags []attr.Value @@ -195,6 +201,7 @@ func (r *contractResource) Read(ctx context.Context, req resource.ReadRequest, r data.Name = types.StringValue(graph.GetName()) data.Namespace = types.StringValue(graph.GetNamespace()) data.RoutingURL = types.StringValue(graph.GetRoutingURL()) + data.SupportsFederation = types.BoolValue(graph.GetSupportsFederation()) if graph.Contract != nil && len(graph.Contract.GetExcludeTags()) > 0 { var responseExcludeTags []attr.Value @@ -286,6 +293,7 @@ func (r *contractResource) Update(ctx context.Context, req resource.UpdateReques data.Name = types.StringValue(graph.GetName()) data.Namespace = types.StringValue(graph.GetNamespace()) data.RoutingURL = types.StringValue(graph.GetRoutingURL()) + data.SupportsFederation = types.BoolValue(graph.GetSupportsFederation()) if graph.Contract != nil && len(graph.Contract.GetExcludeTags()) > 0 { var responseExcludeTags []attr.Value @@ -322,7 +330,7 @@ func (r *contractResource) Delete(ctx context.Context, req resource.DeleteReques return } - apiError := r.client.DeleteContract(ctx, data.Name.ValueString(), data.Namespace.ValueString()) + apiError := r.client.DeleteContract(ctx, data.Name.ValueString(), data.Namespace.ValueString(), data.SupportsFederation.ValueBool()) if apiError != nil { if api.IsNotFoundError(apiError) { utils.AddDiagnosticError(resp, diff --git a/internal/service/contract/resource_cosmo_contract_test.go b/internal/service/contract/resource_cosmo_contract_test.go index a8a7c44..3374f24 100644 --- a/internal/service/contract/resource_cosmo_contract_test.go +++ b/internal/service/contract/resource_cosmo_contract_test.go @@ -42,6 +42,18 @@ func TestAccContractResource(t *testing.T) { Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, readme), Destroy: true, }, + { + Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphRoutingURL, subgraphSchema, name, readme), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cosmo_contract.test_mono", "name", name), + resource.TestCheckResourceAttr("cosmo_contract.test_mono", "namespace", namespace), + resource.TestCheckResourceAttr("cosmo_contract.test_mono", "readme", readme), + ), + }, + { + Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphRoutingURL, subgraphSchema, name, readme), + Destroy: true, + }, }, }) } @@ -78,3 +90,29 @@ resource "cosmo_contract" "test" { } `, namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractReadme) } + +func testAccContractOfMonographResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, graphUrl, schema, contractName, contractReadme string) string { + return fmt.Sprintf(` +resource "cosmo_namespace" "test_mono" { + name = "%s" +} + +resource "cosmo_monograph" "test_mono" { + name = "%s" + namespace = cosmo_namespace.test_mono.name + routing_url = "%s" + graph_url = "%s" + schema = <<-EOT + %s + EOT +} + +resource "cosmo_contract" "test_mono" { + name = "%s" + namespace = cosmo_namespace.test_mono.name + source = cosmo_monograph.test_mono.name + routing_url = "http://localhost:3003" + readme = "%s" +} +`, namespace, federatedGraphName, federatedGraphRoutingURL, graphUrl, schema, contractName, contractReadme) +} From 1cfbbc71af6fb99003bf2fe40f8f42ad1da6f280 Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Wed, 4 Dec 2024 02:05:38 +0530 Subject: [PATCH 10/19] feat: improve tests and handle optional values --- go.mod | 2 +- go.sum | 4 + internal/api/contract.go | 14 ++- internal/api/subgraph.go | 6 +- .../contract/resource_cosmo_contract.go | 17 ++- .../contract/resource_cosmo_contract_test.go | 65 +++++++++- .../resource_cosmo_federated_graph.go | 26 ++-- .../resource_cosmo_federated_graph_test.go | 25 ++-- .../subgraph/resource_cosmo_subgraph.go | 22 +++- .../subgraph/resource_cosmo_subgraph_test.go | 118 ++++++++++++++++-- 10 files changed, 255 insertions(+), 44 deletions(-) diff --git a/go.mod b/go.mod index 5272a94..ed6542f 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/hashicorp/terraform-plugin-go v0.23.0 github.com/hashicorp/terraform-plugin-log v0.9.0 github.com/hashicorp/terraform-plugin-testing v1.10.0 - github.com/wundergraph/cosmo/connect-go v0.0.0-20241104193239-b78c5917d64b + github.com/wundergraph/cosmo/connect-go v0.0.0-20241203152720-979e5a780c8e ) require ( diff --git a/go.sum b/go.sum index 8ce691b..a9b5b47 100644 --- a/go.sum +++ b/go.sum @@ -198,6 +198,10 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/wundergraph/cosmo/connect-go v0.0.0-20241104193239-b78c5917d64b h1:N6CQBlWN7B8cOIVPNxZxkmgOUrSeaZebdhmdGxmg3/8= github.com/wundergraph/cosmo/connect-go v0.0.0-20241104193239-b78c5917d64b/go.mod h1:RLepGeaXdENMlePq4geGzaDV895QuJZ+mUFLzG5ra9E= +github.com/wundergraph/cosmo/connect-go v0.0.0-20241127080034-0681d60a5f89 h1:JnLcb7QijyHR8LoulHw+jiBqM5Z9RNU7/7co3MTgxTY= +github.com/wundergraph/cosmo/connect-go v0.0.0-20241127080034-0681d60a5f89/go.mod h1:RLepGeaXdENMlePq4geGzaDV895QuJZ+mUFLzG5ra9E= +github.com/wundergraph/cosmo/connect-go v0.0.0-20241203152720-979e5a780c8e h1:XFEGOGnBWR6cfW3gV+24An3lNoesWOxTH71D09Tuph4= +github.com/wundergraph/cosmo/connect-go v0.0.0-20241203152720-979e5a780c8e/go.mod h1:RLepGeaXdENMlePq4geGzaDV895QuJZ+mUFLzG5ra9E= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= diff --git a/internal/api/contract.go b/internal/api/contract.go index 21a9e69..5b6599f 100644 --- a/internal/api/contract.go +++ b/internal/api/contract.go @@ -38,12 +38,16 @@ func (p *PlatformClient) CreateContract(ctx context.Context, name, namespace, so return response.Msg, nil } -func (p *PlatformClient) UpdateContract(ctx context.Context, name, namespace string, excludeTags []string, includeTags []string) (*platformv1.UpdateContractResponse, *ApiError) { +func (p *PlatformClient) UpdateContract(ctx context.Context, name, namespace string, excludeTags []string, includeTags []string, routingUrl, admissionWebhookUrl, admissionWebhookSecret, readme string) (*platformv1.UpdateContractResponse, *ApiError) { request := connect.NewRequest(&platformv1.UpdateContractRequest{ - Name: name, - Namespace: namespace, - ExcludeTags: excludeTags, - IncludeTags: includeTags, + Name: name, + Namespace: namespace, + ExcludeTags: excludeTags, + IncludeTags: includeTags, + RoutingUrl: &routingUrl, + AdmissionWebhookUrl: &admissionWebhookUrl, + AdmissionWebhookSecret: &admissionWebhookSecret, + Readme: &readme, }) response, err := p.Client.UpdateContract(ctx, request) diff --git a/internal/api/subgraph.go b/internal/api/subgraph.go index a0712ff..bd2bcb8 100644 --- a/internal/api/subgraph.go +++ b/internal/api/subgraph.go @@ -39,14 +39,14 @@ func (p PlatformClient) CreateSubgraph(ctx context.Context, name string, namespa return nil } -func (p PlatformClient) UpdateSubgraph(ctx context.Context, name, namespace, routingUrl string, labels []*platformv1.Label, headers []string, subscriptionUrl, readme *string, unsetLabels *bool, websocketSubprotocol string, subscriptionProtocol string) *ApiError { +func (p PlatformClient) UpdateSubgraph(ctx context.Context, name, namespace, routingUrl string, labels []*platformv1.Label, headers []string, subscriptionUrl, readme string, unsetLabels *bool, subscriptionProtocol string, websocketSubprotocol string) *ApiError { request := connect.NewRequest(&platformv1.UpdateSubgraphRequest{ Name: name, RoutingUrl: &routingUrl, Labels: labels, Headers: headers, - SubscriptionUrl: subscriptionUrl, - Readme: readme, + SubscriptionUrl: &subscriptionUrl, + Readme: &readme, Namespace: namespace, UnsetLabels: unsetLabels, WebsocketSubprotocol: resolveWebsocketSubprotocol(websocketSubprotocol), diff --git a/internal/service/contract/resource_cosmo_contract.go b/internal/service/contract/resource_cosmo_contract.go index f2bb4f9..09a755c 100644 --- a/internal/service/contract/resource_cosmo_contract.go +++ b/internal/service/contract/resource_cosmo_contract.go @@ -263,7 +263,22 @@ func (r *contractResource) Update(ctx context.Context, req resource.UpdateReques return } - _, apiError := r.client.UpdateContract(ctx, data.Name.ValueString(), data.Namespace.ValueString(), excludeTags, includeTags) + admissionWebhookUrl := "" + if data.AdmissionWebhookUrl.ValueStringPointer() != nil { + admissionWebhookUrl = *data.AdmissionWebhookUrl.ValueStringPointer() + } + + admissionWebhookSecret := "" + if data.AdmissionWebhookSecret.ValueStringPointer() != nil { + admissionWebhookSecret = *data.AdmissionWebhookSecret.ValueStringPointer() + } + + readme := "" + if data.Readme.ValueStringPointer() != nil { + readme = *data.Readme.ValueStringPointer() + } + + _, apiError := r.client.UpdateContract(ctx, data.Name.ValueString(), data.Namespace.ValueString(), excludeTags, includeTags, data.RoutingURL.ValueString(), admissionWebhookUrl, admissionWebhookSecret, readme) if apiError != nil { if api.IsContractCompositionFailedError(apiError) || api.IsSubgraphCompositionFailedError(apiError) { utils.AddDiagnosticError(resp, diff --git a/internal/service/contract/resource_cosmo_contract_test.go b/internal/service/contract/resource_cosmo_contract_test.go index 3374f24..1de28b3 100644 --- a/internal/service/contract/resource_cosmo_contract_test.go +++ b/internal/service/contract/resource_cosmo_contract_test.go @@ -27,11 +27,21 @@ func TestAccContractResource(t *testing.T) { ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, "internal", &readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), resource.TestCheckResourceAttr("cosmo_contract.test", "readme", readme), + resource.TestCheckResourceAttr("cosmo_contract.test", "exclude_tags.0", "internal"), + ), + }, + { + Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, "external", &readme), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), + resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), + resource.TestCheckResourceAttr("cosmo_contract.test", "readme", readme), + resource.TestCheckResourceAttr("cosmo_contract.test", "exclude_tags.0", "external"), ), }, { @@ -39,7 +49,7 @@ func TestAccContractResource(t *testing.T) { RefreshState: true, }, { - Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, "external", &readme), Destroy: true, }, { @@ -58,7 +68,51 @@ func TestAccContractResource(t *testing.T) { }) } -func testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractReadme string) string { +func TestOptionalValuesOfContractResource(t *testing.T) { + name := acctest.RandomWithPrefix("test-contract") + namespace := acctest.RandomWithPrefix("test-namespace") + + federatedGraphName := acctest.RandomWithPrefix("test-federated-graph") + federatedGraphRoutingURL := "https://example.com:3000" + + subgraphName := acctest.RandomWithPrefix("test-subgraph") + subgraphRoutingURL := "https://subgraph-standalone-example.com" + subgraphSchema := acceptance.TestAccValidSubgraphSchema + + readme := "Initial readme content" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acceptance.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, "internal", &readme), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), + resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), + resource.TestCheckResourceAttr("cosmo_contract.test", "exclude_tags.0", "internal"), + resource.TestCheckResourceAttr("cosmo_contract.test", "readme", readme), + ), + }, + { + Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, "external", nil), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), + resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), + resource.TestCheckResourceAttr("cosmo_contract.test", "exclude_tags.0", "external"), + resource.TestCheckNoResourceAttr("cosmo_contract.test", "readme"), + ), + }, + }, + }) +} + +func testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractExcludeTag string, contractReadme *string) string { + var readmePart string + if contractReadme != nil { + readmePart = fmt.Sprintf(`readme = "%s"`, *contractReadme) + } + return fmt.Sprintf(` resource "cosmo_namespace" "test" { name = "%s" @@ -86,9 +140,10 @@ resource "cosmo_contract" "test" { namespace = cosmo_namespace.test.name source = cosmo_federated_graph.test.name routing_url = "http://localhost:3003" - readme = "%s" + exclude_tags = ["%s"] + %s } -`, namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractReadme) +`, namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractExcludeTag, readmePart) } func testAccContractOfMonographResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, graphUrl, schema, contractName, contractReadme string) string { diff --git a/internal/service/federated-graph/resource_cosmo_federated_graph.go b/internal/service/federated-graph/resource_cosmo_federated_graph.go index e59e6c1..0fbf1cf 100644 --- a/internal/service/federated-graph/resource_cosmo_federated_graph.go +++ b/internal/service/federated-graph/resource_cosmo_federated_graph.go @@ -237,21 +237,31 @@ func (r *FederatedGraphResource) Update(ctx context.Context, req resource.Update return } + readme := "" + if data.Readme.ValueStringPointer() != nil { + readme = *data.Readme.ValueStringPointer() + } + + admissionWebhookUrl := "" + if data.AdmissionWebhookUrl.ValueStringPointer() != nil { + admissionWebhookUrl = *data.AdmissionWebhookUrl.ValueStringPointer() + } + + admissionWebhookSecret := "" + if !data.AdmissionWebhookSecret.IsNull() { + admissionWebhookSecret = *data.AdmissionWebhookSecret.ValueStringPointer() + } + updatedGraph := platformv1.FederatedGraph{ Name: data.Name.ValueString(), Namespace: data.Namespace.ValueString(), RoutingURL: data.RoutingURL.ValueString(), - AdmissionWebhookUrl: data.AdmissionWebhookUrl.ValueStringPointer(), + AdmissionWebhookUrl: &admissionWebhookUrl, LabelMatchers: labelMatchers, - Readme: data.Readme.ValueStringPointer(), - } - - var admissionWebhookSecret *string - if !data.AdmissionWebhookSecret.IsNull() { - admissionWebhookSecret = data.AdmissionWebhookSecret.ValueStringPointer() + Readme: &readme, } - _, apiError := r.client.UpdateFederatedGraph(ctx, admissionWebhookSecret, &updatedGraph) + _, apiError := r.client.UpdateFederatedGraph(ctx, &admissionWebhookSecret, &updatedGraph) if apiError != nil { if api.IsSubgraphCompositionFailedError(apiError) { utils.AddDiagnosticError(resp, diff --git a/internal/service/federated-graph/resource_cosmo_federated_graph_test.go b/internal/service/federated-graph/resource_cosmo_federated_graph_test.go index 295cd8e..8543c88 100644 --- a/internal/service/federated-graph/resource_cosmo_federated_graph_test.go +++ b/internal/service/federated-graph/resource_cosmo_federated_graph_test.go @@ -25,7 +25,7 @@ func TestAccFederatedGraphResource(t *testing.T) { ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccFederatedGraphResourceConfig(namespace, name, routingURL, readme), + Config: testAccFederatedGraphResourceConfig(namespace, name, routingURL, &readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_federated_graph.test", "name", name), resource.TestCheckResourceAttr("cosmo_federated_graph.test", "namespace", namespace), @@ -34,21 +34,26 @@ func TestAccFederatedGraphResource(t *testing.T) { ), }, { - Config: testAccFederatedGraphResourceConfig(namespace, name, routingURL, newReadme), + Config: testAccFederatedGraphResourceConfig(namespace, name, routingURL, &newReadme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_federated_graph.test", "readme", newReadme), ), }, { - Config: testAccFederatedGraphResourceConfig(namespace, name, updatedRoutingURL, newReadme), + Config: testAccFederatedGraphResourceConfig(namespace, name, updatedRoutingURL, nil), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_federated_graph.test", "routing_url", updatedRoutingURL), + resource.TestCheckNoResourceAttr("cosmo_federated_graph.test", "readme"), ), }, { ResourceName: "cosmo_federated_graph.test", RefreshState: true, }, + { + Config: testAccFederatedGraphResourceConfig(namespace, name, updatedRoutingURL, nil), + Destroy: true, + }, }, }) } @@ -56,20 +61,26 @@ func TestAccFederatedGraphResource(t *testing.T) { func TestAccFederatedGraphResourceInvalidConfig(t *testing.T) { name := acctest.RandomWithPrefix("test-federated-graph") namespace := acctest.RandomWithPrefix("test-namespace") + readme := "Initial readme content" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.TestAccPreCheck(t) }, ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccFederatedGraphResourceConfig(name, namespace, "invalid-url", ""), + Config: testAccFederatedGraphResourceConfig(name, namespace, "invalid-url", &readme), ExpectError: regexp.MustCompile(`.*Routing URL is not a valid URL*`), }, }, }) } -func testAccFederatedGraphResourceConfig(namespace, name, routingURL, readme string) string { +func testAccFederatedGraphResourceConfig(namespace, name, routingURL string, readme *string) string { + var readmePart string + if readme != nil { + readmePart = fmt.Sprintf(`readme = "%s"`, *readme) + } + return fmt.Sprintf(` resource "cosmo_namespace" "test" { name = "%s" @@ -79,7 +90,7 @@ resource "cosmo_federated_graph" "test" { name = "%s" namespace = cosmo_namespace.test.name routing_url = "%s" - readme = "%s" + %s } -`, namespace, name, routingURL, readme) +`, namespace, name, routingURL, readmePart) } diff --git a/internal/service/subgraph/resource_cosmo_subgraph.go b/internal/service/subgraph/resource_cosmo_subgraph.go index a933360..c912369 100644 --- a/internal/service/subgraph/resource_cosmo_subgraph.go +++ b/internal/service/subgraph/resource_cosmo_subgraph.go @@ -343,9 +343,29 @@ func (r *SubgraphResource) Update(ctx context.Context, req resource.UpdateReques unsetLabels = &[]bool{true}[0] } + readme := "" + if data.Readme.ValueStringPointer() != nil { + readme = *data.Readme.ValueStringPointer() + } + + subscriptionUrl := "" + if data.SubscriptionUrl.ValueStringPointer() != nil { + subscriptionUrl = *data.SubscriptionUrl.ValueStringPointer() + } + + subscriptionProtocol := api.GraphQLSubscriptionProtocolWS + if data.SubscriptionProtocol.ValueStringPointer() != nil { + subscriptionProtocol = *data.SubscriptionProtocol.ValueStringPointer() + } + + websocketSubprotocol := api.GraphQLWebsocketSubprotocolDefault + if data.WebsocketSubprotocol.ValueStringPointer() != nil { + websocketSubprotocol = *data.WebsocketSubprotocol.ValueStringPointer() + } + // TBD: This is only used in the update subgraph method and not used atm // headers := utils.ConvertHeadersToStringList(data.Headers) - apiErr := r.client.UpdateSubgraph(ctx, data.Name.ValueString(), data.Namespace.ValueString(), data.RoutingURL.ValueString(), labels, []string{}, data.SubscriptionUrl.ValueStringPointer(), data.Readme.ValueStringPointer(), unsetLabels, data.SubscriptionProtocol.ValueString(), data.WebsocketSubprotocol.ValueString()) + apiErr := r.client.UpdateSubgraph(ctx, data.Name.ValueString(), data.Namespace.ValueString(), data.RoutingURL.ValueString(), labels, []string{}, subscriptionUrl, readme, unsetLabels, subscriptionProtocol, websocketSubprotocol) if apiErr != nil { if api.IsSubgraphCompositionFailedError(apiErr) { utils.AddDiagnosticWarning(resp, diff --git a/internal/service/subgraph/resource_cosmo_subgraph_test.go b/internal/service/subgraph/resource_cosmo_subgraph_test.go index 79c338c..3d26ba6 100644 --- a/internal/service/subgraph/resource_cosmo_subgraph_test.go +++ b/internal/service/subgraph/resource_cosmo_subgraph_test.go @@ -2,6 +2,7 @@ package subgraph_test import ( "fmt" + "github.com/wundergraph/cosmo/terraform-provider-cosmo/internal/api" "regexp" "testing" @@ -22,23 +23,27 @@ func TestAccSubgraphResource(t *testing.T) { updatedRoutingURL := "https://updated-subgraph-example.com" subgraphSchema := acceptance.TestAccValidSubgraphSchema + readme := "Initial readme content" resource.Test(t, resource.TestCase{ PreCheck: func() { acceptance.TestAccPreCheck(t) }, ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, routingURL, subgraphSchema), + Config: testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, routingURL, subgraphSchema, readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_subgraph.test", "name", subgraphName), resource.TestCheckResourceAttr("cosmo_subgraph.test", "namespace", namespace), resource.TestCheckResourceAttr("cosmo_subgraph.test", "routing_url", routingURL), resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.team", "backend"), resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.stage", "dev"), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "subscription_protocol", api.GraphQLSubscriptionProtocolWS), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "websocket_subprotocol", api.GraphQLWebsocketSubprotocolDefault), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "readme", readme), ), }, { - Config: testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, updatedRoutingURL, subgraphSchema), + Config: testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, updatedRoutingURL, subgraphSchema, readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_subgraph.test", "routing_url", updatedRoutingURL), ), @@ -48,7 +53,7 @@ func TestAccSubgraphResource(t *testing.T) { RefreshState: true, }, { - Config: testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, routingURL, subgraphSchema), + Config: testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, routingURL, subgraphSchema, readme), Destroy: true, }, }, @@ -63,24 +68,40 @@ func TestAccStandaloneSubgraphResource(t *testing.T) { subgraphName := acctest.RandomWithPrefix("test-subgraph") routingURL := "https://subgraph-standalone-example.com" + updatedRoutingURL := "https://updated-subgraph-standalone-example.com" subgraphSchema := acceptance.TestAccValidSubgraphSchema + readme := "Initial readme content" + updatedReadme := "Updated readme content" + resource.Test(t, resource.TestCase{ PreCheck: func() { acceptance.TestAccPreCheck(t) }, ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, routingURL, subgraphSchema), + Config: testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, routingURL, subgraphSchema, readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_subgraph.test", "name", subgraphName), resource.TestCheckResourceAttr("cosmo_subgraph.test", "namespace", namespace), resource.TestCheckResourceAttr("cosmo_subgraph.test", "routing_url", routingURL), resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.team", "backend"), resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.stage", "dev"), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "readme", readme), ), }, { - Config: testStandaloneSubgraph(namespace, subgraphName, routingURL, subgraphSchema), + Config: testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, updatedRoutingURL, subgraphSchema, updatedReadme), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cosmo_subgraph.test", "name", subgraphName), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "namespace", namespace), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "routing_url", updatedRoutingURL), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.team", "backend"), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.stage", "dev"), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "readme", updatedReadme), + ), + }, + { + Config: testStandaloneSubgraph(namespace, subgraphName, routingURL, subgraphSchema, nil, nil, nil, nil), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_subgraph.test", "name", subgraphName), resource.TestCheckResourceAttr("cosmo_subgraph.test", "namespace", namespace), @@ -94,7 +115,7 @@ func TestAccStandaloneSubgraphResource(t *testing.T) { RefreshState: true, }, { - Config: testStandaloneSubgraph(namespace, subgraphName, routingURL, subgraphSchema), + Config: testStandaloneSubgraph(namespace, subgraphName, routingURL, subgraphSchema, nil, nil, nil, nil), Destroy: true, }, }, @@ -109,13 +130,14 @@ func TestAccSubgraphResourceInvalidSchema(t *testing.T) { federatedGraphName := acctest.RandomWithPrefix("test-subgraph") federatedGraphRoutingURL := "https://federated-graph-invalid-subgraph-schema-example.com" subgraphSchema := "invalid" + readme := "Initial readme content" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.TestAccPreCheck(t) }, ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema), + Config: testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, readme), ExpectError: regexp.MustCompile(`.*ERR_INVALID_SUBGRAPH_SCHEMA*`), }, }, @@ -135,7 +157,7 @@ func TestAccStandaloneSubgraphResourcePublishSchema(t *testing.T) { ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema), + Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, nil, nil, nil, nil), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_subgraph.test", "name", subgraphName), resource.TestCheckResourceAttr("cosmo_subgraph.test", "namespace", namespace), @@ -145,14 +167,62 @@ func TestAccStandaloneSubgraphResourcePublishSchema(t *testing.T) { ), }, { - Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, updatedSubgraphSchema), + Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, updatedSubgraphSchema, nil, nil, nil, nil), ExpectError: regexp.MustCompile(`.*ERR_INVALID_SUBGRAPH_SCHEMA*`), }, }, }) } -func testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphroutingURL, subgraphName, subgraphRoutingURL, subgraphSchema string) string { +func TestOptionalValuesOfSubgraphResource(t *testing.T) { + namespace := acctest.RandomWithPrefix("test-namespace") + subgraphName := acctest.RandomWithPrefix("test-subgraph") + subgraphRoutingURL := "https://subgraph-publish-schema-example.com" + + subgraphSchema := acceptance.TestAccValidSubgraphSchema + + readme := "Initial readme content" + subgraphSubscriptionURL := "https://subgraph-publish-schema-example.com/ws" + subscriptionProtocol := api.GraphQLSubscriptionProtocolSSE + websocketSubprotocol := api.GraphQLWebsocketSubprotocolGraphQLWS + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, &readme, &subgraphSubscriptionURL, &subscriptionProtocol, &websocketSubprotocol), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cosmo_subgraph.test", "name", subgraphName), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "namespace", namespace), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "routing_url", subgraphRoutingURL), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "readme", readme), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "subscription_url", subgraphSubscriptionURL), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "subscription_protocol", subscriptionProtocol), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "websocket_subprotocol", websocketSubprotocol), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.team", "backend"), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.stage", "dev"), + ), + }, + { + Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, nil, nil, nil, nil), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cosmo_subgraph.test", "name", subgraphName), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "namespace", namespace), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "routing_url", subgraphRoutingURL), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.team", "backend"), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.stage", "dev"), + resource.TestCheckNoResourceAttr("cosmo_subgraph.test", "readme"), + resource.TestCheckNoResourceAttr("cosmo_subgraph.test", "subscription_url"), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "subscription_protocol", api.GraphQLSubscriptionProtocolWS), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "websocket_subprotocol", api.GraphQLWebsocketSubprotocolDefault), + ), + }, + }, + }) +} + +func testAccSubgraphResourceConfig(namespace, federatedGraphName, federatedGraphroutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, readme string) string { return fmt.Sprintf(` resource "cosmo_namespace" "test" { name = "%s" @@ -178,11 +248,29 @@ resource "cosmo_subgraph" "test" { "team" = "backend", "stage" = "dev" } + readme = "%s" } -`, namespace, federatedGraphName, federatedGraphroutingURL, subgraphName, subgraphRoutingURL, subgraphSchema) +`, namespace, federatedGraphName, federatedGraphroutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, readme) } -func testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema string) string { +func testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema string, readme, subscriptionUrl, subscriptionProtocol, websocketSubprotocol *string) string { + var readmePart, subscriptionUrlPart, subscriptionProtocolPart, websocketSubprotocolPart string + if readme != nil { + readmePart = fmt.Sprintf(`readme = "%s"`, *readme) + } + + if subscriptionUrl != nil { + subscriptionUrlPart = fmt.Sprintf(`subscription_url = "%s"`, *subscriptionUrl) + } + + if subscriptionProtocol != nil { + subscriptionProtocolPart = fmt.Sprintf(`subscription_protocol = "%s"`, *subscriptionProtocol) + } + + if websocketSubprotocol != nil { + websocketSubprotocolPart = fmt.Sprintf(`websocket_subprotocol = "%s"`, *websocketSubprotocol) + } + return fmt.Sprintf(` resource "cosmo_namespace" "test" { name = "%s" @@ -199,6 +287,10 @@ resource "cosmo_subgraph" "test" { "team" = "backend", "stage" = "dev" } + %s + %s + %s + %s } -`, namespace, subgraphName, subgraphRoutingURL, subgraphSchema) +`, namespace, subgraphName, subgraphRoutingURL, subgraphSchema, readmePart, subscriptionUrlPart, subscriptionProtocolPart, websocketSubprotocolPart) } From 8f21677f7022fc4c80bb9aaf11df4fea6a9fe61a Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Wed, 4 Dec 2024 02:23:16 +0530 Subject: [PATCH 11/19] fix: improve readability of code --- internal/api/common.go | 4 +-- internal/api/monograph.go | 8 ++--- internal/api/subgraph.go | 31 +++---------------- .../subgraph/resource_cosmo_subgraph.go | 31 +++++++++++++++++-- 4 files changed, 39 insertions(+), 35 deletions(-) diff --git a/internal/api/common.go b/internal/api/common.go index 2efa0c0..7c1ab0f 100644 --- a/internal/api/common.go +++ b/internal/api/common.go @@ -10,7 +10,7 @@ const ( GraphQLWebsocketSubprotocolGraphQLTransportWS = "graphql-transport-ws" ) -func resolveWebsocketSubprotocol(protocol string) *common.GraphQLWebsocketSubprotocol { +func ResolveWebsocketSubprotocol(protocol string) *common.GraphQLWebsocketSubprotocol { switch protocol { case GraphQLWebsocketSubprotocolGraphQLWS: return common.GraphQLWebsocketSubprotocol_GRAPHQL_WEBSOCKET_SUBPROTOCOL_WS.Enum() @@ -28,7 +28,7 @@ const ( GraphQLSubscriptionProtocolSSEPost = "sse_post" ) -func resolveSubscriptionProtocol(protocol string) *common.GraphQLSubscriptionProtocol { +func ResolveSubscriptionProtocol(protocol string) *common.GraphQLSubscriptionProtocol { switch protocol { case GraphQLSubscriptionProtocolSSE: return common.GraphQLSubscriptionProtocol_GRAPHQL_SUBSCRIPTION_PROTOCOL_SSE.Enum() diff --git a/internal/api/monograph.go b/internal/api/monograph.go index cc970f6..0756e6a 100644 --- a/internal/api/monograph.go +++ b/internal/api/monograph.go @@ -16,8 +16,8 @@ func (p PlatformClient) CreateMonograph(ctx context.Context, name string, namesp GraphUrl: graphUrl, SubscriptionUrl: subscriptionUrl, Readme: readme, - WebsocketSubprotocol: resolveWebsocketSubprotocol(websocketSubprotocol), - SubscriptionProtocol: resolveSubscriptionProtocol(subscriptionProtocol), + WebsocketSubprotocol: ResolveWebsocketSubprotocol(websocketSubprotocol), + SubscriptionProtocol: ResolveSubscriptionProtocol(subscriptionProtocol), AdmissionWebhookURL: admissionWebhookUrl, AdmissionWebhookSecret: &admissionWebhookSecret, }) @@ -46,8 +46,8 @@ func (p PlatformClient) UpdateMonograph(ctx context.Context, name string, namesp GraphUrl: graphUrl, SubscriptionUrl: subscriptionUrl, Readme: readme, - WebsocketSubprotocol: resolveWebsocketSubprotocol(websocketSubprotocol), - SubscriptionProtocol: resolveSubscriptionProtocol(subscriptionProtocol), + WebsocketSubprotocol: ResolveWebsocketSubprotocol(websocketSubprotocol), + SubscriptionProtocol: ResolveSubscriptionProtocol(subscriptionProtocol), AdmissionWebhookURL: &admissionWebhookUrl, AdmissionWebhookSecret: &admissionWebhookSecret, }) diff --git a/internal/api/subgraph.go b/internal/api/subgraph.go index bd2bcb8..54454c0 100644 --- a/internal/api/subgraph.go +++ b/internal/api/subgraph.go @@ -8,20 +8,8 @@ import ( platformv1 "github.com/wundergraph/cosmo/connect-go/gen/proto/wg/cosmo/platform/v1" ) -func (p PlatformClient) CreateSubgraph(ctx context.Context, name string, namespace string, routingUrl string, baseSubgraphName *string, labels []*platformv1.Label, subscriptionUrl *string, readme *string, isEventDrivenGraph *bool, isFeatureSubgraph *bool, subscriptionProtocol string, websocketSubprotocol string) *ApiError { - request := connect.NewRequest(&platformv1.CreateFederatedSubgraphRequest{ - Name: name, - Namespace: namespace, - RoutingUrl: &routingUrl, - Labels: labels, - SubscriptionUrl: subscriptionUrl, - Readme: readme, - WebsocketSubprotocol: resolveWebsocketSubprotocol(websocketSubprotocol), - SubscriptionProtocol: resolveSubscriptionProtocol(subscriptionProtocol), - IsEventDrivenGraph: isEventDrivenGraph, - BaseSubgraphName: baseSubgraphName, - IsFeatureSubgraph: isFeatureSubgraph, - }) +func (p PlatformClient) CreateSubgraph(ctx context.Context, data *platformv1.CreateFederatedSubgraphRequest) *ApiError { + request := connect.NewRequest(data) response, err := p.Client.CreateFederatedSubgraph(ctx, request) if err != nil { return &ApiError{Err: err, Reason: "CreateSubgraph", Status: common.EnumStatusCode_ERR} @@ -39,19 +27,8 @@ func (p PlatformClient) CreateSubgraph(ctx context.Context, name string, namespa return nil } -func (p PlatformClient) UpdateSubgraph(ctx context.Context, name, namespace, routingUrl string, labels []*platformv1.Label, headers []string, subscriptionUrl, readme string, unsetLabels *bool, subscriptionProtocol string, websocketSubprotocol string) *ApiError { - request := connect.NewRequest(&platformv1.UpdateSubgraphRequest{ - Name: name, - RoutingUrl: &routingUrl, - Labels: labels, - Headers: headers, - SubscriptionUrl: &subscriptionUrl, - Readme: &readme, - Namespace: namespace, - UnsetLabels: unsetLabels, - WebsocketSubprotocol: resolveWebsocketSubprotocol(websocketSubprotocol), - SubscriptionProtocol: resolveSubscriptionProtocol(subscriptionProtocol), - }) +func (p PlatformClient) UpdateSubgraph(ctx context.Context, data *platformv1.UpdateSubgraphRequest) *ApiError { + request := connect.NewRequest(data) response, err := p.Client.UpdateSubgraph(ctx, request) if err != nil { diff --git a/internal/service/subgraph/resource_cosmo_subgraph.go b/internal/service/subgraph/resource_cosmo_subgraph.go index c912369..125dc57 100644 --- a/internal/service/subgraph/resource_cosmo_subgraph.go +++ b/internal/service/subgraph/resource_cosmo_subgraph.go @@ -363,9 +363,23 @@ func (r *SubgraphResource) Update(ctx context.Context, req resource.UpdateReques websocketSubprotocol = *data.WebsocketSubprotocol.ValueStringPointer() } + routingUrl := data.RoutingURL.ValueString() + requestData := &platformv1.UpdateSubgraphRequest{ + Name: data.Name.ValueString(), + RoutingUrl: &routingUrl, + Namespace: data.Namespace.ValueString(), + Labels: labels, + UnsetLabels: unsetLabels, + SubscriptionUrl: &subscriptionUrl, + SubscriptionProtocol: api.ResolveSubscriptionProtocol(subscriptionProtocol), + WebsocketSubprotocol: api.ResolveWebsocketSubprotocol(websocketSubprotocol), + Readme: &readme, + Headers: []string{}, + } + // TBD: This is only used in the update subgraph method and not used atm // headers := utils.ConvertHeadersToStringList(data.Headers) - apiErr := r.client.UpdateSubgraph(ctx, data.Name.ValueString(), data.Namespace.ValueString(), data.RoutingURL.ValueString(), labels, []string{}, subscriptionUrl, readme, unsetLabels, subscriptionProtocol, websocketSubprotocol) + apiErr := r.client.UpdateSubgraph(ctx, requestData) if apiErr != nil { if api.IsSubgraphCompositionFailedError(apiErr) { utils.AddDiagnosticWarning(resp, @@ -512,7 +526,20 @@ func (r *SubgraphResource) createAndPublishSubgraph(ctx context.Context, data Su } } - apiErr := r.client.CreateSubgraph(ctx, data.Name.ValueString(), data.Namespace.ValueString(), data.RoutingURL.ValueString(), nil, labels, data.SubscriptionUrl.ValueStringPointer(), data.Readme.ValueStringPointer(), data.IsEventDrivenGraph.ValueBoolPointer(), data.IsFeatureSubgraph.ValueBoolPointer(), data.SubscriptionProtocol.ValueString(), data.WebsocketSubprotocol.ValueString()) + routingUrl := data.RoutingURL.ValueString() + requestData := &platformv1.CreateFederatedSubgraphRequest{ + Name: data.Name.ValueString(), + Namespace: data.Namespace.ValueString(), + RoutingUrl: &routingUrl, + Labels: labels, + SubscriptionUrl: data.SubscriptionUrl.ValueStringPointer(), + Readme: data.Readme.ValueStringPointer(), + SubscriptionProtocol: api.ResolveSubscriptionProtocol(data.SubscriptionProtocol.ValueString()), + WebsocketSubprotocol: api.ResolveWebsocketSubprotocol(data.WebsocketSubprotocol.ValueString()), + IsEventDrivenGraph: data.IsEventDrivenGraph.ValueBoolPointer(), + } + + apiErr := r.client.CreateSubgraph(ctx, requestData) if apiErr != nil { utils.AddDiagnosticError(resp, ErrCreatingSubgraph, From 8d9603230ee27b7d279cf372855d263f51c01e46 Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Wed, 4 Dec 2024 02:33:28 +0530 Subject: [PATCH 12/19] fix: improve code readability --- internal/api/contract.go | 27 +++-------------- .../contract/resource_cosmo_contract.go | 29 +++++++++++++++++-- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/internal/api/contract.go b/internal/api/contract.go index 5b6599f..acd0e47 100644 --- a/internal/api/contract.go +++ b/internal/api/contract.go @@ -8,18 +8,8 @@ import ( platformv1 "github.com/wundergraph/cosmo/connect-go/gen/proto/wg/cosmo/platform/v1" ) -func (p *PlatformClient) CreateContract(ctx context.Context, name, namespace, sourceGraphName, routingUrl, admissionWebhookUrl, admissionWebhookSecret string, excludeTags []string, includeTags []string, readme string) (*platformv1.CreateContractResponse, *ApiError) { - request := connect.NewRequest(&platformv1.CreateContractRequest{ - Name: name, - Namespace: namespace, - SourceGraphName: sourceGraphName, - RoutingUrl: routingUrl, - AdmissionWebhookUrl: admissionWebhookUrl, - ExcludeTags: excludeTags, - Readme: &readme, - AdmissionWebhookSecret: &admissionWebhookSecret, - IncludeTags: includeTags, - }) +func (p *PlatformClient) CreateContract(ctx context.Context, data *platformv1.CreateContractRequest) (*platformv1.CreateContractResponse, *ApiError) { + request := connect.NewRequest(data) response, err := p.Client.CreateContract(ctx, request) if err != nil { @@ -38,17 +28,8 @@ func (p *PlatformClient) CreateContract(ctx context.Context, name, namespace, so return response.Msg, nil } -func (p *PlatformClient) UpdateContract(ctx context.Context, name, namespace string, excludeTags []string, includeTags []string, routingUrl, admissionWebhookUrl, admissionWebhookSecret, readme string) (*platformv1.UpdateContractResponse, *ApiError) { - request := connect.NewRequest(&platformv1.UpdateContractRequest{ - Name: name, - Namespace: namespace, - ExcludeTags: excludeTags, - IncludeTags: includeTags, - RoutingUrl: &routingUrl, - AdmissionWebhookUrl: &admissionWebhookUrl, - AdmissionWebhookSecret: &admissionWebhookSecret, - Readme: &readme, - }) +func (p *PlatformClient) UpdateContract(ctx context.Context, data *platformv1.UpdateContractRequest) (*platformv1.UpdateContractResponse, *ApiError) { + request := connect.NewRequest(data) response, err := p.Client.UpdateContract(ctx, request) if err != nil { diff --git a/internal/service/contract/resource_cosmo_contract.go b/internal/service/contract/resource_cosmo_contract.go index 09a755c..7f35080 100644 --- a/internal/service/contract/resource_cosmo_contract.go +++ b/internal/service/contract/resource_cosmo_contract.go @@ -278,7 +278,19 @@ func (r *contractResource) Update(ctx context.Context, req resource.UpdateReques readme = *data.Readme.ValueStringPointer() } - _, apiError := r.client.UpdateContract(ctx, data.Name.ValueString(), data.Namespace.ValueString(), excludeTags, includeTags, data.RoutingURL.ValueString(), admissionWebhookUrl, admissionWebhookSecret, readme) + routingUrl := data.RoutingURL.ValueString() + requestData := &platformv1.UpdateContractRequest{ + Name: data.Name.ValueString(), + Namespace: data.Namespace.ValueString(), + ExcludeTags: excludeTags, + IncludeTags: includeTags, + RoutingUrl: &routingUrl, + AdmissionWebhookUrl: &admissionWebhookUrl, + AdmissionWebhookSecret: &admissionWebhookSecret, + Readme: &readme, + } + + _, apiError := r.client.UpdateContract(ctx, requestData) if apiError != nil { if api.IsContractCompositionFailedError(apiError) || api.IsSubgraphCompositionFailedError(apiError) { utils.AddDiagnosticError(resp, @@ -399,7 +411,20 @@ func (r *contractResource) createAndFetchContract(ctx context.Context, data cont "includeTags": strings.Join(includeTags, ","), }) - _, apiError := r.client.CreateContract(ctx, data.Name.ValueString(), data.Namespace.ValueString(), data.SourceGraphName.ValueString(), data.RoutingURL.ValueString(), data.AdmissionWebhookUrl.ValueString(), data.AdmissionWebhookSecret.ValueString(), excludeTags, includeTags, data.Readme.ValueString()) + readme := data.Readme.ValueString() + requestData := &platformv1.CreateContractRequest{ + Name: data.Name.ValueString(), + Namespace: data.Namespace.ValueString(), + SourceGraphName: data.SourceGraphName.ValueString(), + RoutingUrl: data.RoutingURL.ValueString(), + AdmissionWebhookUrl: data.AdmissionWebhookUrl.ValueString(), + ExcludeTags: excludeTags, + Readme: &readme, + AdmissionWebhookSecret: data.AdmissionWebhookSecret.ValueStringPointer(), + IncludeTags: includeTags, + } + + _, apiError := r.client.CreateContract(ctx, requestData) if apiError != nil { if api.IsContractCompositionFailedError(apiError) || api.IsSubgraphCompositionFailedError(apiError) { utils.AddDiagnosticError(resp, From 1b14c4b0e90b4dfd1026fb693d73f72f47e882e2 Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Wed, 4 Dec 2024 02:43:32 +0530 Subject: [PATCH 13/19] fix: ci --- .../contract/resource_cosmo_contract_test.go | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/internal/service/contract/resource_cosmo_contract_test.go b/internal/service/contract/resource_cosmo_contract_test.go index 1de28b3..b5835d6 100644 --- a/internal/service/contract/resource_cosmo_contract_test.go +++ b/internal/service/contract/resource_cosmo_contract_test.go @@ -16,7 +16,6 @@ func TestAccContractResource(t *testing.T) { readme := "Initial readme content" federatedGraphName := acctest.RandomWithPrefix("test-federated-graph") - federatedGraphRoutingURL := "https://example.com:3000" subgraphName := acctest.RandomWithPrefix("test-subgraph") subgraphRoutingURL := "https://subgraph-standalone-example.com" @@ -27,16 +26,17 @@ func TestAccContractResource(t *testing.T) { ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, "internal", &readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, name, "internal", &readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), resource.TestCheckResourceAttr("cosmo_contract.test", "readme", readme), + resource.TestCheckResourceAttr("cosmo_contract.test", "readme", readme), resource.TestCheckResourceAttr("cosmo_contract.test", "exclude_tags.0", "internal"), ), }, { - Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, "external", &readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, name, "external", &readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), @@ -49,11 +49,11 @@ func TestAccContractResource(t *testing.T) { RefreshState: true, }, { - Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, "external", &readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, name, "external", &readme), Destroy: true, }, { - Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphRoutingURL, subgraphSchema, name, readme), + Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, subgraphRoutingURL, subgraphSchema, name, readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test_mono", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test_mono", "namespace", namespace), @@ -61,7 +61,7 @@ func TestAccContractResource(t *testing.T) { ), }, { - Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphRoutingURL, subgraphSchema, name, readme), + Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, subgraphRoutingURL, subgraphSchema, name, readme), Destroy: true, }, }, @@ -73,7 +73,6 @@ func TestOptionalValuesOfContractResource(t *testing.T) { namespace := acctest.RandomWithPrefix("test-namespace") federatedGraphName := acctest.RandomWithPrefix("test-federated-graph") - federatedGraphRoutingURL := "https://example.com:3000" subgraphName := acctest.RandomWithPrefix("test-subgraph") subgraphRoutingURL := "https://subgraph-standalone-example.com" @@ -86,7 +85,7 @@ func TestOptionalValuesOfContractResource(t *testing.T) { ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, "internal", &readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, name, "internal", &readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), @@ -95,7 +94,7 @@ func TestOptionalValuesOfContractResource(t *testing.T) { ), }, { - Config: testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, name, "external", nil), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, name, "external", nil), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), @@ -107,7 +106,7 @@ func TestOptionalValuesOfContractResource(t *testing.T) { }) } -func testAccContractResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractExcludeTag string, contractReadme *string) string { +func testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractExcludeTag string, contractReadme *string) string { var readmePart string if contractReadme != nil { readmePart = fmt.Sprintf(`readme = "%s"`, *contractReadme) @@ -121,7 +120,7 @@ resource "cosmo_namespace" "test" { resource "cosmo_federated_graph" "test" { name = "%s" namespace = cosmo_namespace.test.name - routing_url = "%s" + routing_url = "https://example.com:3000" depends_on = [cosmo_subgraph.test] } @@ -143,10 +142,10 @@ resource "cosmo_contract" "test" { exclude_tags = ["%s"] %s } -`, namespace, federatedGraphName, federatedGraphRoutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractExcludeTag, readmePart) +`, namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractExcludeTag, readmePart) } -func testAccContractOfMonographResourceConfig(namespace, federatedGraphName, federatedGraphRoutingURL, graphUrl, schema, contractName, contractReadme string) string { +func testAccContractOfMonographResourceConfig(namespace, federatedGraphName, graphUrl, schema, contractName, contractReadme string) string { return fmt.Sprintf(` resource "cosmo_namespace" "test_mono" { name = "%s" @@ -155,7 +154,7 @@ resource "cosmo_namespace" "test_mono" { resource "cosmo_monograph" "test_mono" { name = "%s" namespace = cosmo_namespace.test_mono.name - routing_url = "%s" + routing_url = "https://example.com:3000" graph_url = "%s" schema = <<-EOT %s @@ -169,5 +168,5 @@ resource "cosmo_contract" "test_mono" { routing_url = "http://localhost:3003" readme = "%s" } -`, namespace, federatedGraphName, federatedGraphRoutingURL, graphUrl, schema, contractName, contractReadme) +`, namespace, federatedGraphName, graphUrl, schema, contractName, contractReadme) } From 761b12a4d10bfe43253af2b901a441097e0d9256 Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Wed, 4 Dec 2024 02:46:27 +0530 Subject: [PATCH 14/19] fix: ci --- .../contract/resource_cosmo_contract_test.go | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/internal/service/contract/resource_cosmo_contract_test.go b/internal/service/contract/resource_cosmo_contract_test.go index b5835d6..ff039c8 100644 --- a/internal/service/contract/resource_cosmo_contract_test.go +++ b/internal/service/contract/resource_cosmo_contract_test.go @@ -18,7 +18,6 @@ func TestAccContractResource(t *testing.T) { federatedGraphName := acctest.RandomWithPrefix("test-federated-graph") subgraphName := acctest.RandomWithPrefix("test-subgraph") - subgraphRoutingURL := "https://subgraph-standalone-example.com" subgraphSchema := acceptance.TestAccValidSubgraphSchema resource.Test(t, resource.TestCase{ @@ -26,7 +25,7 @@ func TestAccContractResource(t *testing.T) { ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, name, "internal", &readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphSchema, name, "internal", &readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), @@ -36,7 +35,7 @@ func TestAccContractResource(t *testing.T) { ), }, { - Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, name, "external", &readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphSchema, name, "external", &readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), @@ -49,11 +48,11 @@ func TestAccContractResource(t *testing.T) { RefreshState: true, }, { - Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, name, "external", &readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphSchema, name, "external", &readme), Destroy: true, }, { - Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, subgraphRoutingURL, subgraphSchema, name, readme), + Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, subgraphSchema, name, readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test_mono", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test_mono", "namespace", namespace), @@ -61,7 +60,7 @@ func TestAccContractResource(t *testing.T) { ), }, { - Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, subgraphRoutingURL, subgraphSchema, name, readme), + Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, subgraphSchema, name, readme), Destroy: true, }, }, @@ -75,7 +74,6 @@ func TestOptionalValuesOfContractResource(t *testing.T) { federatedGraphName := acctest.RandomWithPrefix("test-federated-graph") subgraphName := acctest.RandomWithPrefix("test-subgraph") - subgraphRoutingURL := "https://subgraph-standalone-example.com" subgraphSchema := acceptance.TestAccValidSubgraphSchema readme := "Initial readme content" @@ -85,7 +83,7 @@ func TestOptionalValuesOfContractResource(t *testing.T) { ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, name, "internal", &readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphSchema, name, "internal", &readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), @@ -94,7 +92,7 @@ func TestOptionalValuesOfContractResource(t *testing.T) { ), }, { - Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, name, "external", nil), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphSchema, name, "external", nil), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), @@ -106,7 +104,7 @@ func TestOptionalValuesOfContractResource(t *testing.T) { }) } -func testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractExcludeTag string, contractReadme *string) string { +func testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphSchema, contractName, contractExcludeTag string, contractReadme *string) string { var readmePart string if contractReadme != nil { readmePart = fmt.Sprintf(`readme = "%s"`, *contractReadme) @@ -127,7 +125,7 @@ resource "cosmo_federated_graph" "test" { resource "cosmo_subgraph" "test" { name = "%s" namespace = cosmo_namespace.test.name - routing_url = "%s" + routing_url = "https://subgraph-standalone-example.com" schema = <<-EOT %s EOT @@ -142,10 +140,10 @@ resource "cosmo_contract" "test" { exclude_tags = ["%s"] %s } -`, namespace, federatedGraphName, subgraphName, subgraphRoutingURL, subgraphSchema, contractName, contractExcludeTag, readmePart) +`, namespace, federatedGraphName, subgraphName, subgraphSchema, contractName, contractExcludeTag, readmePart) } -func testAccContractOfMonographResourceConfig(namespace, federatedGraphName, graphUrl, schema, contractName, contractReadme string) string { +func testAccContractOfMonographResourceConfig(namespace, federatedGraphName, schema, contractName, contractReadme string) string { return fmt.Sprintf(` resource "cosmo_namespace" "test_mono" { name = "%s" @@ -155,7 +153,7 @@ resource "cosmo_monograph" "test_mono" { name = "%s" namespace = cosmo_namespace.test_mono.name routing_url = "https://example.com:3000" - graph_url = "%s" + graph_url = "https://subgraph-standalone-example.com" schema = <<-EOT %s EOT @@ -168,5 +166,5 @@ resource "cosmo_contract" "test_mono" { routing_url = "http://localhost:3003" readme = "%s" } -`, namespace, federatedGraphName, graphUrl, schema, contractName, contractReadme) +`, namespace, federatedGraphName, schema, contractName, contractReadme) } From 217abd0e145912d16b2c097010d7d14f1d0d7fd7 Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Wed, 4 Dec 2024 02:51:16 +0530 Subject: [PATCH 15/19] fix: ci --- .github/workflows/test.yml | 2 ++ go.sum | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 826641a..d8eb5e2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,6 +8,8 @@ on: paths-ignore: - "README.md" push: + branches: + - main paths-ignore: - "README.md" diff --git a/go.sum b/go.sum index a9b5b47..9df6555 100644 --- a/go.sum +++ b/go.sum @@ -196,10 +196,6 @@ github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IU github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/wundergraph/cosmo/connect-go v0.0.0-20241104193239-b78c5917d64b h1:N6CQBlWN7B8cOIVPNxZxkmgOUrSeaZebdhmdGxmg3/8= -github.com/wundergraph/cosmo/connect-go v0.0.0-20241104193239-b78c5917d64b/go.mod h1:RLepGeaXdENMlePq4geGzaDV895QuJZ+mUFLzG5ra9E= -github.com/wundergraph/cosmo/connect-go v0.0.0-20241127080034-0681d60a5f89 h1:JnLcb7QijyHR8LoulHw+jiBqM5Z9RNU7/7co3MTgxTY= -github.com/wundergraph/cosmo/connect-go v0.0.0-20241127080034-0681d60a5f89/go.mod h1:RLepGeaXdENMlePq4geGzaDV895QuJZ+mUFLzG5ra9E= github.com/wundergraph/cosmo/connect-go v0.0.0-20241203152720-979e5a780c8e h1:XFEGOGnBWR6cfW3gV+24An3lNoesWOxTH71D09Tuph4= github.com/wundergraph/cosmo/connect-go v0.0.0-20241203152720-979e5a780c8e/go.mod h1:RLepGeaXdENMlePq4geGzaDV895QuJZ+mUFLzG5ra9E= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= From dacc658cdd9e56869b231407ada2b139b9625bd2 Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Wed, 4 Dec 2024 02:54:09 +0530 Subject: [PATCH 16/19] fix: ci --- .../contract/resource_cosmo_contract_test.go | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/internal/service/contract/resource_cosmo_contract_test.go b/internal/service/contract/resource_cosmo_contract_test.go index ff039c8..4c20a33 100644 --- a/internal/service/contract/resource_cosmo_contract_test.go +++ b/internal/service/contract/resource_cosmo_contract_test.go @@ -18,14 +18,13 @@ func TestAccContractResource(t *testing.T) { federatedGraphName := acctest.RandomWithPrefix("test-federated-graph") subgraphName := acctest.RandomWithPrefix("test-subgraph") - subgraphSchema := acceptance.TestAccValidSubgraphSchema resource.Test(t, resource.TestCase{ PreCheck: func() { acceptance.TestAccPreCheck(t) }, ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphSchema, name, "internal", &readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, name, "internal", &readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), @@ -35,7 +34,7 @@ func TestAccContractResource(t *testing.T) { ), }, { - Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphSchema, name, "external", &readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, name, "external", &readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), @@ -48,11 +47,11 @@ func TestAccContractResource(t *testing.T) { RefreshState: true, }, { - Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphSchema, name, "external", &readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, name, "external", &readme), Destroy: true, }, { - Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, subgraphSchema, name, readme), + Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, name, readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test_mono", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test_mono", "namespace", namespace), @@ -60,7 +59,7 @@ func TestAccContractResource(t *testing.T) { ), }, { - Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, subgraphSchema, name, readme), + Config: testAccContractOfMonographResourceConfig(namespace, federatedGraphName, name, readme), Destroy: true, }, }, @@ -74,7 +73,6 @@ func TestOptionalValuesOfContractResource(t *testing.T) { federatedGraphName := acctest.RandomWithPrefix("test-federated-graph") subgraphName := acctest.RandomWithPrefix("test-subgraph") - subgraphSchema := acceptance.TestAccValidSubgraphSchema readme := "Initial readme content" @@ -83,7 +81,7 @@ func TestOptionalValuesOfContractResource(t *testing.T) { ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphSchema, name, "internal", &readme), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, name, "internal", &readme), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), @@ -92,7 +90,7 @@ func TestOptionalValuesOfContractResource(t *testing.T) { ), }, { - Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphSchema, name, "external", nil), + Config: testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, name, "external", nil), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_contract.test", "name", name), resource.TestCheckResourceAttr("cosmo_contract.test", "namespace", namespace), @@ -104,11 +102,12 @@ func TestOptionalValuesOfContractResource(t *testing.T) { }) } -func testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, subgraphSchema, contractName, contractExcludeTag string, contractReadme *string) string { +func testAccContractResourceConfig(namespace, federatedGraphName, subgraphName, contractName, contractExcludeTag string, contractReadme *string) string { var readmePart string if contractReadme != nil { readmePart = fmt.Sprintf(`readme = "%s"`, *contractReadme) } + subgraphSchema := acceptance.TestAccValidSubgraphSchema return fmt.Sprintf(` resource "cosmo_namespace" "test" { @@ -143,7 +142,8 @@ resource "cosmo_contract" "test" { `, namespace, federatedGraphName, subgraphName, subgraphSchema, contractName, contractExcludeTag, readmePart) } -func testAccContractOfMonographResourceConfig(namespace, federatedGraphName, schema, contractName, contractReadme string) string { +func testAccContractOfMonographResourceConfig(namespace, federatedGraphName, contractName, contractReadme string) string { + schema := acceptance.TestAccValidSubgraphSchema return fmt.Sprintf(` resource "cosmo_namespace" "test_mono" { name = "%s" From 48361d690a15e0505a97fdfde3f1c3ac2f9dbea9 Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Wed, 4 Dec 2024 14:18:01 +0530 Subject: [PATCH 17/19] fix: handle optional labels --- .../subgraph/resource_cosmo_subgraph.go | 18 +++++-- .../subgraph/resource_cosmo_subgraph_test.go | 51 +++++++++++++++---- 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/internal/service/subgraph/resource_cosmo_subgraph.go b/internal/service/subgraph/resource_cosmo_subgraph.go index 125dc57..daee813 100644 --- a/internal/service/subgraph/resource_cosmo_subgraph.go +++ b/internal/service/subgraph/resource_cosmo_subgraph.go @@ -207,7 +207,9 @@ func (r *SubgraphResource) Create(ctx context.Context, req resource.CreateReques } } mapValue, _ := types.MapValueFrom(ctx, types.StringType, labels) - data.Labels = mapValue + if len(labels) != 0 { + data.Labels = mapValue + } if subgraph.GetSubscriptionUrl() != "" { data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) @@ -301,7 +303,11 @@ func (r *SubgraphResource) Read(ctx context.Context, req resource.ReadRequest, r data.SubscriptionProtocol = types.StringValue(subgraph.GetSubscriptionProtocol()) data.WebsocketSubprotocol = types.StringValue(subgraph.GetWebsocketSubprotocol()) data.IsEventDrivenGraph = types.BoolValue(subgraph.GetIsEventDrivenGraph()) - data.Labels = mapValue + if len(labels) != 0 { + data.Labels = mapValue + } else { + data.Labels = types.MapNull(types.StringType) + } if subgraph.GetSubscriptionUrl() != "" { data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) @@ -339,7 +345,7 @@ func (r *SubgraphResource) Update(ctx context.Context, req resource.UpdateReques } var unsetLabels *bool - if data.UnsetLabels.ValueBool() { + if len(labels) == 0 || data.UnsetLabels.ValueBool() { unsetLabels = &[]bool{true}[0] } @@ -459,7 +465,11 @@ func (r *SubgraphResource) Update(ctx context.Context, req resource.UpdateReques data.SubscriptionProtocol = types.StringValue(subgraph.GetSubscriptionProtocol()) data.WebsocketSubprotocol = types.StringValue(subgraph.GetWebsocketSubprotocol()) data.IsEventDrivenGraph = types.BoolValue(subgraph.GetIsEventDrivenGraph()) - data.Labels = mapValue + if len(responseLabels) != 0 { + data.Labels = mapValue + } else { + data.Labels = types.MapNull(types.StringType) + } if subgraph.GetSubscriptionUrl() != "" { data.SubscriptionUrl = types.StringValue(subgraph.GetSubscriptionUrl()) diff --git a/internal/service/subgraph/resource_cosmo_subgraph_test.go b/internal/service/subgraph/resource_cosmo_subgraph_test.go index 3d26ba6..7c52e1d 100644 --- a/internal/service/subgraph/resource_cosmo_subgraph_test.go +++ b/internal/service/subgraph/resource_cosmo_subgraph_test.go @@ -101,7 +101,7 @@ func TestAccStandaloneSubgraphResource(t *testing.T) { ), }, { - Config: testStandaloneSubgraph(namespace, subgraphName, routingURL, subgraphSchema, nil, nil, nil, nil), + Config: testStandaloneSubgraph(namespace, subgraphName, routingURL, subgraphSchema, nil, nil, nil, nil, false), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_subgraph.test", "name", subgraphName), resource.TestCheckResourceAttr("cosmo_subgraph.test", "namespace", namespace), @@ -115,7 +115,7 @@ func TestAccStandaloneSubgraphResource(t *testing.T) { RefreshState: true, }, { - Config: testStandaloneSubgraph(namespace, subgraphName, routingURL, subgraphSchema, nil, nil, nil, nil), + Config: testStandaloneSubgraph(namespace, subgraphName, routingURL, subgraphSchema, nil, nil, nil, nil, false), Destroy: true, }, }, @@ -157,7 +157,7 @@ func TestAccStandaloneSubgraphResourcePublishSchema(t *testing.T) { ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, nil, nil, nil, nil), + Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, nil, nil, nil, nil, false), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_subgraph.test", "name", subgraphName), resource.TestCheckResourceAttr("cosmo_subgraph.test", "namespace", namespace), @@ -167,7 +167,7 @@ func TestAccStandaloneSubgraphResourcePublishSchema(t *testing.T) { ), }, { - Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, updatedSubgraphSchema, nil, nil, nil, nil), + Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, updatedSubgraphSchema, nil, nil, nil, nil, false), ExpectError: regexp.MustCompile(`.*ERR_INVALID_SUBGRAPH_SCHEMA*`), }, }, @@ -191,7 +191,7 @@ func TestOptionalValuesOfSubgraphResource(t *testing.T) { ProtoV6ProviderFactories: acceptance.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, &readme, &subgraphSubscriptionURL, &subscriptionProtocol, &websocketSubprotocol), + Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, &readme, &subgraphSubscriptionURL, &subscriptionProtocol, &websocketSubprotocol, true), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_subgraph.test", "name", subgraphName), resource.TestCheckResourceAttr("cosmo_subgraph.test", "namespace", namespace), @@ -200,20 +200,32 @@ func TestOptionalValuesOfSubgraphResource(t *testing.T) { resource.TestCheckResourceAttr("cosmo_subgraph.test", "subscription_url", subgraphSubscriptionURL), resource.TestCheckResourceAttr("cosmo_subgraph.test", "subscription_protocol", subscriptionProtocol), resource.TestCheckResourceAttr("cosmo_subgraph.test", "websocket_subprotocol", websocketSubprotocol), - resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.team", "backend"), - resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.stage", "dev"), + resource.TestCheckNoResourceAttr("cosmo_subgraph.test", "labels"), ), }, { - Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, nil, nil, nil, nil), + Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, &readme, &subgraphSubscriptionURL, &subscriptionProtocol, &websocketSubprotocol, false), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("cosmo_subgraph.test", "name", subgraphName), resource.TestCheckResourceAttr("cosmo_subgraph.test", "namespace", namespace), resource.TestCheckResourceAttr("cosmo_subgraph.test", "routing_url", subgraphRoutingURL), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "readme", readme), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "subscription_url", subgraphSubscriptionURL), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "subscription_protocol", subscriptionProtocol), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "websocket_subprotocol", websocketSubprotocol), resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.team", "backend"), resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.stage", "dev"), + ), + }, + { + Config: testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema, nil, nil, nil, nil, true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("cosmo_subgraph.test", "name", subgraphName), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "namespace", namespace), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "routing_url", subgraphRoutingURL), resource.TestCheckNoResourceAttr("cosmo_subgraph.test", "readme"), resource.TestCheckNoResourceAttr("cosmo_subgraph.test", "subscription_url"), + resource.TestCheckNoResourceAttr("cosmo_subgraph.test", "labels"), resource.TestCheckResourceAttr("cosmo_subgraph.test", "subscription_protocol", api.GraphQLSubscriptionProtocolWS), resource.TestCheckResourceAttr("cosmo_subgraph.test", "websocket_subprotocol", api.GraphQLWebsocketSubprotocolDefault), ), @@ -253,7 +265,7 @@ resource "cosmo_subgraph" "test" { `, namespace, federatedGraphName, federatedGraphroutingURL, subgraphName, subgraphRoutingURL, subgraphSchema, readme) } -func testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema string, readme, subscriptionUrl, subscriptionProtocol, websocketSubprotocol *string) string { +func testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgraphSchema string, readme, subscriptionUrl, subscriptionProtocol, websocketSubprotocol *string, unsetLabels bool) string { var readmePart, subscriptionUrlPart, subscriptionProtocolPart, websocketSubprotocolPart string if readme != nil { readmePart = fmt.Sprintf(`readme = "%s"`, *readme) @@ -271,6 +283,27 @@ func testStandaloneSubgraph(namespace, subgraphName, subgraphRoutingURL, subgrap websocketSubprotocolPart = fmt.Sprintf(`websocket_subprotocol = "%s"`, *websocketSubprotocol) } + if unsetLabels { + return fmt.Sprintf(` +resource "cosmo_namespace" "test" { + name = "%s" +} + +resource "cosmo_subgraph" "test" { + name = "%s" + namespace = cosmo_namespace.test.name + routing_url = "%s" + schema = <<-EOT + %s + EOT + %s + %s + %s + %s +} +`, namespace, subgraphName, subgraphRoutingURL, subgraphSchema, readmePart, subscriptionUrlPart, subscriptionProtocolPart, websocketSubprotocolPart) + } + return fmt.Sprintf(` resource "cosmo_namespace" "test" { name = "%s" From 906e4e788ac8cbd0a2b48932732d8d0897c4ca7d Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Thu, 5 Dec 2024 00:49:13 +0530 Subject: [PATCH 18/19] fix: tests --- internal/service/subgraph/resource_cosmo_subgraph.go | 7 +++++-- internal/service/subgraph/resource_cosmo_subgraph_test.go | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/service/subgraph/resource_cosmo_subgraph.go b/internal/service/subgraph/resource_cosmo_subgraph.go index daee813..1aa05b4 100644 --- a/internal/service/subgraph/resource_cosmo_subgraph.go +++ b/internal/service/subgraph/resource_cosmo_subgraph.go @@ -150,6 +150,7 @@ For more information on subgraphs, please refer to the [Cosmo Documentation](htt Optional: true, MarkdownDescription: "Labels for the subgraph.", ElementType: types.StringType, + Computed: true, }, "schema": schema.StringAttribute{ Optional: true, @@ -209,6 +210,8 @@ func (r *SubgraphResource) Create(ctx context.Context, req resource.CreateReques mapValue, _ := types.MapValueFrom(ctx, types.StringType, labels) if len(labels) != 0 { data.Labels = mapValue + } else { + data.Labels = types.MapValueMust(types.StringType, map[string]attr.Value{}) } if subgraph.GetSubscriptionUrl() != "" { @@ -306,7 +309,7 @@ func (r *SubgraphResource) Read(ctx context.Context, req resource.ReadRequest, r if len(labels) != 0 { data.Labels = mapValue } else { - data.Labels = types.MapNull(types.StringType) + data.Labels = types.MapValueMust(types.StringType, map[string]attr.Value{}) } if subgraph.GetSubscriptionUrl() != "" { @@ -468,7 +471,7 @@ func (r *SubgraphResource) Update(ctx context.Context, req resource.UpdateReques if len(responseLabels) != 0 { data.Labels = mapValue } else { - data.Labels = types.MapNull(types.StringType) + data.Labels = types.MapValueMust(types.StringType, map[string]attr.Value{}) } if subgraph.GetSubscriptionUrl() != "" { diff --git a/internal/service/subgraph/resource_cosmo_subgraph_test.go b/internal/service/subgraph/resource_cosmo_subgraph_test.go index 7c52e1d..7171d6f 100644 --- a/internal/service/subgraph/resource_cosmo_subgraph_test.go +++ b/internal/service/subgraph/resource_cosmo_subgraph_test.go @@ -200,7 +200,8 @@ func TestOptionalValuesOfSubgraphResource(t *testing.T) { resource.TestCheckResourceAttr("cosmo_subgraph.test", "subscription_url", subgraphSubscriptionURL), resource.TestCheckResourceAttr("cosmo_subgraph.test", "subscription_protocol", subscriptionProtocol), resource.TestCheckResourceAttr("cosmo_subgraph.test", "websocket_subprotocol", websocketSubprotocol), - resource.TestCheckNoResourceAttr("cosmo_subgraph.test", "labels"), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "websocket_subprotocol", websocketSubprotocol), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.%", "0"), ), }, { @@ -225,7 +226,7 @@ func TestOptionalValuesOfSubgraphResource(t *testing.T) { resource.TestCheckResourceAttr("cosmo_subgraph.test", "routing_url", subgraphRoutingURL), resource.TestCheckNoResourceAttr("cosmo_subgraph.test", "readme"), resource.TestCheckNoResourceAttr("cosmo_subgraph.test", "subscription_url"), - resource.TestCheckNoResourceAttr("cosmo_subgraph.test", "labels"), + resource.TestCheckResourceAttr("cosmo_subgraph.test", "labels.%", "0"), resource.TestCheckResourceAttr("cosmo_subgraph.test", "subscription_protocol", api.GraphQLSubscriptionProtocolWS), resource.TestCheckResourceAttr("cosmo_subgraph.test", "websocket_subprotocol", api.GraphQLWebsocketSubprotocolDefault), ), From 7246b388e0674489d22142f9b984cb8e4e20d19a Mon Sep 17 00:00:00 2001 From: JivusAyrus Date: Fri, 6 Dec 2024 02:39:33 +0530 Subject: [PATCH 19/19] fix: pr suggestions --- .../contract/resource_cosmo_contract.go | 17 +++----------- .../resource_cosmo_federated_graph.go | 17 +++----------- .../subgraph/resource_cosmo_subgraph.go | 23 ++++--------------- internal/utils/helpers.go | 7 ++++++ 4 files changed, 17 insertions(+), 47 deletions(-) diff --git a/internal/service/contract/resource_cosmo_contract.go b/internal/service/contract/resource_cosmo_contract.go index 7f35080..af1e83c 100644 --- a/internal/service/contract/resource_cosmo_contract.go +++ b/internal/service/contract/resource_cosmo_contract.go @@ -263,20 +263,9 @@ func (r *contractResource) Update(ctx context.Context, req resource.UpdateReques return } - admissionWebhookUrl := "" - if data.AdmissionWebhookUrl.ValueStringPointer() != nil { - admissionWebhookUrl = *data.AdmissionWebhookUrl.ValueStringPointer() - } - - admissionWebhookSecret := "" - if data.AdmissionWebhookSecret.ValueStringPointer() != nil { - admissionWebhookSecret = *data.AdmissionWebhookSecret.ValueStringPointer() - } - - readme := "" - if data.Readme.ValueStringPointer() != nil { - readme = *data.Readme.ValueStringPointer() - } + readme := utils.GetValueOrDefault(data.Readme.ValueStringPointer(), "") + admissionWebhookUrl := utils.GetValueOrDefault(data.AdmissionWebhookUrl.ValueStringPointer(), "") + admissionWebhookSecret := utils.GetValueOrDefault(data.AdmissionWebhookSecret.ValueStringPointer(), "") routingUrl := data.RoutingURL.ValueString() requestData := &platformv1.UpdateContractRequest{ diff --git a/internal/service/federated-graph/resource_cosmo_federated_graph.go b/internal/service/federated-graph/resource_cosmo_federated_graph.go index 0fbf1cf..0643054 100644 --- a/internal/service/federated-graph/resource_cosmo_federated_graph.go +++ b/internal/service/federated-graph/resource_cosmo_federated_graph.go @@ -237,20 +237,9 @@ func (r *FederatedGraphResource) Update(ctx context.Context, req resource.Update return } - readme := "" - if data.Readme.ValueStringPointer() != nil { - readme = *data.Readme.ValueStringPointer() - } - - admissionWebhookUrl := "" - if data.AdmissionWebhookUrl.ValueStringPointer() != nil { - admissionWebhookUrl = *data.AdmissionWebhookUrl.ValueStringPointer() - } - - admissionWebhookSecret := "" - if !data.AdmissionWebhookSecret.IsNull() { - admissionWebhookSecret = *data.AdmissionWebhookSecret.ValueStringPointer() - } + readme := utils.GetValueOrDefault(data.Readme.ValueStringPointer(), "") + admissionWebhookUrl := utils.GetValueOrDefault(data.AdmissionWebhookUrl.ValueStringPointer(), "") + admissionWebhookSecret := utils.GetValueOrDefault(data.AdmissionWebhookSecret.ValueStringPointer(), "") updatedGraph := platformv1.FederatedGraph{ Name: data.Name.ValueString(), diff --git a/internal/service/subgraph/resource_cosmo_subgraph.go b/internal/service/subgraph/resource_cosmo_subgraph.go index 1aa05b4..61e80ea 100644 --- a/internal/service/subgraph/resource_cosmo_subgraph.go +++ b/internal/service/subgraph/resource_cosmo_subgraph.go @@ -352,25 +352,10 @@ func (r *SubgraphResource) Update(ctx context.Context, req resource.UpdateReques unsetLabels = &[]bool{true}[0] } - readme := "" - if data.Readme.ValueStringPointer() != nil { - readme = *data.Readme.ValueStringPointer() - } - - subscriptionUrl := "" - if data.SubscriptionUrl.ValueStringPointer() != nil { - subscriptionUrl = *data.SubscriptionUrl.ValueStringPointer() - } - - subscriptionProtocol := api.GraphQLSubscriptionProtocolWS - if data.SubscriptionProtocol.ValueStringPointer() != nil { - subscriptionProtocol = *data.SubscriptionProtocol.ValueStringPointer() - } - - websocketSubprotocol := api.GraphQLWebsocketSubprotocolDefault - if data.WebsocketSubprotocol.ValueStringPointer() != nil { - websocketSubprotocol = *data.WebsocketSubprotocol.ValueStringPointer() - } + readme := utils.GetValueOrDefault(data.Readme.ValueStringPointer(), "") + subscriptionUrl := utils.GetValueOrDefault(data.SubscriptionUrl.ValueStringPointer(), "") + subscriptionProtocol := utils.GetValueOrDefault(data.SubscriptionProtocol.ValueStringPointer(), api.GraphQLSubscriptionProtocolWS) + websocketSubprotocol := utils.GetValueOrDefault(data.WebsocketSubprotocol.ValueStringPointer(), api.GraphQLWebsocketSubprotocolDefault) routingUrl := data.RoutingURL.ValueString() requestData := &platformv1.UpdateSubgraphRequest{ diff --git a/internal/utils/helpers.go b/internal/utils/helpers.go index 9450270..e6aa740 100644 --- a/internal/utils/helpers.go +++ b/internal/utils/helpers.go @@ -21,3 +21,10 @@ func ConvertHeadersToStringList(headersList types.List) []string { } return headers } + +func GetValueOrDefault[T any](value *T, defaultValue T) T { + if value == nil { + return defaultValue + } + return *value +}