Skip to content

Commit

Permalink
Add recurring schedule to deployment freeze data source and add test
Browse files Browse the repository at this point in the history
  • Loading branch information
HuyPhanNguyen committed Dec 9, 2024
1 parent 9be2779 commit 11e25de
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 6 deletions.
17 changes: 17 additions & 0 deletions docs/data-sources/deployment_freezes.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,23 @@ Read-Only:
- `id` (String) The unique ID for this resource.
- `name` (String) The name of this resource.
- `project_environment_scope` (Map of List of String) The project environment scope of the deployment freeze
- `recurring_schedule` (Attributes) (see [below for nested schema](#nestedatt--deployment_freezes--recurring_schedule))
- `start` (String) The start time of the freeze

<a id="nestedatt--deployment_freezes--recurring_schedule"></a>
### Nested Schema for `deployment_freezes.recurring_schedule`

Read-Only:

- `date_of_month` (String) The date of the month for monthly schedules
- `day_number_of_month` (String) The day number of the month for monthly schedules
- `day_of_week` (String) The day of the week for monthly schedules
- `days_of_week` (List of String) List of days of the week for weekly schedules
- `end_after_occurrences` (Number) Number of occurrences after which the schedule should end
- `end_on_date` (String) The date when the recurring schedule should end
- `end_type` (String) When the recurring schedule should end (Never, OnDate, AfterOccurrences)
- `monthly_schedule_type` (String) Type of monthly schedule (DayOfMonth, DateOfMonth)
- `type` (String) Type of recurring schedule (OnceDaily, DaysPerWeek, DaysPerMonth, Annually)
- `unit` (Number) The unit value for the schedule


107 changes: 103 additions & 4 deletions octopusdeploy_framework/datasource_deployment_freeze.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,29 @@ import (

const deploymentFreezeDatasourceName = "deployment_freezes"

type deploymentFreezesModel struct {
type recurringScheduleDatasourceModel struct {
Type types.String `tfsdk:"type"`
Unit types.Int64 `tfsdk:"unit"`
EndType types.String `tfsdk:"end_type"`
EndOnDate types.String `tfsdk:"end_on_date"`
EndAfterOccurrences types.Int64 `tfsdk:"end_after_occurrences"`
MonthlyScheduleType types.String `tfsdk:"monthly_schedule_type"`
DateOfMonth types.String `tfsdk:"date_of_month"`
DayNumberOfMonth types.String `tfsdk:"day_number_of_month"`
DaysOfWeek types.List `tfsdk:"days_of_week"`
DayOfWeek types.String `tfsdk:"day_of_week"`
}

type deploymentFreezeDatasourceModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Start types.String `tfsdk:"start"`
End types.String `tfsdk:"end"`
ProjectEnvironmentScope types.Map `tfsdk:"project_environment_scope"`
RecurringSchedule *recurringScheduleDatasourceModel `tfsdk:"recurring_schedule"`
}

type deploymentFreezesDatasourceModel struct {
ID types.String `tfsdk:"id"`
IDs types.List `tfsdk:"ids"`
PartialName types.String `tfsdk:"partial_name"`
Expand Down Expand Up @@ -48,7 +70,7 @@ func (d *deploymentFreezeDataSource) Schema(ctx context.Context, req datasource.
}

func (d *deploymentFreezeDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data deploymentFreezesModel
var data deploymentFreezesDatasourceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
Expand Down Expand Up @@ -102,13 +124,89 @@ func mapFreezeToAttribute(ctx context.Context, freeze deploymentfreezes.Deployme
return nil, diags
}

return types.ObjectValueMust(freezeObjectType(), map[string]attr.Value{
attrs := map[string]attr.Value{
"id": types.StringValue(freeze.ID),
"name": types.StringValue(freeze.Name),
"start": types.StringValue(freeze.Start.Format(time.RFC3339)),
"end": types.StringValue(freeze.End.Format(time.RFC3339)),
"project_environment_scope": scopeType,
}), diags
}

if freeze.RecurringSchedule != nil {
daysOfWeek, diags := types.ListValueFrom(ctx, types.StringType, freeze.RecurringSchedule.DaysOfWeek)
if diags.HasError() {
return nil, diags
}

endOnDate := types.StringNull()
if freeze.RecurringSchedule.EndOnDate != nil {
endOnDate = types.StringValue(freeze.RecurringSchedule.EndOnDate.Format(time.RFC3339))
}

endAfterOccurrences := types.Int64Null()
if freeze.RecurringSchedule.EndAfterOccurrences != nil {
endAfterOccurrences = types.Int64Value(int64(*freeze.RecurringSchedule.EndAfterOccurrences))
}

monthlyScheduleType := types.StringNull()
if freeze.RecurringSchedule.MonthlyScheduleType != "" {
monthlyScheduleType = types.StringValue(freeze.RecurringSchedule.MonthlyScheduleType)
}

dateOfMonth := types.StringNull()
if freeze.RecurringSchedule.DateOfMonth != nil {
dateOfMonth = types.StringValue(*freeze.RecurringSchedule.DateOfMonth)
}

dayNumberOfMonth := types.StringNull()
if freeze.RecurringSchedule.DayNumberOfMonth != nil {
dayNumberOfMonth = types.StringValue(*freeze.RecurringSchedule.DayNumberOfMonth)
}

dayOfWeek := types.StringNull()
if freeze.RecurringSchedule.DayOfWeek != nil {
dayOfWeek = types.StringValue(*freeze.RecurringSchedule.DayOfWeek)
}

scheduleAttrs := map[string]attr.Value{
"type": types.StringValue(string(freeze.RecurringSchedule.Type)),
"unit": types.Int64Value(int64(freeze.RecurringSchedule.Unit)),
"end_type": types.StringValue(string(freeze.RecurringSchedule.EndType)),
"end_on_date": endOnDate,
"end_after_occurrences": endAfterOccurrences,
"monthly_schedule_type": monthlyScheduleType,
"date_of_month": dateOfMonth,
"day_number_of_month": dayNumberOfMonth,
"days_of_week": daysOfWeek,
"day_of_week": dayOfWeek,
}

recurringSchedule, diags := types.ObjectValue(freezeRecurringScheduleObjectType(), scheduleAttrs)
if diags.HasError() {
return nil, diags
}

attrs["recurring_schedule"] = recurringSchedule
} else {
attrs["recurring_schedule"] = types.ObjectNull(freezeRecurringScheduleObjectType())
}

return types.ObjectValueMust(freezeObjectType(), attrs), diags
}

func freezeRecurringScheduleObjectType() map[string]attr.Type {
return map[string]attr.Type{
"type": types.StringType,
"unit": types.Int64Type,
"end_type": types.StringType,
"end_on_date": types.StringType,
"end_after_occurrences": types.Int64Type,
"monthly_schedule_type": types.StringType,
"date_of_month": types.StringType,
"day_number_of_month": types.StringType,
"days_of_week": types.ListType{ElemType: types.StringType},
"day_of_week": types.StringType,
}
}

func freezeObjectType() map[string]attr.Type {
Expand All @@ -118,5 +216,6 @@ func freezeObjectType() map[string]attr.Type {
"start": types.StringType,
"end": types.StringType,
"project_environment_scope": types.MapType{ElemType: types.ListType{ElemType: types.StringType}},
"recurring_schedule": types.ObjectType{AttrTypes: freezeRecurringScheduleObjectType()},
}
}
90 changes: 90 additions & 0 deletions octopusdeploy_framework/datasource_deployment_freeze_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package octopusdeploy_framework

import (
"fmt"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"testing"
"time"
)

func TestAccDataSourceDeploymentFreezes(t *testing.T) {
spaceName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
freezeName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
resourceName := "data.octopusdeploy_deployment_freezes.test_freeze"

// Use future dates for the freeze period, ensuring UTC timezone
startTime := time.Now().AddDate(1, 0, 0).UTC()
endTime := startTime.Add(24 * time.Hour)

resource.Test(t, resource.TestCase{
PreCheck: func() { TestAccPreCheck(t) },
ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
Steps: []resource.TestStep{
{
Config: testAccDataSourceDeploymentFreezesConfig(spaceName, freezeName, startTime, endTime),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(resourceName, "id"),
resource.TestCheckResourceAttr(resourceName, "partial_name", freezeName),
resource.TestCheckResourceAttr(resourceName, "deployment_freezes.#", "1"),
resource.TestCheckResourceAttrSet(resourceName, "deployment_freezes.0.id"),
resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.name", freezeName),
resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.start", startTime.Format(time.RFC3339)),
resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.end", endTime.Format(time.RFC3339)),
resource.TestCheckResourceAttrSet(resourceName, "deployment_freezes.0.project_environment_scope.%"),
resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.recurring_schedule.type", "DaysPerWeek"),
resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.recurring_schedule.unit", "24"),
resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.recurring_schedule.end_type", "AfterOccurrences"),
resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.recurring_schedule.end_after_occurrences", "5"),
resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.recurring_schedule.days_of_week.#", "3"),
testAccCheckOutputExists("octopus_space_id"),
testAccCheckOutputExists("octopus_freeze_id"),
),
},
},
})
}

func testAccDataSourceDeploymentFreezesConfig(spaceName, freezeName string, startTime, endTime time.Time) string {
return fmt.Sprintf(`
resource "octopusdeploy_space" "test_space" {
name = "%s"
is_default = false
is_task_queue_stopped = false
description = "Test space for deployment freeze datasource"
space_managers_teams = ["teams-administrators"]
}
resource "octopusdeploy_deployment_freeze" "test_freeze" {
name = "%s"
start = "%s"
end = "%s"
recurring_schedule = {
type = "DaysPerWeek"
unit = 24
end_type = "AfterOccurrences"
end_after_occurrences = 5
days_of_week = ["Monday", "Wednesday", "Friday"]
}
depends_on = [octopusdeploy_space.test_space]
}
data "octopusdeploy_deployment_freezes" "test_freeze" {
ids = null
partial_name = "%s"
skip = 0
take = 1
depends_on = [octopusdeploy_deployment_freeze.test_freeze]
}
output "octopus_space_id" {
value = octopusdeploy_space.test_space.id
}
output "octopus_freeze_id" {
value = data.octopusdeploy_deployment_freezes.test_freeze.deployment_freezes[0].id
}
`, spaceName, freezeName, startTime.Format(time.RFC3339), endTime.Format(time.RFC3339), freezeName)
}
49 changes: 47 additions & 2 deletions octopusdeploy_framework/schemas/deployment_freeze.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ func (d DeploymentFreezeSchema) GetResourceSchema() resourceSchema.Schema {
},
}
}

func (d DeploymentFreezeSchema) GetDatasourceSchema() datasourceSchema.Schema {
return datasourceSchema.Schema{
Description: "Provides information about deployment freezes",
Expand Down Expand Up @@ -107,14 +106,60 @@ func (d DeploymentFreezeSchema) GetDatasourceSchema() datasourceSchema.Schema {
Optional: false,
Computed: true,
},
"recurring_schedule": datasourceSchema.SingleNestedAttribute{
Computed: true,
Optional: false,
Attributes: map[string]datasourceSchema.Attribute{
"type": datasourceSchema.StringAttribute{
Description: "Type of recurring schedule (OnceDaily, DaysPerWeek, DaysPerMonth, Annually)",
Computed: true,
},
"unit": datasourceSchema.Int64Attribute{
Description: "The unit value for the schedule",
Computed: true,
},
"end_type": datasourceSchema.StringAttribute{
Description: "When the recurring schedule should end (Never, OnDate, AfterOccurrences)",
Computed: true,
},
"end_on_date": datasourceSchema.StringAttribute{
Description: "The date when the recurring schedule should end",
Computed: true,
},
"end_after_occurrences": datasourceSchema.Int64Attribute{
Description: "Number of occurrences after which the schedule should end",
Computed: true,
},
"monthly_schedule_type": datasourceSchema.StringAttribute{
Description: "Type of monthly schedule (DayOfMonth, DateOfMonth)",
Computed: true,
},
"date_of_month": datasourceSchema.StringAttribute{
Description: "The date of the month for monthly schedules",
Computed: true,
},
"day_number_of_month": datasourceSchema.StringAttribute{
Description: "The day number of the month for monthly schedules",
Computed: true,
},
"days_of_week": datasourceSchema.ListAttribute{
Description: "List of days of the week for weekly schedules",
Computed: true,
ElementType: types.StringType,
},
"day_of_week": datasourceSchema.StringAttribute{
Description: "The day of the week for monthly schedules",
Computed: true,
},
},
},
},
},
Optional: false,
Computed: true,
},
},
}

}

var _ EntitySchema = &DeploymentFreezeSchema{}

0 comments on commit 11e25de

Please sign in to comment.