From 7fade0508fa4f3279c9ef91caa3e97bb6c781464 Mon Sep 17 00:00:00 2001
From: Huy Nguyen <162080607+HuyPhanNguyen@users.noreply.github.com>
Date: Thu, 8 Aug 2024 14:25:25 +1000
Subject: [PATCH] Update schema and doc GitCredential, Lifecycles and
TenantProjectVariable (#717)
* Update lifecycles schema and doc
* Fix lifecyle schema
* Update git credential resource
* Refactor tenant project variable
* Make it consistent
* Update datasource GitCredentialModel
* fix test fail
* Add username_password_account resource
* Revert "Add username_password_account resource"
This reverts commit 7a20ecb5c8698d7f341c2437d5f841aa2cf179ae.
* Update doc example
* small change on lifecycle example
---
docs/data-sources/lifecycles.md | 70 ++++----
docs/resources/git_credential.md | 10 +-
docs/resources/lifecycle.md | 38 ++---
docs/resources/tenant_project_variable.md | 18 +-
.../datasource_git_credentials.go | 8 +-
.../schemas/gitCredential.go | 95 +++++------
octopusdeploy_framework/schemas/lifecycle.go | 155 +++++++++---------
.../schemas/tenant_project_variable.go | 44 +++--
.../util/resource_attribute_builder.go | 80 +++++++++
9 files changed, 307 insertions(+), 211 deletions(-)
diff --git a/docs/data-sources/lifecycles.md b/docs/data-sources/lifecycles.md
index 2d6ce478e..d7fb232f4 100644
--- a/docs/data-sources/lifecycles.md
+++ b/docs/data-sources/lifecycles.md
@@ -26,62 +26,62 @@ data "octopusdeploy_lifecycles" "example" {
### Optional
-- `ids` (List of String) A filter to search by a list of IDs.
-- `partial_name` (String) A filter to search by the partial match of a name.
+- `ids` (List of String) A list of lifecycle IDs to filter by.
+- `partial_name` (String) A partial name to filter lifecycles by.
- `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 lifecycle.
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
### Read-Only
-- `id` (String) The ID of this resource.
-- `lifecycles` (Block List) A list of lifecycles that match the filter(s). (see [below for nested schema](#nestedblock--lifecycles))
+- `id` (String) The ID of the lifecycle.
+- `lifecycles` (Attributes List) (see [below for nested schema](#nestedatt--lifecycles))
-
+
### Nested Schema for `lifecycles`
Read-Only:
-- `description` (String) The description of this lifecycle.
-- `id` (String) The unique ID for this resource.
-- `name` (String) The name of this resource.
-- `phase` (List of Object) (see [below for nested schema](#nestedatt--lifecycles--phase))
-- `release_retention_policy` (List of Object) (see [below for nested schema](#nestedatt--lifecycles--release_retention_policy))
-- `space_id` (String) The space ID associated with this resource.
-- `tentacle_retention_policy` (List of Object) (see [below for nested schema](#nestedatt--lifecycles--tentacle_retention_policy))
+- `description` (String) The description of the lifecycle.
+- `id` (String) The ID of the lifecycle.
+- `name` (String) The name of the lifecycle.
+- `phase` (Attributes List) (see [below for nested schema](#nestedatt--lifecycles--phase))
+- `release_retention_policy` (Attributes List) (see [below for nested schema](#nestedatt--lifecycles--release_retention_policy))
+- `space_id` (String) The space ID associated with this lifecycle.
+- `tentacle_retention_policy` (Attributes List) (see [below for nested schema](#nestedatt--lifecycles--tentacle_retention_policy))
### Nested Schema for `lifecycles.phase`
Read-Only:
-- `automatic_deployment_targets` (List of String)
-- `id` (String)
-- `is_optional_phase` (Boolean)
-- `minimum_environments_before_promotion` (Number)
-- `name` (String)
-- `optional_deployment_targets` (List of String)
-- `release_retention_policy` (List of Object) (see [below for nested schema](#nestedobjatt--lifecycles--phase--release_retention_policy))
-- `tentacle_retention_policy` (List of Object) (see [below for nested schema](#nestedobjatt--lifecycles--phase--tentacle_retention_policy))
+- `automatic_deployment_targets` (List of String) The automatic deployment targets for this phase.
+- `id` (String) The ID of the phase.
+- `is_optional_phase` (Boolean) Whether this phase is optional.
+- `minimum_environments_before_promotion` (Number) The minimum number of environments before promotion.
+- `name` (String) The name of the phase.
+- `optional_deployment_targets` (List of String) The optional deployment targets for this phase.
+- `release_retention_policy` (Attributes List) (see [below for nested schema](#nestedatt--lifecycles--phase--release_retention_policy))
+- `tentacle_retention_policy` (Attributes List) (see [below for nested schema](#nestedatt--lifecycles--phase--tentacle_retention_policy))
-
+
### Nested Schema for `lifecycles.phase.release_retention_policy`
Read-Only:
-- `quantity_to_keep` (Number)
-- `should_keep_forever` (Boolean)
-- `unit` (String)
+- `quantity_to_keep` (Number) The quantity of releases to keep.
+- `should_keep_forever` (Boolean) Whether releases should be kept forever.
+- `unit` (String) The unit of time for the retention policy.
-
+
### Nested Schema for `lifecycles.phase.tentacle_retention_policy`
Read-Only:
-- `quantity_to_keep` (Number)
-- `should_keep_forever` (Boolean)
-- `unit` (String)
+- `quantity_to_keep` (Number) The quantity of releases to keep.
+- `should_keep_forever` (Boolean) Whether releases should be kept forever.
+- `unit` (String) The unit of time for the retention policy.
@@ -90,9 +90,9 @@ Read-Only:
Read-Only:
-- `quantity_to_keep` (Number)
-- `should_keep_forever` (Boolean)
-- `unit` (String)
+- `quantity_to_keep` (Number) The quantity of releases to keep.
+- `should_keep_forever` (Boolean) Whether releases should be kept forever.
+- `unit` (String) The unit of time for the retention policy.
@@ -100,8 +100,8 @@ Read-Only:
Read-Only:
-- `quantity_to_keep` (Number)
-- `should_keep_forever` (Boolean)
-- `unit` (String)
+- `quantity_to_keep` (Number) The quantity of releases to keep.
+- `should_keep_forever` (Boolean) Whether releases should be kept forever.
+- `unit` (String) The unit of time for the retention policy.
diff --git a/docs/resources/git_credential.md b/docs/resources/git_credential.md
index e47402fa1..ad9aa4392 100644
--- a/docs/resources/git_credential.md
+++ b/docs/resources/git_credential.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_git_credential Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
- This resource manages Git credentials in Octopus Deploy.
+ Manages a Git credential in Octopus Deploy.
---
# octopusdeploy_git_credential (Resource)
-This resource manages Git credentials in Octopus Deploy.
+Manages a Git credential in Octopus Deploy.
@@ -17,15 +17,15 @@ This resource manages Git credentials in Octopus Deploy.
### Required
-- `name` (String) The name of the Git credential. This name must be unique.
+- `name` (String) The name of this Git Credential.
- `password` (String, Sensitive) The password for the Git credential.
- `username` (String) The username for the Git credential.
### Optional
-- `description` (String) The description of this Git credential.
+- `description` (String) The description of this Git Credential.
- `id` (String) The unique ID for this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this Git Credential.
- `type` (String) The Git credential authentication type.
diff --git a/docs/resources/lifecycle.md b/docs/resources/lifecycle.md
index a367cce62..8714ab06e 100644
--- a/docs/resources/lifecycle.md
+++ b/docs/resources/lifecycle.md
@@ -33,8 +33,8 @@ resource "octopusdeploy_lifecycle" "example" {
name = "foo"
release_retention_policy {
- quantity_to_keep = 0
- should_keep_forever = true
+ quantity_to_keep = 0
+ should_keep_forever = true // true only if quantity_to_keep = 0
unit = "Days"
}
@@ -64,10 +64,10 @@ resource "octopusdeploy_lifecycle" "example" {
- `description` (String) The description of this lifecycle.
- `id` (String) The unique ID for this resource.
-- `phase` (Block List) (see [below for nested schema](#nestedblock--phase))
-- `release_retention_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--release_retention_policy))
+- `phase` (Block List) Defines a phase in the lifecycle. (see [below for nested schema](#nestedblock--phase))
+- `release_retention_policy` (Block List) Defines the retention policy for releases or tentacles. (see [below for nested schema](#nestedblock--release_retention_policy))
- `space_id` (String) The space ID associated with this resource.
-- `tentacle_retention_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--tentacle_retention_policy))
+- `tentacle_retention_policy` (Block List) Defines the retention policy for releases or tentacles. (see [below for nested schema](#nestedblock--tentacle_retention_policy))
### Nested Schema for `phase`
@@ -83,17 +83,17 @@ Optional:
- `is_optional_phase` (Boolean) If false a release must be deployed to this phase before it can be deployed to the next phase.
- `minimum_environments_before_promotion` (Number) The number of units required before a release can enter the next phase. If 0, all environments are required.
- `optional_deployment_targets` (List of String) Environment IDs in this phase that a release can be deployed to, but is not automatically deployed to
-- `release_retention_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--phase--release_retention_policy))
-- `tentacle_retention_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--phase--tentacle_retention_policy))
+- `release_retention_policy` (Block List) Defines the retention policy for releases or tentacles. (see [below for nested schema](#nestedblock--phase--release_retention_policy))
+- `tentacle_retention_policy` (Block List) Defines the retention policy for releases or tentacles. (see [below for nested schema](#nestedblock--phase--tentacle_retention_policy))
### Nested Schema for `phase.release_retention_policy`
Optional:
-- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is `30`. If `0` then all are kept.
-- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is `false`.
-- `unit` (String) The unit of quantity to keep. Valid units are `Days` or `Items`. The default value is `Days`.
+- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is 30. If 0 then all are kept.
+- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is false.
+- `unit` (String) The unit of quantity to keep. Valid units are Days or Items. The default value is Days.
@@ -101,9 +101,9 @@ Optional:
Optional:
-- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is `30`. If `0` then all are kept.
-- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is `false`.
-- `unit` (String) The unit of quantity to keep. Valid units are `Days` or `Items`. The default value is `Days`.
+- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is 30. If 0 then all are kept.
+- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is false.
+- `unit` (String) The unit of quantity to keep. Valid units are Days or Items. The default value is Days.
@@ -112,9 +112,9 @@ Optional:
Optional:
-- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is `30`. If `0` then all are kept.
-- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is `false`.
-- `unit` (String) The unit of quantity to keep. Valid units are `Days` or `Items`. The default value is `Days`.
+- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is 30. If 0 then all are kept.
+- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is false.
+- `unit` (String) The unit of quantity to keep. Valid units are Days or Items. The default value is Days.
@@ -122,9 +122,9 @@ Optional:
Optional:
-- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is `30`. If `0` then all are kept.
-- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is `false`.
-- `unit` (String) The unit of quantity to keep. Valid units are `Days` or `Items`. The default value is `Days`.
+- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is 30. If 0 then all are kept.
+- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is false.
+- `unit` (String) The unit of quantity to keep. Valid units are Days or Items. The default value is Days.
## Import
diff --git a/docs/resources/tenant_project_variable.md b/docs/resources/tenant_project_variable.md
index c27b1afae..053b6739a 100644
--- a/docs/resources/tenant_project_variable.md
+++ b/docs/resources/tenant_project_variable.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_tenant_project_variable Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
- This resource manages tenant project variables in Octopus Deploy.
+ Manages a tenant project variable in Octopus Deploy.
---
# octopusdeploy_tenant_project_variable (Resource)
-This resource manages tenant project variables in Octopus Deploy.
+Manages a tenant project variable in Octopus Deploy.
@@ -17,18 +17,18 @@ This resource manages tenant project variables in Octopus Deploy.
### Required
-- `environment_id` (String)
-- `project_id` (String)
-- `template_id` (String)
-- `tenant_id` (String)
+- `environment_id` (String) The ID of the environment.
+- `project_id` (String) The ID of the project.
+- `template_id` (String) The ID of the variable template.
+- `tenant_id` (String) The ID of the tenant.
### Optional
-- `space_id` (String)
-- `value` (String, Sensitive)
+- `space_id` (String) The space ID associated with this Tenant Project Variable.
+- `value` (String, Sensitive) The value of the variable.
### Read-Only
-- `id` (String) The ID of this resource.
+- `id` (String) The unique ID for this resource.
diff --git a/octopusdeploy_framework/datasource_git_credentials.go b/octopusdeploy_framework/datasource_git_credentials.go
index 210c7d83b..5dc1592c3 100644
--- a/octopusdeploy_framework/datasource_git_credentials.go
+++ b/octopusdeploy_framework/datasource_git_credentials.go
@@ -8,7 +8,6 @@ import (
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/datasource"
- "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"time"
)
@@ -35,6 +34,7 @@ type GitCredentialModel struct {
Description types.String `tfsdk:"description"`
Type types.String `tfsdk:"type"`
Username types.String `tfsdk:"username"`
+ Password types.String `tfsdk:"password"`
}
func NewGitCredentialsDataSource() datasource.DataSource {
@@ -46,10 +46,7 @@ func (g *gitCredentialsDataSource) Metadata(_ context.Context, req datasource.Me
}
func (g *gitCredentialsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
- resp.Schema = schema.Schema{
- Description: "A list of Git Credentials that match the filter(s).",
- Attributes: schemas.GetGitCredentialDataSourceSchema(),
- }
+ resp.Schema = schemas.GetGitCredentialDataSourceSchema()
}
func (g *gitCredentialsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
@@ -102,6 +99,7 @@ func GetGitCredentialAttrTypes() map[string]attr.Type {
"description": types.StringType,
"type": types.StringType,
"username": types.StringType,
+ "password": types.StringType,
}
}
diff --git a/octopusdeploy_framework/schemas/gitCredential.go b/octopusdeploy_framework/schemas/gitCredential.go
index 594f927b1..c4b0b4d6f 100644
--- a/octopusdeploy_framework/schemas/gitCredential.go
+++ b/octopusdeploy_framework/schemas/gitCredential.go
@@ -5,59 +5,55 @@ import (
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
datasourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/schema/validator"
)
const (
- GitCredentialResourceDescription = "Git Credential"
- GitCredentialResourceName = "git_credential"
- GitCredentialDatasourceName = "git_credentials"
+ GitCredentialResourceName = "git_credential"
+ GitCredentialDatasourceName = "git_credentials"
)
func GetGitCredentialResourceSchema() resourceSchema.Schema {
return resourceSchema.Schema{
Description: "Manages a Git credential in Octopus Deploy.",
Attributes: map[string]resourceSchema.Attribute{
- "id": util.GetIdResourceSchema(),
- "space_id": util.GetSpaceIdResourceSchema(GitCredentialResourceDescription),
- "name": util.GetNameResourceSchema(true),
- "description": util.GetDescriptionResourceSchema(GitCredentialResourceDescription),
- "type": resourceSchema.StringAttribute{
- Optional: true,
- Description: "The Git credential authentication type.",
- },
- "username": resourceSchema.StringAttribute{
- Required: true,
- Description: "The username for the Git credential.",
- Validators: []validator.String{
- stringvalidator.LengthAtLeast(1),
- },
- },
- "password": resourceSchema.StringAttribute{
- Required: true,
- Sensitive: true,
- Description: "The password for the Git credential.",
- Validators: []validator.String{
- stringvalidator.LengthAtLeast(1),
- },
- },
+ "id": util.ResourceString().Optional().Computed().Description("The unique ID for this resource.").Build(),
+ "space_id": util.ResourceString().Optional().Computed().Description("The space ID associated with this Git Credential.").Build(),
+ "name": util.ResourceString().Required().Description("The name of this Git Credential.").Build(),
+ "description": util.ResourceString().Optional().Description("The description of this Git Credential.").Build(),
+ "type": util.ResourceString().
+ Optional().
+ Description("The Git credential authentication type.").
+ Build(),
+ "username": util.ResourceString().
+ Required().
+ Description("The username for the Git credential.").
+ Validators(stringvalidator.LengthAtLeast(1)).
+ Build(),
+ "password": util.ResourceString().
+ Required().
+ Sensitive().
+ Description("The password for the Git credential.").
+ Validators(stringvalidator.LengthAtLeast(1)).
+ Build(),
},
}
}
-func GetGitCredentialDataSourceSchema() map[string]datasourceSchema.Attribute {
- return map[string]datasourceSchema.Attribute{
- "id": util.GetIdDatasourceSchema(),
- "space_id": util.GetSpaceIdDatasourceSchema(GitCredentialResourceDescription),
- "name": util.GetQueryNameDatasourceSchema(),
- "skip": util.GetQuerySkipDatasourceSchema(),
- "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(),
+func GetGitCredentialDataSourceSchema() datasourceSchema.Schema {
+ return datasourceSchema.Schema{
+ Description: "Use this data source to retrieve information about Git credentials in Octopus Deploy.",
+ Attributes: map[string]datasourceSchema.Attribute{
+ "id": util.DataSourceString().Computed().Description("The unique ID for this resource.").Build(),
+ "space_id": util.DataSourceString().Optional().Description("The space ID associated with this Git Credential.").Build(),
+ "name": util.DataSourceString().Optional().Description("The name of the Git Credential to filter by.").Build(),
+ "skip": util.DataSourceInt64().Optional().Description("The number of records to skip.").Build(),
+ "take": util.DataSourceInt64().Optional().Description("The number of records to take.").Build(),
+ "git_credentials": datasourceSchema.ListNestedAttribute{
+ Computed: true,
+ Description: "Provides information about existing GitCredentials.",
+ NestedObject: datasourceSchema.NestedAttributeObject{
+ Attributes: GetGitCredentialAttributes(),
+ },
},
},
}
@@ -65,17 +61,12 @@ func GetGitCredentialDataSourceSchema() map[string]datasourceSchema.Attribute {
func GetGitCredentialAttributes() map[string]datasourceSchema.Attribute {
return map[string]datasourceSchema.Attribute{
- "id": util.GetIdDatasourceSchema(),
- "space_id": util.GetSpaceIdDatasourceSchema(GitCredentialResourceDescription),
- "name": util.GetQueryNameDatasourceSchema(),
- "description": util.GetDescriptionDatasourceSchema(GitCredentialResourceDescription),
- "type": datasourceSchema.StringAttribute{
- Computed: true,
- Description: "The Git credential authentication type.",
- },
- "username": datasourceSchema.StringAttribute{
- Computed: true,
- Description: "The username for the Git credential.",
- },
+ "id": util.DataSourceString().Computed().Description("The unique ID for this resource.").Build(),
+ "space_id": util.DataSourceString().Computed().Description("The space ID associated with this Git Credential.").Build(),
+ "name": util.DataSourceString().Computed().Description("The name of this Git Credential.").Build(),
+ "description": util.DataSourceString().Computed().Description("The description of this Git Credential.").Build(),
+ "type": util.DataSourceString().Computed().Description("The Git credential authentication type.").Build(),
+ "username": util.DataSourceString().Computed().Description("The username for the Git credential.").Build(),
+ "password": util.DataSourceString().Computed().Sensitive().Description("The password for the Git credential.").Build(),
}
}
diff --git a/octopusdeploy_framework/schemas/lifecycle.go b/octopusdeploy_framework/schemas/lifecycle.go
index 04f7f493a..ba28f35b9 100644
--- a/octopusdeploy_framework/schemas/lifecycle.go
+++ b/octopusdeploy_framework/schemas/lifecycle.go
@@ -7,16 +7,18 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
)
func GetResourceLifecycleSchema() resourceSchema.Schema {
return resourceSchema.Schema{
+ Description: "This resource manages lifecycles in Octopus Deploy.",
Attributes: map[string]resourceSchema.Attribute{
- "id": util.GetIdResourceSchema(),
- "space_id": util.GetSpaceIdResourceSchema("lifecycle"),
- "name": util.GetNameResourceSchema(true),
- "description": util.GetDescriptionResourceSchema("lifecycle"),
+ "id": util.ResourceString().Optional().Computed().Description("The unique ID for this resource.").PlanModifiers(stringplanmodifier.UseStateForUnknown()).Build(),
+ "space_id": util.ResourceString().Optional().Computed().Description("The space ID associated with this resource.").PlanModifiers(stringplanmodifier.UseStateForUnknown()).Build(),
+ "name": util.ResourceString().Required().Description("The name of this resource.").Build(),
+ "description": util.ResourceString().Optional().Computed().Default("").Description("The description of this lifecycle.").Build(),
},
Blocks: map[string]resourceSchema.Block{
"phase": getResourcePhaseBlockSchema(),
@@ -28,30 +30,29 @@ func GetResourceLifecycleSchema() resourceSchema.Schema {
func getResourcePhaseBlockSchema() resourceSchema.ListNestedBlock {
return resourceSchema.ListNestedBlock{
+ Description: "Defines a phase in the lifecycle.",
NestedObject: resourceSchema.NestedBlockObject{
Attributes: map[string]resourceSchema.Attribute{
- "id": util.GetIdResourceSchema(),
- "name": util.GetNameResourceSchema(true),
- "automatic_deployment_targets": resourceSchema.ListAttribute{
- ElementType: types.StringType,
- Optional: true,
- Computed: true,
- },
- "optional_deployment_targets": resourceSchema.ListAttribute{
- ElementType: types.StringType,
- Optional: true,
- Computed: true,
- },
- "minimum_environments_before_promotion": resourceSchema.Int64Attribute{
- Optional: true,
- Computed: true,
- Default: int64default.StaticInt64(0),
- },
- "is_optional_phase": resourceSchema.BoolAttribute{
- Optional: true,
- Computed: true,
- Default: booldefault.StaticBool(false),
- },
+ "id": util.ResourceString().Optional().Computed().Description("The unique ID for this resource.").Build(),
+ "name": util.ResourceString().Required().Description("The name of this resource.").Build(),
+ "automatic_deployment_targets": util.ResourceList(types.StringType).
+ Optional().Computed().
+ Description("Environment IDs in this phase that a release is automatically deployed to when it is eligible for this phase").
+ Build(),
+ "optional_deployment_targets": util.ResourceList(types.StringType).
+ Optional().Computed().
+ Description("Environment IDs in this phase that a release can be deployed to, but is not automatically deployed to").
+ Build(),
+ "minimum_environments_before_promotion": util.ResourceInt64().
+ Optional().Computed().
+ Default(int64default.StaticInt64(0)).
+ Description("The number of units required before a release can enter the next phase. If 0, all environments are required.").
+ Build(),
+ "is_optional_phase": util.ResourceBool().
+ Optional().Computed().
+ Default(booldefault.StaticBool(false)).
+ Description("If false a release must be deployed to this phase before it can be deployed to the next phase.").
+ Build(),
},
Blocks: map[string]resourceSchema.Block{
"release_retention_policy": getResourceRetentionPolicyBlockSchema(),
@@ -63,83 +64,87 @@ func getResourcePhaseBlockSchema() resourceSchema.ListNestedBlock {
func getResourceRetentionPolicyBlockSchema() resourceSchema.ListNestedBlock {
return resourceSchema.ListNestedBlock{
+ Description: "Defines the retention policy for releases or tentacles.",
NestedObject: resourceSchema.NestedBlockObject{
Attributes: map[string]resourceSchema.Attribute{
- "quantity_to_keep": resourceSchema.Int64Attribute{
- Optional: true,
- Computed: true,
- Default: int64default.StaticInt64(30),
- },
- "should_keep_forever": resourceSchema.BoolAttribute{
- Optional: true,
- Computed: true,
- Default: booldefault.StaticBool(false),
- },
- "unit": resourceSchema.StringAttribute{
- Optional: true,
- Computed: true,
- Default: stringdefault.StaticString("Days"),
- },
+ "quantity_to_keep": util.ResourceInt64().
+ Optional().Computed().
+ Default(int64default.StaticInt64(30)).
+ Description("The number of days/releases to keep. The default value is 30. If 0 then all are kept.").
+ Build(),
+ "should_keep_forever": util.ResourceBool().
+ Optional().Computed().
+ Default(booldefault.StaticBool(false)).
+ Description("Indicates if items should never be deleted. The default value is false.").
+ Build(),
+ "unit": util.ResourceString().
+ Optional().Computed().
+ Default(stringdefault.StaticString("Days")).
+ Description("The unit of quantity to keep. Valid units are Days or Items. The default value is Days.").
+ Build(),
},
},
}
}
func GetDatasourceLifecycleSchema() datasourceSchema.Schema {
- description := "lifecycle"
return datasourceSchema.Schema{
+ Description: "Provides information about existing lifecycles.",
Attributes: map[string]datasourceSchema.Attribute{
- "id": util.GetIdDatasourceSchema(),
- "space_id": util.GetSpaceIdDatasourceSchema(description),
- "ids": util.GetQueryIDsDatasourceSchema(),
- "partial_name": util.GetQueryPartialNameDatasourceSchema(),
- "skip": util.GetQuerySkipDatasourceSchema(),
- "take": util.GetQueryTakeDatasourceSchema(),
- "lifecycles": datasourceSchema.ListNestedAttribute{
- Computed: true,
- Optional: false,
- NestedObject: datasourceSchema.NestedAttributeObject{
- Attributes: map[string]datasourceSchema.Attribute{
- "id": util.GetIdDatasourceSchema(),
- "space_id": util.GetSpaceIdDatasourceSchema(description),
- "name": util.GetNameDatasourceSchema(true),
- "description": util.GetDescriptionDatasourceSchema(description),
- "phase": getDatasourcePhasesSchema(),
- "release_retention_policy": getDatasourceRetentionPolicySchema(),
- "tentacle_retention_policy": getDatasourceRetentionPolicySchema(),
- },
- },
+ "id": util.DataSourceString().Computed().Description("The ID of the lifecycle.").Build(),
+ "space_id": util.DataSourceString().Optional().Description("The space ID associated with this lifecycle.").Build(),
+ "ids": util.DataSourceList(types.StringType).Optional().Description("A list of lifecycle IDs to filter by.").Build(),
+ "partial_name": util.DataSourceString().Optional().Description("A partial name to filter lifecycles by.").Build(),
+ "skip": util.DataSourceInt64().Optional().Description("A filter to specify the number of items to skip in the response.").Build(),
+ "take": util.DataSourceInt64().Optional().Description("A filter to specify the number of items to take (or return) in the response.").Build(),
+ "lifecycles": getLifecyclesAttribute(),
+ },
+ }
+}
+
+func getLifecyclesAttribute() datasourceSchema.ListNestedAttribute {
+ return datasourceSchema.ListNestedAttribute{
+ Computed: true,
+ NestedObject: datasourceSchema.NestedAttributeObject{
+ Attributes: map[string]datasourceSchema.Attribute{
+ "id": util.DataSourceString().Computed().Description("The ID of the lifecycle.").Build(),
+ "space_id": util.DataSourceString().Computed().Description("The space ID associated with this lifecycle.").Build(),
+ "name": util.DataSourceString().Computed().Description("The name of the lifecycle.").Build(),
+ "description": util.DataSourceString().Computed().Description("The description of the lifecycle.").Build(),
+ "phase": getPhasesAttribute(),
+ "release_retention_policy": getRetentionPolicyAttribute(),
+ "tentacle_retention_policy": getRetentionPolicyAttribute(),
},
},
}
}
-func getDatasourcePhasesSchema() datasourceSchema.ListNestedAttribute {
+func getPhasesAttribute() datasourceSchema.ListNestedAttribute {
return datasourceSchema.ListNestedAttribute{
Computed: true,
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: map[string]datasourceSchema.Attribute{
- "id": util.GetIdDatasourceSchema(),
- "name": util.GetNameDatasourceSchema(true),
- "automatic_deployment_targets": datasourceSchema.ListAttribute{ElementType: types.StringType, Computed: true},
- "optional_deployment_targets": datasourceSchema.ListAttribute{ElementType: types.StringType, Computed: true},
- "minimum_environments_before_promotion": datasourceSchema.Int64Attribute{Computed: true},
- "is_optional_phase": datasourceSchema.BoolAttribute{Computed: true},
- "release_retention_policy": getDatasourceRetentionPolicySchema(),
- "tentacle_retention_policy": getDatasourceRetentionPolicySchema(),
+ "id": util.DataSourceString().Computed().Description("The ID of the phase.").Build(),
+ "name": util.DataSourceString().Computed().Description("The name of the phase.").Build(),
+ "automatic_deployment_targets": util.DataSourceList(types.StringType).Computed().Description("The automatic deployment targets for this phase.").Build(),
+ "optional_deployment_targets": util.DataSourceList(types.StringType).Computed().Description("The optional deployment targets for this phase.").Build(),
+ "minimum_environments_before_promotion": util.DataSourceInt64().Computed().Description("The minimum number of environments before promotion.").Build(),
+ "is_optional_phase": util.DataSourceBool().Computed().Description("Whether this phase is optional.").Build(),
+ "release_retention_policy": getRetentionPolicyAttribute(),
+ "tentacle_retention_policy": getRetentionPolicyAttribute(),
},
},
}
}
-func getDatasourceRetentionPolicySchema() datasourceSchema.ListNestedAttribute {
+func getRetentionPolicyAttribute() datasourceSchema.ListNestedAttribute {
return datasourceSchema.ListNestedAttribute{
Computed: true,
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: map[string]datasourceSchema.Attribute{
- "quantity_to_keep": datasourceSchema.Int64Attribute{Computed: true},
- "should_keep_forever": datasourceSchema.BoolAttribute{Computed: true},
- "unit": datasourceSchema.StringAttribute{Computed: true},
+ "quantity_to_keep": util.DataSourceInt64().Computed().Description("The quantity of releases to keep.").Build(),
+ "should_keep_forever": util.DataSourceBool().Computed().Description("Whether releases should be kept forever.").Build(),
+ "unit": util.DataSourceString().Computed().Description("The unit of time for the retention policy.").Build(),
},
},
}
diff --git a/octopusdeploy_framework/schemas/tenant_project_variable.go b/octopusdeploy_framework/schemas/tenant_project_variable.go
index 99553e7c6..4e681a99e 100644
--- a/octopusdeploy_framework/schemas/tenant_project_variable.go
+++ b/octopusdeploy_framework/schemas/tenant_project_variable.go
@@ -3,6 +3,7 @@ package schemas
import (
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
)
const (
@@ -14,17 +15,38 @@ func GetTenantProjectVariableResourceSchema() schema.Schema {
return schema.Schema{
Description: "Manages a tenant project variable in Octopus Deploy.",
Attributes: map[string]schema.Attribute{
- "id": util.GetIdResourceSchema(),
- "space_id": util.GetSpaceIdResourceSchema(TenantProjectVariableResourceDescription),
- "tenant_id": util.GetRequiredStringResourceSchema("The ID of the tenant."),
- "project_id": util.GetRequiredStringResourceSchema("The ID of the project."),
- "environment_id": util.GetRequiredStringResourceSchema("The ID of the environment."),
- "template_id": util.GetRequiredStringResourceSchema("The ID of the variable template."),
- "value": schema.StringAttribute{
- Required: true,
- Description: "The value of the variable.",
- Sensitive: true,
- },
+ "id": util.ResourceString().
+ Computed().
+ Description("The unique ID for this resource.").
+ PlanModifiers(stringplanmodifier.UseStateForUnknown()).
+ Build(),
+ "space_id": util.ResourceString().
+ Optional().
+ Computed().
+ Description("The space ID associated with this Tenant Project Variable.").
+ PlanModifiers(stringplanmodifier.UseStateForUnknown()).
+ Build(),
+ "tenant_id": util.ResourceString().
+ Required().
+ Description("The ID of the tenant.").
+ Build(),
+ "project_id": util.ResourceString().
+ Required().
+ Description("The ID of the project.").
+ Build(),
+ "environment_id": util.ResourceString().
+ Required().
+ Description("The ID of the environment.").
+ Build(),
+ "template_id": util.ResourceString().
+ Required().
+ Description("The ID of the variable template.").
+ Build(),
+ "value": util.ResourceString().
+ Optional().
+ Sensitive().
+ Description("The value of the variable.").
+ Build(),
},
}
}
diff --git a/octopusdeploy_framework/util/resource_attribute_builder.go b/octopusdeploy_framework/util/resource_attribute_builder.go
index 153cafbf7..908f07929 100644
--- a/octopusdeploy_framework/util/resource_attribute_builder.go
+++ b/octopusdeploy_framework/util/resource_attribute_builder.go
@@ -8,8 +8,10 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/mapdefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/setdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
@@ -217,6 +219,84 @@ func (b *AttributeBuilder[T]) Build() T {
return b.attr
}
+func (b *AttributeBuilder[T]) PlanModifiers(modifiers ...any) *AttributeBuilder[T] {
+ switch a := any(&b.attr).(type) {
+ case *schema.StringAttribute:
+ if stringModifiers, ok := convertToTypedSlice[planmodifier.String](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, stringModifiers...)
+ }
+ case *schema.BoolAttribute:
+ if boolModifiers, ok := convertToTypedSlice[planmodifier.Bool](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, boolModifiers...)
+ }
+ case *schema.Int64Attribute:
+ if int64Modifiers, ok := convertToTypedSlice[planmodifier.Int64](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, int64Modifiers...)
+ }
+ case *schema.Float64Attribute:
+ if float64Modifiers, ok := convertToTypedSlice[planmodifier.Float64](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, float64Modifiers...)
+ }
+ case *schema.ListAttribute:
+ if listModifiers, ok := convertToTypedSlice[planmodifier.List](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, listModifiers...)
+ }
+ case *schema.SetAttribute:
+ if setModifiers, ok := convertToTypedSlice[planmodifier.Set](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, setModifiers...)
+ }
+ case *schema.MapAttribute:
+ if mapModifiers, ok := convertToTypedSlice[planmodifier.Map](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, mapModifiers...)
+ }
+ }
+ return b
+}
+func (b *AttributeBuilder[T]) Validators(validators ...any) *AttributeBuilder[T] {
+ switch a := any(&b.attr).(type) {
+ case *schema.StringAttribute:
+ if stringValidators, ok := convertToTypedSlice[validator.String](validators); ok {
+ a.Validators = append(a.Validators, stringValidators...)
+ }
+ case *schema.BoolAttribute:
+ if boolValidators, ok := convertToTypedSlice[validator.Bool](validators); ok {
+ a.Validators = append(a.Validators, boolValidators...)
+ }
+ case *schema.Int64Attribute:
+ if int64Validators, ok := convertToTypedSlice[validator.Int64](validators); ok {
+ a.Validators = append(a.Validators, int64Validators...)
+ }
+ case *schema.Float64Attribute:
+ if float64Validators, ok := convertToTypedSlice[validator.Float64](validators); ok {
+ a.Validators = append(a.Validators, float64Validators...)
+ }
+ case *schema.ListAttribute:
+ if listValidators, ok := convertToTypedSlice[validator.List](validators); ok {
+ a.Validators = append(a.Validators, listValidators...)
+ }
+ case *schema.SetAttribute:
+ if setValidators, ok := convertToTypedSlice[validator.Set](validators); ok {
+ a.Validators = append(a.Validators, setValidators...)
+ }
+ case *schema.MapAttribute:
+ if mapValidators, ok := convertToTypedSlice[validator.Map](validators); ok {
+ a.Validators = append(a.Validators, mapValidators...)
+ }
+ }
+ return b
+}
+
+func convertToTypedSlice[T any](slice []any) ([]T, bool) {
+ typedSlice := make([]T, 0, len(slice))
+ for _, item := range slice {
+ if typed, ok := item.(T); ok {
+ typedSlice = append(typedSlice, typed)
+ } else {
+ return nil, false
+ }
+ }
+ return typedSlice, true
+}
func ResourceString() *AttributeBuilder[schema.StringAttribute] {
return NewAttributeBuilder[schema.StringAttribute]()
}