From fdcf66c8ed14ec4394d8889c1b820caa89648fe8 Mon Sep 17 00:00:00 2001
From: Isaac Calligeros <101079287+IsaacCalligeros95@users.noreply.github.com>
Date: Wed, 7 Aug 2024 14:34:53 +0930
Subject: [PATCH 1/3] Chore!: Migrate docker container registry (#702)
* Migrate docker container registry
* Tidy up
* Rename APIVersion
* Fix descriptions
---
docs/data-sources/feeds.md | 35 ++--
docs/data-sources/library_variable_sets.md | 4 +-
docs/resources/artifactory_generic_feed.md | 4 +-
.../aws_elastic_container_registry.md | 6 +-
docs/resources/docker_container_registry.md | 6 +-
docs/resources/github_repository_feed.md | 4 +-
docs/resources/helm_feed.md | 8 +-
docs/resources/library_variable_set.md | 4 +-
docs/resources/maven_feed.md | 4 +-
docs/resources/nuget_feed.md | 6 +-
octopusdeploy/provider.go | 1 -
.../resource_docker_container_registry.go | 104 ----------
.../schema_docker_container_registry.go | 104 ----------
octopusdeploy_framework/framework_provider.go | 3 +-
.../resource_artifactory_generic_feed.go | 3 +-
...resource_aws_elastic_container_registry.go | 3 +-
.../resource_docker_container_registry.go | 183 ++++++++++++++++++
...resource_docker_container_registry_test.go | 11 +-
.../resource_github_repository_feed.go | 3 +-
octopusdeploy_framework/resource_helm_feed.go | 3 +-
.../resource_maven_feed.go | 3 +-
.../resource_nuget_feed.go | 3 +-
.../schemas/docker_container_registry_feed.go | 39 ++++
.../schemas/library_variable_set.go | 4 +-
24 files changed, 286 insertions(+), 262 deletions(-)
delete mode 100644 octopusdeploy/resource_docker_container_registry.go
delete mode 100644 octopusdeploy/schema_docker_container_registry.go
create mode 100644 octopusdeploy_framework/resource_docker_container_registry.go
rename {octopusdeploy => octopusdeploy_framework}/resource_docker_container_registry_test.go (94%)
create mode 100644 octopusdeploy_framework/schemas/docker_container_registry_feed.go
diff --git a/docs/data-sources/feeds.md b/docs/data-sources/feeds.md
index 623ec5593..91fde3c96 100644
--- a/docs/data-sources/feeds.md
+++ b/docs/data-sources/feeds.md
@@ -27,37 +27,40 @@ data "octopusdeploy_feeds" "example" {
### Optional
- `feed_type` (String) A filter to search by feed type. Valid feed types are `AwsElasticContainerRegistry`, `BuiltIn`, `Docker`, `GitHub`, `Helm`, `Maven`, `NuGet`, or `OctopusProject`.
+- `feeds` (Block List) (see [below for nested schema](#nestedblock--feeds))
+- `id` (String) The unique ID for this resource.
- `ids` (List of String) A filter to search by a list of IDs.
-- `name` (String) A filter to search by name.
-- `partial_name` (String) A filter to search by the partial match of a name.
+- `name` (String) The name of this resource.
+- `partial_name` (String) A filter to search by a partial name.
- `skip` (Number) A filter to specify the number of items to skip in the response.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this feeds.
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
-### Read-Only
-
-- `feeds` (Block List) A list of feeds that match the filter(s). (see [below for nested schema](#nestedblock--feeds))
-- `id` (String) The ID of this resource.
-
### Nested Schema for `feeds`
-Read-Only:
+Required:
+
+- `access_key` (String) The AWS access key to use when authenticating against Amazon Web Services.
+- `feed_uri` (String)
+- `name` (String) The name of this resource.
+
+Optional:
-- `access_key` (String)
- `api_version` (String)
- `delete_unreleased_packages_after_days` (Number)
- `download_attempts` (Number) The number of times a deployment should attempt to download a package from this feed before failing.
- `download_retry_backoff_seconds` (Number) The number of seconds to apply as a linear back off between download attempts.
-- `feed_type` (String)
-- `feed_uri` (String)
+- `feed_type` (String) A filter to search by feed type. Valid feed types are `AwsElasticContainerRegistry`, `BuiltIn`, `Docker`, `GitHub`, `Helm`, `Maven`, `NuGet`, or `OctopusProject`.
- `id` (String) The unique ID for this resource.
- `is_enhanced_mode` (Boolean)
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
-- `region` (String)
- `registry_path` (String)
- `secret_key` (String, Sensitive)
-- `space_id` (String) The space ID associated with this resource.
-- `username` (String, Sensitive) The username associated with this resource.
\ No newline at end of file
+- `space_id` (String) The space ID associated with this feeds.
+- `username` (String, Sensitive) The username associated with this resource.
+
+Read-Only:
+
+- `region` (String)
\ No newline at end of file
diff --git a/docs/data-sources/library_variable_sets.md b/docs/data-sources/library_variable_sets.md
index da636ab68..8b6eeb19f 100644
--- a/docs/data-sources/library_variable_sets.md
+++ b/docs/data-sources/library_variable_sets.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_library_variable_sets Data Source - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
-
+ Provides information about existing library variable sets.
---
# octopusdeploy_library_variable_sets (Data Source)
-
+Provides information about existing library variable sets.
diff --git a/docs/resources/artifactory_generic_feed.md b/docs/resources/artifactory_generic_feed.md
index 3d46c6eec..07ea676ce 100644
--- a/docs/resources/artifactory_generic_feed.md
+++ b/docs/resources/artifactory_generic_feed.md
@@ -29,7 +29,7 @@ resource "octopusdeploy_artifactory_generic_feed" "example" {
### Required
- `feed_uri` (String)
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `name` (String) The name of this resource.
- `repository` (String)
### Optional
@@ -38,7 +38,7 @@ resource "octopusdeploy_artifactory_generic_feed" "example" {
- `layout_regex` (String)
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this helm feed.
- `username` (String, Sensitive) The username associated with this resource.
## Import
diff --git a/docs/resources/aws_elastic_container_registry.md b/docs/resources/aws_elastic_container_registry.md
index 5549897ea..e0b4f802f 100644
--- a/docs/resources/aws_elastic_container_registry.md
+++ b/docs/resources/aws_elastic_container_registry.md
@@ -25,15 +25,15 @@ resource "octopusdeploy_aws_elastic_container_registry" "example" {
### Required
- `access_key` (String) The AWS access key to use when authenticating against Amazon Web Services.
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `name` (String) The name of this resource.
- `region` (String) The AWS region where the registry resides.
- `secret_key` (String, Sensitive) The AWS secret key to use when authenticating against Amazon Web Services.
### Optional
-- `id` (String) The unique ID for this feed.
+- `id` (String) The unique ID for this resource.
- `package_acquisition_location_options` (List of String)
-- `space_id` (String) The space ID associated with this feed.
+- `space_id` (String) The space ID associated with this aws elastic container registry.
## Import
diff --git a/docs/resources/docker_container_registry.md b/docs/resources/docker_container_registry.md
index ebc6b68cb..8a59fe071 100644
--- a/docs/resources/docker_container_registry.md
+++ b/docs/resources/docker_container_registry.md
@@ -25,8 +25,8 @@ resource "octopusdeploy_docker_container_registry" "example" {
### Required
-- `feed_uri` (String) The URL to a Docker repository.
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `feed_uri` (String)
+- `name` (String) The name of this resource.
### Optional
@@ -35,7 +35,7 @@ resource "octopusdeploy_docker_container_registry" "example" {
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
- `registry_path` (String)
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this docker container registry feed.
- `username` (String, Sensitive) The username associated with this resource.
## Import
diff --git a/docs/resources/github_repository_feed.md b/docs/resources/github_repository_feed.md
index c743a47dd..37e9601c1 100644
--- a/docs/resources/github_repository_feed.md
+++ b/docs/resources/github_repository_feed.md
@@ -27,7 +27,7 @@ resource "octopusdeploy_github_repository_feed" "example" {
### Required
- `feed_uri` (String)
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `name` (String) The name of this resource.
### Optional
@@ -36,7 +36,7 @@ resource "octopusdeploy_github_repository_feed" "example" {
- `id` (String) The unique ID for this resource.
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this github repository feed.
- `username` (String, Sensitive) The username associated with this resource.
## Import
diff --git a/docs/resources/helm_feed.md b/docs/resources/helm_feed.md
index 037bc5888..5eed44882 100644
--- a/docs/resources/helm_feed.md
+++ b/docs/resources/helm_feed.md
@@ -2,12 +2,12 @@
page_title: "octopusdeploy_helm_feed Resource - terraform-provider-octopusdeploy"
subcategory: "Feeds"
description: |-
- This resource manages a Helm feed in Octopus Deploy.
+ This resource manages a Helm Feed in Octopus Deploy.
---
# octopusdeploy_helm_feed (Resource)
-This resource manages a Helm feed in Octopus Deploy.
+This resource manages a Helm Feed in Octopus Deploy.
## Example Usage
@@ -25,14 +25,14 @@ resource "octopusdeploy_helm_feed" "example" {
### Required
- `feed_uri` (String)
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `name` (String) The name of this resource.
### Optional
- `id` (String) The unique ID for this resource.
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this helm feed.
- `username` (String, Sensitive) The username associated with this resource.
## Import
diff --git a/docs/resources/library_variable_set.md b/docs/resources/library_variable_set.md
index b30fd3f1f..9bff4bf78 100644
--- a/docs/resources/library_variable_set.md
+++ b/docs/resources/library_variable_set.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_library_variable_set Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
-
+ This resource manages library variable sets in Octopus Deploy.
---
# octopusdeploy_library_variable_set (Resource)
-
+This resource manages library variable sets in Octopus Deploy.
diff --git a/docs/resources/maven_feed.md b/docs/resources/maven_feed.md
index a589dc13f..1c01d16e8 100644
--- a/docs/resources/maven_feed.md
+++ b/docs/resources/maven_feed.md
@@ -27,7 +27,7 @@ resource "octopusdeploy_maven_feed" "example" {
### Required
- `feed_uri` (String)
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `name` (String) The name of this resource.
### Optional
@@ -36,7 +36,7 @@ resource "octopusdeploy_maven_feed" "example" {
- `id` (String) The unique ID for this resource.
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this maven feed.
- `username` (String, Sensitive) The username associated with this resource.
## Import
diff --git a/docs/resources/nuget_feed.md b/docs/resources/nuget_feed.md
index 0444d55ba..b5758af66 100644
--- a/docs/resources/nuget_feed.md
+++ b/docs/resources/nuget_feed.md
@@ -27,8 +27,8 @@ resource "octopusdeploy_nuget_feed" "example" {
### Required
-- `feed_uri` (String) The feed URI can be a URL or a folder path.
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `feed_uri` (String)
+- `name` (String) The name of this resource.
### Optional
@@ -38,7 +38,7 @@ resource "octopusdeploy_nuget_feed" "example" {
- `is_enhanced_mode` (Boolean) This will improve performance of the NuGet feed but may not be supported by some older feeds. Disable if the operation, Create Release does not return the latest version for a package.
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this nuget feed.
- `username` (String, Sensitive) The username associated with this resource.
## Import
diff --git a/octopusdeploy/provider.go b/octopusdeploy/provider.go
index cd51d9521..07f503374 100644
--- a/octopusdeploy/provider.go
+++ b/octopusdeploy/provider.go
@@ -48,7 +48,6 @@ func Provider() *schema.Provider {
"octopusdeploy_channel": resourceChannel(),
"octopusdeploy_cloud_region_deployment_target": resourceCloudRegionDeploymentTarget(),
"octopusdeploy_deployment_process": resourceDeploymentProcess(),
- "octopusdeploy_docker_container_registry": resourceDockerContainerRegistry(),
"octopusdeploy_dynamic_worker_pool": resourceDynamicWorkerPool(),
"octopusdeploy_gcp_account": resourceGoogleCloudPlatformAccount(),
"octopusdeploy_kubernetes_agent_deployment_target": resourceKubernetesAgentDeploymentTarget(),
diff --git a/octopusdeploy/resource_docker_container_registry.go b/octopusdeploy/resource_docker_container_registry.go
deleted file mode 100644
index bf5d1edd8..000000000
--- a/octopusdeploy/resource_docker_container_registry.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "fmt"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
- "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
- "github.com/hashicorp/terraform-plugin-log/tflog"
- "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-)
-
-func resourceDockerContainerRegistry() *schema.Resource {
- return &schema.Resource{
- CreateContext: resourceDockerContainerRegistryCreate,
- DeleteContext: resourceDockerContainerRegistryDelete,
- Description: "This resource manages a Docker Container Registry in Octopus Deploy.",
- Importer: getImporter(),
- ReadContext: resourceDockerContainerRegistryRead,
- Schema: getDockerContainerRegistrySchema(),
- UpdateContext: resourceDockerContainerRegistryUpdate,
- }
-}
-
-func resourceDockerContainerRegistryCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- dockerContainerRegistry, err := expandDockerContainerRegistry(d)
- if err != nil {
- return diag.FromErr(err)
- }
-
- tflog.Info(ctx, fmt.Sprintf("creating Docker container registry, %s", dockerContainerRegistry.GetName()))
-
- client := m.(*client.Client)
- createdDockerContainerRegistry, err := feeds.Add(client, dockerContainerRegistry)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := setDockerContainerRegistry(ctx, d, createdDockerContainerRegistry.(*feeds.DockerContainerRegistry)); err != nil {
- return diag.FromErr(err)
- }
-
- d.SetId(createdDockerContainerRegistry.GetID())
-
- tflog.Info(ctx, fmt.Sprintf("Docker container registry created (%s)", d.Id()))
- return nil
-}
-
-func resourceDockerContainerRegistryDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- tflog.Info(ctx, fmt.Sprintf("deleting Docker container registry (%s)", d.Id()))
-
- client := m.(*client.Client)
- err := client.Feeds.DeleteByID(d.Id())
- if err != nil {
- return diag.FromErr(err)
- }
-
- d.SetId("")
-
- tflog.Info(ctx, "Docker container registry deleted")
- return nil
-}
-
-func resourceDockerContainerRegistryRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- tflog.Info(ctx, fmt.Sprintf("reading Docker container registry (%s)", d.Id()))
-
- client := m.(*client.Client)
- feed, err := feeds.GetByID(client, d.Get("space_id").(string), d.Id())
- if err != nil {
- return errors.ProcessApiError(ctx, d, err, "Docker container registry")
- }
-
- dockerContainerRegistry := feed.(*feeds.DockerContainerRegistry)
- if err := setDockerContainerRegistry(ctx, d, dockerContainerRegistry); err != nil {
- return diag.FromErr(err)
- }
-
- tflog.Info(ctx, fmt.Sprintf("Docker container registry read (%s)", dockerContainerRegistry.GetID()))
- return nil
-}
-
-func resourceDockerContainerRegistryUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- feed, err := expandDockerContainerRegistry(d)
- if err != nil {
- return diag.FromErr(err)
- }
-
- tflog.Info(ctx, fmt.Sprintf("updating Docker container registry (%s)", feed.GetID()))
-
- client := m.(*client.Client)
- updatedFeed, err := feeds.Update(client, feed)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := setDockerContainerRegistry(ctx, d, updatedFeed.(*feeds.DockerContainerRegistry)); err != nil {
- return diag.FromErr(err)
- }
-
- tflog.Info(ctx, fmt.Sprintf("Docker container registry updated (%s)", d.Id()))
- return nil
-}
diff --git a/octopusdeploy/schema_docker_container_registry.go b/octopusdeploy/schema_docker_container_registry.go
deleted file mode 100644
index a28f565cd..000000000
--- a/octopusdeploy/schema_docker_container_registry.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "fmt"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
-)
-
-func expandDockerContainerRegistry(d *schema.ResourceData) (*feeds.DockerContainerRegistry, error) {
- name := d.Get("name").(string)
-
- feed, err := feeds.NewDockerContainerRegistry(name)
- if err != nil {
- return nil, err
- }
-
- feed.ID = d.Id()
-
- if v, ok := d.GetOk("api_version"); ok {
- feed.APIVersion = v.(string)
- }
-
- if v, ok := d.GetOk("feed_uri"); ok {
- feed.FeedURI = v.(string)
- }
-
- if v, ok := d.GetOk("registry_path"); ok {
- feed.RegistryPath = v.(string)
- }
-
- if v, ok := d.GetOk("space_id"); ok {
- feed.SpaceID = v.(string)
- }
-
- if v, ok := d.GetOk("package_acquisition_location_options"); ok {
- feed.PackageAcquisitionLocationOptions = getSliceFromTerraformTypeList(v)
- }
-
- if v, ok := d.GetOk("password"); ok {
- feed.Password = core.NewSensitiveValue(v.(string))
- }
-
- if v, ok := d.GetOk("username"); ok {
- feed.Username = v.(string)
- }
-
- return feed, nil
-}
-
-func getDockerContainerRegistrySchema() map[string]*schema.Schema {
- return map[string]*schema.Schema{
- "api_version": {
- Optional: true,
- Type: schema.TypeString,
- },
- "feed_uri": {
- Description: "The URL to a Docker repository.",
- Required: true,
- Type: schema.TypeString,
- ValidateDiagFunc: validation.ToDiagFunc(validation.IsURLWithHTTPorHTTPS),
- },
- "id": getIDSchema(),
- "name": {
- Description: "A short, memorable, unique name for this feed. Example: ACME Builds.",
- Required: true,
- Type: schema.TypeString,
- ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotEmpty),
- },
- "password": getPasswordSchema(false),
- "package_acquisition_location_options": {
- Computed: true,
- Elem: &schema.Schema{Type: schema.TypeString},
- Optional: true,
- Type: schema.TypeList,
- },
- "registry_path": {
- Optional: true,
- Type: schema.TypeString,
- },
- "space_id": getSpaceIDSchema(),
- "username": getUsernameSchema(false),
- }
-}
-
-func setDockerContainerRegistry(ctx context.Context, d *schema.ResourceData, feed *feeds.DockerContainerRegistry) error {
- d.Set("api_version", feed.APIVersion)
- d.Set("feed_uri", feed.FeedURI)
- d.Set("name", feed.Name)
- d.Set("registry_path", feed.RegistryPath)
- d.Set("space_id", feed.SpaceID)
- d.Set("username", feed.Username)
-
- if err := d.Set("package_acquisition_location_options", feed.PackageAcquisitionLocationOptions); err != nil {
- return fmt.Errorf("error setting package_acquisition_location_options: %s", err)
- }
-
- d.SetId(feed.GetID())
-
- return nil
-}
diff --git a/octopusdeploy_framework/framework_provider.go b/octopusdeploy_framework/framework_provider.go
index 816b8f774..447f66237 100644
--- a/octopusdeploy_framework/framework_provider.go
+++ b/octopusdeploy_framework/framework_provider.go
@@ -2,9 +2,9 @@ package octopusdeploy_framework
import (
"context"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"os"
- "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
@@ -92,6 +92,7 @@ func (p *octopusDeployFrameworkProvider) Resources(ctx context.Context) []func()
NewLibraryVariableSetFeedResource,
NewVariableResource,
NewProjectResource,
+ NewDockerContainerRegistryFeedResource,
}
}
diff --git a/octopusdeploy_framework/resource_artifactory_generic_feed.go b/octopusdeploy_framework/resource_artifactory_generic_feed.go
index e70900061..a1eb7ab58 100644
--- a/octopusdeploy_framework/resource_artifactory_generic_feed.go
+++ b/octopusdeploy_framework/resource_artifactory_generic_feed.go
@@ -29,7 +29,8 @@ func (r *artifactoryGenericFeedTypeResource) Metadata(ctx context.Context, req r
func (r *artifactoryGenericFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: schemas.GetArtifactoryGenericFeedResourceSchema(),
+ Attributes: schemas.GetArtifactoryGenericFeedResourceSchema(),
+ Description: "This resource manages a Artifactory Generic feed in Octopus Deploy.",
}
}
diff --git a/octopusdeploy_framework/resource_aws_elastic_container_registry.go b/octopusdeploy_framework/resource_aws_elastic_container_registry.go
index 96f089a83..72cef3b51 100644
--- a/octopusdeploy_framework/resource_aws_elastic_container_registry.go
+++ b/octopusdeploy_framework/resource_aws_elastic_container_registry.go
@@ -28,7 +28,8 @@ func (r *awsElasticContainerRegistryFeedTypeResource) Metadata(ctx context.Conte
func (r *awsElasticContainerRegistryFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: schemas.GetAwsElasticContainerRegistryFeedResourceSchema(),
+ Attributes: schemas.GetAwsElasticContainerRegistryFeedResourceSchema(),
+ Description: "This resource manages an AWS Elastic Container Registry in Octopus Deploy.",
}
}
diff --git a/octopusdeploy_framework/resource_docker_container_registry.go b/octopusdeploy_framework/resource_docker_container_registry.go
new file mode 100644
index 000000000..fa73ef902
--- /dev/null
+++ b/octopusdeploy_framework/resource_docker_container_registry.go
@@ -0,0 +1,183 @@
+package octopusdeploy_framework
+
+import (
+ "context"
+ "fmt"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+)
+
+type dockerContainerRegistryFeedTypeResource struct {
+ *Config
+}
+
+func NewDockerContainerRegistryFeedResource() resource.Resource {
+ return &dockerContainerRegistryFeedTypeResource{}
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = util.GetTypeName("docker_container_registry")
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ Attributes: schemas.GetDockerContainerRegistryFeedResourceSchema(),
+ Description: "This resource manages a Docker Container Registry in Octopus Deploy.",
+ }
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ r.Config = ResourceConfiguration(req, resp)
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var data *schemas.DockerContainerRegistryFeedTypeResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ dockerContainerRegistryFeed, err := createDockerContainerRegistryFeedResourceFromData(data)
+ if err != nil {
+ return
+ }
+
+ tflog.Info(ctx, fmt.Sprintf("creating Docker Container Registry feed: %s", dockerContainerRegistryFeed.GetName()))
+
+ client := r.Config.Client
+ createdFeed, err := feeds.Add(client, dockerContainerRegistryFeed)
+ if err != nil {
+ resp.Diagnostics.AddError("unable to create docker container registry feed", err.Error())
+ return
+ }
+
+ updateDataFromDockerContainerRegistryFeed(data, data.SpaceID.ValueString(), createdFeed.(*feeds.DockerContainerRegistry))
+
+ tflog.Info(ctx, fmt.Sprintf("Docker Container Registry feed created (%s)", data.ID))
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var data *schemas.DockerContainerRegistryFeedTypeResourceModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Info(ctx, fmt.Sprintf("reading Docker Container Registry feed (%s)", data.ID))
+
+ client := r.Config.Client
+ feed, err := feeds.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
+ if err != nil {
+ resp.Diagnostics.AddError("unable to load docker container registry feed", err.Error())
+ return
+ }
+
+ dockerContainerRegistry := feed.(*feeds.DockerContainerRegistry)
+ updateDataFromDockerContainerRegistryFeed(data, data.SpaceID.ValueString(), dockerContainerRegistry)
+
+ tflog.Info(ctx, fmt.Sprintf("Docker Container Registry feed read (%s)", dockerContainerRegistry.GetID()))
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var data, state *schemas.DockerContainerRegistryFeedTypeResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+ resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("updating docker container registry feed '%s'", data.ID.ValueString()))
+
+ feed, err := createDockerContainerRegistryFeedResourceFromData(data)
+ feed.ID = state.ID.ValueString()
+ if err != nil {
+ resp.Diagnostics.AddError("unable to load docker container registry feed", err.Error())
+ return
+ }
+
+ tflog.Info(ctx, fmt.Sprintf("updating Docker Container Registry feed (%s)", data.ID))
+
+ client := r.Config.Client
+ updatedFeed, err := feeds.Update(client, feed)
+ if err != nil {
+ resp.Diagnostics.AddError("unable to update docker container registry feed", err.Error())
+ return
+ }
+
+ updateDataFromDockerContainerRegistryFeed(data, state.SpaceID.ValueString(), updatedFeed.(*feeds.DockerContainerRegistry))
+
+ tflog.Info(ctx, fmt.Sprintf("Docker Container Registry feed updated (%s)", data.ID))
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var data schemas.DockerContainerRegistryFeedTypeResourceModel
+
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ if err := feeds.DeleteByID(r.Config.Client, data.SpaceID.ValueString(), data.ID.ValueString()); err != nil {
+ resp.Diagnostics.AddError("unable to delete docker container registry feed", err.Error())
+ return
+ }
+}
+
+func createDockerContainerRegistryFeedResourceFromData(data *schemas.DockerContainerRegistryFeedTypeResourceModel) (*feeds.DockerContainerRegistry, error) {
+ feed, err := feeds.NewDockerContainerRegistry(data.Name.ValueString())
+ if err != nil {
+ return nil, err
+ }
+
+ feed.ID = data.ID.ValueString()
+ feed.FeedURI = data.FeedUri.ValueString()
+
+ var packageAcquisitionLocationOptions []string
+ for _, element := range data.PackageAcquisitionLocationOptions.Elements() {
+ packageAcquisitionLocationOptions = append(packageAcquisitionLocationOptions, element.(types.String).ValueString())
+ }
+
+ feed.PackageAcquisitionLocationOptions = packageAcquisitionLocationOptions
+ feed.Password = core.NewSensitiveValue(data.Password.ValueString())
+ feed.SpaceID = data.SpaceID.ValueString()
+ feed.Username = data.Username.ValueString()
+ feed.APIVersion = data.APIVersion.ValueString()
+ feed.RegistryPath = data.RegistryPath.ValueString()
+
+ return feed, nil
+}
+
+func updateDataFromDockerContainerRegistryFeed(data *schemas.DockerContainerRegistryFeedTypeResourceModel, spaceId string, feed *feeds.DockerContainerRegistry) {
+ data.FeedUri = types.StringValue(feed.FeedURI)
+ data.Name = types.StringValue(feed.Name)
+ data.SpaceID = types.StringValue(spaceId)
+ if feed.APIVersion != "" {
+ data.APIVersion = types.StringValue(feed.APIVersion)
+ }
+ if feed.RegistryPath != "" {
+ data.RegistryPath = types.StringValue(feed.RegistryPath)
+ }
+ if feed.Username != "" {
+ data.Username = types.StringValue(feed.Username)
+ }
+
+ packageAcquisitionLocationOptionsList := make([]attr.Value, len(feed.PackageAcquisitionLocationOptions))
+ for i, option := range feed.PackageAcquisitionLocationOptions {
+ packageAcquisitionLocationOptionsList[i] = types.StringValue(option)
+ }
+
+ var packageAcquisitionLocationOptionsListValue, _ = types.ListValue(types.StringType, packageAcquisitionLocationOptionsList)
+ data.PackageAcquisitionLocationOptions = packageAcquisitionLocationOptionsListValue
+ data.ID = types.StringValue(feed.ID)
+}
diff --git a/octopusdeploy/resource_docker_container_registry_test.go b/octopusdeploy_framework/resource_docker_container_registry_test.go
similarity index 94%
rename from octopusdeploy/resource_docker_container_registry_test.go
rename to octopusdeploy_framework/resource_docker_container_registry_test.go
index 377ced443..9e2c893fa 100644
--- a/octopusdeploy/resource_docker_container_registry_test.go
+++ b/octopusdeploy_framework/resource_docker_container_registry_test.go
@@ -1,16 +1,15 @@
-package octopusdeploy
+package octopusdeploy_framework
import (
"fmt"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
"github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/octoclient"
"github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/test"
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
"path/filepath"
"testing"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
- "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func TestAccOctopusDeployDockerContainerRegistry(t *testing.T) {
@@ -26,7 +25,7 @@ func TestAccOctopusDeployDockerContainerRegistry(t *testing.T) {
resource.Test(t, resource.TestCase{
CheckDestroy: testDockerContainerRegistryCheckDestroy,
- PreCheck: func() { testAccPreCheck(t) },
+ PreCheck: func() { TestAccPreCheck(t) },
ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
Steps: []resource.TestStep{
{
diff --git a/octopusdeploy_framework/resource_github_repository_feed.go b/octopusdeploy_framework/resource_github_repository_feed.go
index 7a198daaa..30f7bdb28 100644
--- a/octopusdeploy_framework/resource_github_repository_feed.go
+++ b/octopusdeploy_framework/resource_github_repository_feed.go
@@ -28,7 +28,8 @@ func (r *githubRepositoryFeedTypeResource) Metadata(ctx context.Context, req res
func (r *githubRepositoryFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: schemas.GetGitHubRepositoryFeedResourceSchema(),
+ Attributes: schemas.GetGitHubRepositoryFeedResourceSchema(),
+ Description: "This resource manages a GitHub repository feed in Octopus Deploy.",
}
}
diff --git a/octopusdeploy_framework/resource_helm_feed.go b/octopusdeploy_framework/resource_helm_feed.go
index 4fc1c9d3c..64ec52677 100644
--- a/octopusdeploy_framework/resource_helm_feed.go
+++ b/octopusdeploy_framework/resource_helm_feed.go
@@ -29,7 +29,8 @@ func (r *helmFeedTypeResource) Metadata(ctx context.Context, req resource.Metada
func (r *helmFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: schemas.GetHelmFeedResourceSchema(),
+ Attributes: schemas.GetHelmFeedResourceSchema(),
+ Description: "This resource manages a Helm Feed in Octopus Deploy.",
}
}
diff --git a/octopusdeploy_framework/resource_maven_feed.go b/octopusdeploy_framework/resource_maven_feed.go
index c6f6ddd19..722081e81 100644
--- a/octopusdeploy_framework/resource_maven_feed.go
+++ b/octopusdeploy_framework/resource_maven_feed.go
@@ -28,7 +28,8 @@ func (r *mavenFeedTypeResource) Metadata(ctx context.Context, req resource.Metad
func (r *mavenFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: schemas.GetMavenFeedResourceSchema(),
+ Attributes: schemas.GetMavenFeedResourceSchema(),
+ Description: "This resource manages a Maven feed in Octopus Deploy.",
}
}
diff --git a/octopusdeploy_framework/resource_nuget_feed.go b/octopusdeploy_framework/resource_nuget_feed.go
index 306e16f14..f053ea450 100644
--- a/octopusdeploy_framework/resource_nuget_feed.go
+++ b/octopusdeploy_framework/resource_nuget_feed.go
@@ -28,7 +28,8 @@ func (r *nugetFeedTypeResource) Metadata(ctx context.Context, req resource.Metad
func (r *nugetFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: schemas.GetNugetFeedResourceSchema(),
+ Attributes: schemas.GetNugetFeedResourceSchema(),
+ Description: "This resource manages a Nuget feed in Octopus Deploy.",
}
}
diff --git a/octopusdeploy_framework/schemas/docker_container_registry_feed.go b/octopusdeploy_framework/schemas/docker_container_registry_feed.go
new file mode 100644
index 000000000..d7ff550c4
--- /dev/null
+++ b/octopusdeploy_framework/schemas/docker_container_registry_feed.go
@@ -0,0 +1,39 @@
+package schemas
+
+import (
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+const dockerContainerRegistryFeedDescription = "docker container registry feed"
+
+func GetDockerContainerRegistryFeedResourceSchema() map[string]resourceSchema.Attribute {
+ return map[string]resourceSchema.Attribute{
+ "api_version": resourceSchema.StringAttribute{
+ Optional: true,
+ },
+ "feed_uri": util.GetFeedUriResourceSchema(),
+ "id": util.GetIdResourceSchema(),
+ "name": util.GetNameResourceSchema(true),
+ "package_acquisition_location_options": util.GetPackageAcquisitionLocationOptionsResourceSchema(),
+ "password": util.GetPasswordResourceSchema(false),
+ "space_id": util.GetSpaceIdResourceSchema(dockerContainerRegistryFeedDescription),
+ "username": util.GetUsernameResourceSchema(false),
+ "registry_path": resourceSchema.StringAttribute{
+ Optional: true,
+ },
+ }
+}
+
+type DockerContainerRegistryFeedTypeResourceModel struct {
+ APIVersion types.String `tfsdk:"api_version"`
+ FeedUri types.String `tfsdk:"feed_uri"`
+ ID types.String `tfsdk:"id"`
+ Name types.String `tfsdk:"name"`
+ PackageAcquisitionLocationOptions types.List `tfsdk:"package_acquisition_location_options"`
+ Password types.String `tfsdk:"password"`
+ SpaceID types.String `tfsdk:"space_id"`
+ Username types.String `tfsdk:"username"`
+ RegistryPath types.String `tfsdk:"registry_path"`
+}
diff --git a/octopusdeploy_framework/schemas/library_variable_set.go b/octopusdeploy_framework/schemas/library_variable_set.go
index f3355768f..5fab75d02 100644
--- a/octopusdeploy_framework/schemas/library_variable_set.go
+++ b/octopusdeploy_framework/schemas/library_variable_set.go
@@ -22,7 +22,8 @@ type LibraryVariableSetResourceModel struct {
func GetLibraryVariableSetDataSourceSchema() datasourceSchema.Schema {
return datasourceSchema.Schema{
- Attributes: getLibraryVariableSetDataSchema(),
+ Attributes: getLibraryVariableSetDataSchema(),
+ Description: "Provides information about existing library variable sets.",
Blocks: map[string]datasourceSchema.Block{
"library_variable_sets": datasourceSchema.ListNestedBlock{
Description: "A list of library variable sets that match the filter(s).",
@@ -97,6 +98,7 @@ func GetLibraryVariableSetResourceSchema() resourceSchema.Schema {
Computed: true,
},
},
+ Description: "This resource manages library variable sets in Octopus Deploy.",
Blocks: map[string]resourceSchema.Block{
"template": resourceSchema.ListNestedBlock{
NestedObject: resourceSchema.NestedBlockObject{
From 7c81ce944a04db0272c2a4aab8adac7d3b56a1b1 Mon Sep 17 00:00:00 2001
From: Huy Nguyen <162080607+HuyPhanNguyen@users.noreply.github.com>
Date: Wed, 7 Aug 2024 18:37:14 +1000
Subject: [PATCH 2/3] Fix bug datasource spaces (#710)
* Fix query.Ids convert and add basic test
* Update the test
* Fix the util method instead
* just ignore if cant convert to string
* try to fix flaky test
* second try
* Add lifecycle datasource test
* Last try to avoid race condition
* Test why not 7 variables create
* switch the order
---
octopusdeploy/testing_container_test.go | 5 ++
.../datasource_lifecycle_test.go | 63 +++++++++++++++++
.../datasource_spaces_test.go | 58 ++++++++++++++++
.../resource_variable_test.go | 15 +++-
octopusdeploy_framework/schemas/schema.go | 7 +-
terraform/49-variables/variables.tf | 68 ++++++++++++++++---
6 files changed, 203 insertions(+), 13 deletions(-)
create mode 100644 octopusdeploy_framework/datasource_lifecycle_test.go
create mode 100644 octopusdeploy_framework/datasource_spaces_test.go
diff --git a/octopusdeploy/testing_container_test.go b/octopusdeploy/testing_container_test.go
index 8c1bd6397..6fd5dfba7 100644
--- a/octopusdeploy/testing_container_test.go
+++ b/octopusdeploy/testing_container_test.go
@@ -57,6 +57,11 @@ func TestMain(m *testing.M) {
log.Printf("Failed to create client: (%s)", err.Error())
panic(m)
}
+
+ octoContainer = &test.OctopusContainer{
+ Container: nil,
+ URI: url,
+ }
}
code := m.Run()
os.Exit(code)
diff --git a/octopusdeploy_framework/datasource_lifecycle_test.go b/octopusdeploy_framework/datasource_lifecycle_test.go
new file mode 100644
index 000000000..c7febe404
--- /dev/null
+++ b/octopusdeploy_framework/datasource_lifecycle_test.go
@@ -0,0 +1,63 @@
+package octopusdeploy_framework
+
+import (
+ "fmt"
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccDataSourceLifecycles(t *testing.T) {
+ spaceName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
+ lifecycleName := "Default Lifecycle"
+ resourceName := "data.octopusdeploy_lifecycles.lifecycle_default_lifecycle"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
+ Steps: []resource.TestStep{
+ {
+ Config: testAccDataSourceLifecyclesConfig(spaceName, lifecycleName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttrSet(resourceName, "space_id"),
+ resource.TestCheckResourceAttr(resourceName, "partial_name", lifecycleName),
+ resource.TestCheckResourceAttr(resourceName, "lifecycles.#", "1"),
+ resource.TestCheckResourceAttrSet(resourceName, "lifecycles.0.id"),
+ resource.TestCheckResourceAttr(resourceName, "lifecycles.0.name", lifecycleName),
+ testAccCheckOutputExists("octopus_space_id"),
+ testAccCheckOutputExists("octopus_lifecycle_id"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccDataSourceLifecyclesConfig(spaceName, lifecycleName string) string {
+ return fmt.Sprintf(`
+resource "octopusdeploy_space" "octopus_project_space_test" {
+ name = "%s"
+ is_default = false
+ is_task_queue_stopped = false
+ description = "Test space for lifecycles datasource"
+ space_managers_teams = ["teams-administrators"]
+}
+
+data "octopusdeploy_lifecycles" "lifecycle_default_lifecycle" {
+ ids = null
+ partial_name = "%s"
+ space_id = octopusdeploy_space.octopus_project_space_test.id
+ skip = 0
+ take = 1
+ depends_on = [octopusdeploy_space.octopus_project_space_test]
+}
+
+output "octopus_space_id" {
+ value = octopusdeploy_space.octopus_project_space_test.id
+}
+
+output "octopus_lifecycle_id" {
+ value = data.octopusdeploy_lifecycles.lifecycle_default_lifecycle.lifecycles[0].id
+}
+`, spaceName, lifecycleName)
+}
diff --git a/octopusdeploy_framework/datasource_spaces_test.go b/octopusdeploy_framework/datasource_spaces_test.go
new file mode 100644
index 000000000..dc48f1108
--- /dev/null
+++ b/octopusdeploy_framework/datasource_spaces_test.go
@@ -0,0 +1,58 @@
+package octopusdeploy_framework
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+)
+
+func TestAccDataSourceSpaces(t *testing.T) {
+ spaceID := "Spaces-1"
+ resourceName := "data.octopusdeploy_spaces.test"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
+ Steps: []resource.TestStep{
+ {
+ Config: testAccDataSourceSpacesConfig(spaceID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "ids.#", "1"),
+ resource.TestCheckResourceAttr(resourceName, "ids.0", spaceID),
+ resource.TestCheckResourceAttr(resourceName, "skip", "0"),
+ resource.TestCheckResourceAttr(resourceName, "take", "1"),
+ resource.TestCheckResourceAttrSet(resourceName, "spaces.0.id"),
+ testAccCheckOutputExists("octopus_space_id"),
+ resource.TestCheckOutput("octopus_space_id", spaceID),
+ ),
+ },
+ },
+ })
+}
+
+func testAccDataSourceSpacesConfig(spaceID string) string {
+ tfConfig := fmt.Sprintf(`
+ data "octopusdeploy_spaces" "test" {
+ ids = ["%s"]
+ skip = 0
+ take = 1
+ }
+
+ output "octopus_space_id" {
+ value = data.octopusdeploy_spaces.test.spaces[0].id
+ }
+ `, spaceID)
+ return tfConfig
+}
+
+func testAccCheckOutputExists(name string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ _, ok := s.RootModule().Outputs[name]
+ if !ok {
+ return fmt.Errorf("output %s not found", name)
+ }
+ return nil
+ }
+}
diff --git a/octopusdeploy_framework/resource_variable_test.go b/octopusdeploy_framework/resource_variable_test.go
index 055d796d4..d71cc6dd8 100644
--- a/octopusdeploy_framework/resource_variable_test.go
+++ b/octopusdeploy_framework/resource_variable_test.go
@@ -3,7 +3,9 @@ package octopusdeploy_framework
import (
"fmt"
"path/filepath"
+ "strings"
"testing"
+ "time"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/variables"
internalTest "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/test"
@@ -320,6 +322,9 @@ func TestVariableResource(t *testing.T) {
// Assert
client, err := octoclient.CreateClient(octoContainer.URI, newSpaceId, test.ApiKey)
project, err := client.Projects.GetByName("Test")
+
+ // Add a short delay before querying the API
+ time.Sleep(5 * time.Second)
variableSet, err := client.Variables.GetAll(project.ID)
if err != nil {
@@ -327,7 +332,15 @@ func TestVariableResource(t *testing.T) {
}
if len(variableSet.Variables) != 7 {
- t.Fatalf("Expected 7 variables to be created.")
+ var report strings.Builder
+ report.WriteString(fmt.Sprintf("Expected 7 variables, but found %d.\nReturned variables:\n", len(variableSet.Variables)))
+
+ for _, v := range variableSet.Variables {
+ report.WriteString(fmt.Sprintf("- Name: %s\n Type: %s\n Value: %s\n Scope: %+v\n\n",
+ v.Name, v.Type, v.Value, v.Scope))
+ }
+
+ t.Fatalf(report.String())
}
for _, variable := range variableSet.Variables {
diff --git a/octopusdeploy_framework/schemas/schema.go b/octopusdeploy_framework/schemas/schema.go
index 5c786144b..395aefc7f 100644
--- a/octopusdeploy_framework/schemas/schema.go
+++ b/octopusdeploy_framework/schemas/schema.go
@@ -191,7 +191,12 @@ func GetBooleanResourceAttribute(description string, defaultValue bool, isOption
func GetIds(ids types.List) []string {
var result = make([]string, 0, len(ids.Elements()))
for _, id := range ids.Elements() {
- result = append(result, id.String())
+ strVal, ok := id.(types.String)
+
+ if !ok || strVal.IsNull() || strVal.IsUnknown() {
+ continue
+ }
+ result = append(result, strVal.ValueString())
}
return result
}
diff --git a/terraform/49-variables/variables.tf b/terraform/49-variables/variables.tf
index 9ebdc692c..0e2f15da7 100644
--- a/terraform/49-variables/variables.tf
+++ b/terraform/49-variables/variables.tf
@@ -1,21 +1,35 @@
+
+
+resource "octopusdeploy_variable" "scoped_project_variable_action" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ ]
+ owner_id = octopusdeploy_project.test_project.id
+ type = "String"
+ name = "ActionScopedVariable"
+ value = "unscoped variable"
+ scope {
+ actions = [octopusdeploy_deployment_process.test_deployment_process.step[0].run_script_action[0].id]
+ }
+}
+
resource "octopusdeploy_variable" "unscoped_project_variable" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ octopusdeploy_variable.scoped_project_variable_action,
+ ]
owner_id = octopusdeploy_project.test_project.id
type = "String"
name = "UnscopedVariable"
value = "UnscopedVariable"
}
-resource "octopusdeploy_variable" "scoped_project_variable_action" {
- owner_id = octopusdeploy_project.test_project.id
- type = "String"
- name = "ActionScopedVariable"
- value = "unscoped variable"
- scope {
- actions = [octopusdeploy_deployment_process.test_deployment_process.step[0].run_script_action[0].id]
- }
-}
-
resource "octopusdeploy_variable" "scoped_project_variable_channel" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ octopusdeploy_variable.unscoped_project_variable,
+ octopusdeploy_variable.scoped_project_variable_action,
+ ]
owner_id = octopusdeploy_project.test_project.id
type = "String"
name = "ChannelScopedVariable"
@@ -26,6 +40,12 @@ resource "octopusdeploy_variable" "scoped_project_variable_channel" {
}
resource "octopusdeploy_variable" "scoped_project_variable_environment" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ octopusdeploy_variable.unscoped_project_variable,
+ octopusdeploy_variable.scoped_project_variable_action,
+ octopusdeploy_variable.scoped_project_variable_channel,
+ ]
owner_id = octopusdeploy_project.test_project.id
type = "String"
name = "EnvironmentScopedVariable"
@@ -36,6 +56,14 @@ resource "octopusdeploy_variable" "scoped_project_variable_environment" {
}
resource "octopusdeploy_variable" "scoped_project_variable_machine" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ octopusdeploy_variable.unscoped_project_variable,
+ octopusdeploy_variable.scoped_project_variable_action,
+ octopusdeploy_variable.scoped_project_variable_channel,
+ octopusdeploy_variable.scoped_project_variable_environment
+ ]
+
owner_id = octopusdeploy_project.test_project.id
type = "String"
name = "MachineScopedVariable"
@@ -46,6 +74,14 @@ resource "octopusdeploy_variable" "scoped_project_variable_machine" {
}
resource "octopusdeploy_variable" "scoped_project_variable_process" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ octopusdeploy_variable.unscoped_project_variable,
+ octopusdeploy_variable.scoped_project_variable_action,
+ octopusdeploy_variable.scoped_project_variable_channel,
+ octopusdeploy_variable.scoped_project_variable_environment,
+ octopusdeploy_variable.scoped_project_variable_machine,
+ ]
owner_id = octopusdeploy_project.test_project.id
type = "String"
name = "ProcessScopedVariable"
@@ -56,6 +92,16 @@ resource "octopusdeploy_variable" "scoped_project_variable_process" {
}
resource "octopusdeploy_variable" "scoped_project_variable_role" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ octopusdeploy_variable.unscoped_project_variable,
+ octopusdeploy_variable.scoped_project_variable_action,
+ octopusdeploy_variable.scoped_project_variable_channel,
+ octopusdeploy_variable.scoped_project_variable_environment,
+ octopusdeploy_variable.scoped_project_variable_machine,
+ octopusdeploy_variable.scoped_project_variable_process,
+ ]
+
owner_id = octopusdeploy_project.test_project.id
type = "String"
name = "RoleScopedVariable"
@@ -63,4 +109,4 @@ resource "octopusdeploy_variable" "scoped_project_variable_role" {
scope {
roles = ["role"]
}
-}
+}
\ No newline at end of file
From 3a8a027a764cda034b8840bbba6df254e5f0d6b4 Mon Sep 17 00:00:00 2001
From: Isaac Calligeros <101079287+IsaacCalligeros95@users.noreply.github.com>
Date: Thu, 8 Aug 2024 10:23:22 +0930
Subject: [PATCH 3/3] Isaac/mc schema fixes (#715)
* propagate an error
* The collection returned by data sources must not be optional
* Add more optionals
---------
Co-authored-by: Matthew Casperson
---
octopusdeploy/data_source_tenants.go | 5 ++++-
octopusdeploy/schema_account_resource.go | 1 +
.../schema_azure_cloud_service_deployment_target.go | 2 +-
.../schema_azure_service_fabric_cluster_deployment_target.go | 2 +-
octopusdeploy/schema_azure_web_app_deployment_target.go | 2 +-
octopusdeploy/schema_certificate.go | 2 +-
octopusdeploy/schema_channel.go | 2 +-
octopusdeploy/schema_cloud_region_deployment_target.go | 2 +-
octopusdeploy/schema_deployment_target.go | 2 +-
octopusdeploy/schema_kubernetes_agent_deployment_target.go | 2 +-
octopusdeploy/schema_kubernetes_cluster_deployment_target.go | 2 +-
octopusdeploy/schema_listening_tentacle_deployment_target.go | 2 +-
octopusdeploy/schema_machine_policy.go | 2 +-
.../schema_offline_package_drop_deployment_target.go | 2 +-
octopusdeploy/schema_polling_tentacle_deployment_target.go | 2 +-
octopusdeploy/schema_script_modules.go | 2 +-
octopusdeploy/schema_ssh_connection_deployment_target.go | 2 +-
octopusdeploy/schema_tag_set.go | 2 +-
octopusdeploy/schema_team.go | 2 +-
octopusdeploy/schema_tenant.go | 2 +-
octopusdeploy/schema_user.go | 2 +-
octopusdeploy/schema_user_role.go | 2 +-
octopusdeploy/schema_worker_pool.go | 2 +-
octopusdeploy_framework/schemas/gitCredential.go | 1 +
octopusdeploy_framework/schemas/lifecycle.go | 1 +
octopusdeploy_framework/schemas/project.go | 1 +
26 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/octopusdeploy/data_source_tenants.go b/octopusdeploy/data_source_tenants.go
index fcbdceae8..4c9cfa569 100644
--- a/octopusdeploy/data_source_tenants.go
+++ b/octopusdeploy/data_source_tenants.go
@@ -44,7 +44,10 @@ func dataSourceTenantsRead(ctx context.Context, d *schema.ResourceData, meta int
flattenedTenants = append(flattenedTenants, flattenTenant(tenant))
}
- d.Set("tenants", flattenedTenants)
+ if err := d.Set("tenants", flattenedTenants); err != nil {
+ return diag.FromErr(err)
+ }
+
d.SetId("Tenants " + time.Now().UTC().String())
return nil
diff --git a/octopusdeploy/schema_account_resource.go b/octopusdeploy/schema_account_resource.go
index 5dbee9361..4a31f5017 100644
--- a/octopusdeploy/schema_account_resource.go
+++ b/octopusdeploy/schema_account_resource.go
@@ -50,6 +50,7 @@ func getAccountResourceDataSchema() map[string]*schema.Schema {
Description: "A list of accounts that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
Type: schema.TypeList,
+ Optional: false,
},
"id": getDataSchemaID(),
"space_id": getQuerySpaceID(),
diff --git a/octopusdeploy/schema_azure_cloud_service_deployment_target.go b/octopusdeploy/schema_azure_cloud_service_deployment_target.go
index 46488a934..45e00de20 100644
--- a/octopusdeploy/schema_azure_cloud_service_deployment_target.go
+++ b/octopusdeploy/schema_azure_cloud_service_deployment_target.go
@@ -70,7 +70,7 @@ func getAzureCloudServiceDeploymentTargetDataSchema() map[string]*schema.Schema
Computed: true,
Description: "A list of Azure cloud service deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_azure_service_fabric_cluster_deployment_target.go b/octopusdeploy/schema_azure_service_fabric_cluster_deployment_target.go
index 3f8af8905..639d08553 100644
--- a/octopusdeploy/schema_azure_service_fabric_cluster_deployment_target.go
+++ b/octopusdeploy/schema_azure_service_fabric_cluster_deployment_target.go
@@ -85,7 +85,7 @@ func getAzureServiceFabricClusterDeploymentTargetDataSchema() map[string]*schema
Computed: true,
Description: "A list of Azure service fabric cluster deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_azure_web_app_deployment_target.go b/octopusdeploy/schema_azure_web_app_deployment_target.go
index 8478378b6..f8b2cfe25 100644
--- a/octopusdeploy/schema_azure_web_app_deployment_target.go
+++ b/octopusdeploy/schema_azure_web_app_deployment_target.go
@@ -55,7 +55,7 @@ func getAzureWebAppDeploymentTargetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of Azure web app deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_certificate.go b/octopusdeploy/schema_certificate.go
index 4252f9899..2d35164c9 100644
--- a/octopusdeploy/schema_certificate.go
+++ b/octopusdeploy/schema_certificate.go
@@ -170,7 +170,7 @@ func getCertificateDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of certificates that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"first_result": getQueryFirstResult(),
diff --git a/octopusdeploy/schema_channel.go b/octopusdeploy/schema_channel.go
index 88aa0bda9..eed2eead6 100644
--- a/octopusdeploy/schema_channel.go
+++ b/octopusdeploy/schema_channel.go
@@ -73,7 +73,7 @@ func getChannelDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A channel that matches the specified filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"ids": getQueryIDs(),
diff --git a/octopusdeploy/schema_cloud_region_deployment_target.go b/octopusdeploy/schema_cloud_region_deployment_target.go
index bce3dd18e..8e2375e07 100644
--- a/octopusdeploy/schema_cloud_region_deployment_target.go
+++ b/octopusdeploy/schema_cloud_region_deployment_target.go
@@ -40,7 +40,7 @@ func getCloudRegionDeploymentTargetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of cloud region deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_deployment_target.go b/octopusdeploy/schema_deployment_target.go
index 456265859..9649a7bec 100644
--- a/octopusdeploy/schema_deployment_target.go
+++ b/octopusdeploy/schema_deployment_target.go
@@ -90,7 +90,7 @@ func getDeploymentTargetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"environments": getQueryEnvironments(),
diff --git a/octopusdeploy/schema_kubernetes_agent_deployment_target.go b/octopusdeploy/schema_kubernetes_agent_deployment_target.go
index 822e7dce8..2323f311b 100644
--- a/octopusdeploy/schema_kubernetes_agent_deployment_target.go
+++ b/octopusdeploy/schema_kubernetes_agent_deployment_target.go
@@ -173,7 +173,7 @@ func getKubernetesAgentDeploymentTargetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of kubernetes agent deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_kubernetes_cluster_deployment_target.go b/octopusdeploy/schema_kubernetes_cluster_deployment_target.go
index 6dcbd6a35..4704688ff 100644
--- a/octopusdeploy/schema_kubernetes_cluster_deployment_target.go
+++ b/octopusdeploy/schema_kubernetes_cluster_deployment_target.go
@@ -131,7 +131,7 @@ func getKubernetesClusterDeploymentTargetDataSchema() map[string]*schema.Schema
Computed: true,
Description: "A list of Kubernetes cluster deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_listening_tentacle_deployment_target.go b/octopusdeploy/schema_listening_tentacle_deployment_target.go
index 32d2b3481..a35cdb8af 100644
--- a/octopusdeploy/schema_listening_tentacle_deployment_target.go
+++ b/octopusdeploy/schema_listening_tentacle_deployment_target.go
@@ -57,7 +57,7 @@ func getListeningTentacleDeploymentTargetDataSchema() map[string]*schema.Schema
Computed: true,
Description: "A list of listening tentacle deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_machine_policy.go b/octopusdeploy/schema_machine_policy.go
index 537da34df..0d24b2f6c 100644
--- a/octopusdeploy/schema_machine_policy.go
+++ b/octopusdeploy/schema_machine_policy.go
@@ -112,7 +112,7 @@ func getMachinePolicyDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of machine policies that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"partial_name": getQueryPartialName(),
diff --git a/octopusdeploy/schema_offline_package_drop_deployment_target.go b/octopusdeploy/schema_offline_package_drop_deployment_target.go
index f8b88f704..371a08b01 100644
--- a/octopusdeploy/schema_offline_package_drop_deployment_target.go
+++ b/octopusdeploy/schema_offline_package_drop_deployment_target.go
@@ -51,7 +51,7 @@ func getOfflinePackageDropDeploymentTargetDataSchema() map[string]*schema.Schema
Computed: true,
Description: "A list of offline package drop deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_polling_tentacle_deployment_target.go b/octopusdeploy/schema_polling_tentacle_deployment_target.go
index ab6472663..ee73b0cfb 100644
--- a/octopusdeploy/schema_polling_tentacle_deployment_target.go
+++ b/octopusdeploy/schema_polling_tentacle_deployment_target.go
@@ -51,7 +51,7 @@ func getPollingTentacleDeploymentTargetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of polling tentacle deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_script_modules.go b/octopusdeploy/schema_script_modules.go
index c4a24d1f8..906d2ea54 100644
--- a/octopusdeploy/schema_script_modules.go
+++ b/octopusdeploy/schema_script_modules.go
@@ -86,7 +86,7 @@ func getScriptModuleDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of script modules that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"partial_name": getQueryPartialName(),
diff --git a/octopusdeploy/schema_ssh_connection_deployment_target.go b/octopusdeploy/schema_ssh_connection_deployment_target.go
index 90934132f..df977c19d 100644
--- a/octopusdeploy/schema_ssh_connection_deployment_target.go
+++ b/octopusdeploy/schema_ssh_connection_deployment_target.go
@@ -57,7 +57,7 @@ func getSSHConnectionDeploymentTargetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of SSH connection deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_tag_set.go b/octopusdeploy/schema_tag_set.go
index db5c31a23..953b5c40c 100644
--- a/octopusdeploy/schema_tag_set.go
+++ b/octopusdeploy/schema_tag_set.go
@@ -54,7 +54,7 @@ func getTagSetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of tag sets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"take": getQueryTake(),
diff --git a/octopusdeploy/schema_team.go b/octopusdeploy/schema_team.go
index 3f782a1c9..d0656662e 100644
--- a/octopusdeploy/schema_team.go
+++ b/octopusdeploy/schema_team.go
@@ -85,7 +85,7 @@ func getTeamDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of teams that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
}
diff --git a/octopusdeploy/schema_tenant.go b/octopusdeploy/schema_tenant.go
index 6045f5981..260ba93f8 100644
--- a/octopusdeploy/schema_tenant.go
+++ b/octopusdeploy/schema_tenant.go
@@ -67,7 +67,7 @@ func getTenantDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of tenants that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"take": getQueryTake(),
diff --git a/octopusdeploy/schema_user.go b/octopusdeploy/schema_user.go
index 5ef089c67..620c3db37 100644
--- a/octopusdeploy/schema_user.go
+++ b/octopusdeploy/schema_user.go
@@ -74,7 +74,7 @@ func getUserDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of users that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
}
diff --git a/octopusdeploy/schema_user_role.go b/octopusdeploy/schema_user_role.go
index 9258402e5..4487a9170 100644
--- a/octopusdeploy/schema_user_role.go
+++ b/octopusdeploy/schema_user_role.go
@@ -84,7 +84,7 @@ func getUserRoleDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of user roles that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
}
diff --git a/octopusdeploy/schema_worker_pool.go b/octopusdeploy/schema_worker_pool.go
index 9207124c2..036e2a04a 100644
--- a/octopusdeploy/schema_worker_pool.go
+++ b/octopusdeploy/schema_worker_pool.go
@@ -39,7 +39,7 @@ func getWorkerPoolDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of worker pools that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
}
diff --git a/octopusdeploy_framework/schemas/gitCredential.go b/octopusdeploy_framework/schemas/gitCredential.go
index 2a29f1b4d..594f927b1 100644
--- a/octopusdeploy_framework/schemas/gitCredential.go
+++ b/octopusdeploy_framework/schemas/gitCredential.go
@@ -54,6 +54,7 @@ func GetGitCredentialDataSourceSchema() map[string]datasourceSchema.Attribute {
"take": util.GetQueryTakeDatasourceSchema(),
"git_credentials": datasourceSchema.ListNestedAttribute{
Computed: true,
+ Optional: false,
Description: "A list of Git Credentials that match the filter(s).",
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: GetGitCredentialAttributes(),
diff --git a/octopusdeploy_framework/schemas/lifecycle.go b/octopusdeploy_framework/schemas/lifecycle.go
index 092d48ab6..04f7f493a 100644
--- a/octopusdeploy_framework/schemas/lifecycle.go
+++ b/octopusdeploy_framework/schemas/lifecycle.go
@@ -97,6 +97,7 @@ func GetDatasourceLifecycleSchema() datasourceSchema.Schema {
"take": util.GetQueryTakeDatasourceSchema(),
"lifecycles": datasourceSchema.ListNestedAttribute{
Computed: true,
+ Optional: false,
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: map[string]datasourceSchema.Attribute{
"id": util.GetIdDatasourceSchema(),
diff --git a/octopusdeploy_framework/schemas/project.go b/octopusdeploy_framework/schemas/project.go
index fc4fee3b7..814710bda 100644
--- a/octopusdeploy_framework/schemas/project.go
+++ b/octopusdeploy_framework/schemas/project.go
@@ -193,6 +193,7 @@ func getProjectsDataSourceAttribute() datasourceSchema.ListNestedAttribute {
return datasourceSchema.ListNestedAttribute{
Description: "A list of projects that match the filter(s).",
Computed: true,
+ Optional: false,
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: map[string]datasourceSchema.Attribute{
"allow_deployments_to_no_targets": util.DataSourceBool().Computed().Deprecated("Allow deployments to be created when there are no targets.").Build(),