From e4435282541ac767a2d92c0e2002407157ece6ae Mon Sep 17 00:00:00 2001 From: Mark DeCrane Date: Thu, 13 Jun 2024 12:31:27 -0400 Subject: [PATCH 1/3] Add CreatedBefore and CreatedAfter filters for admin runs list --- admin_run.go | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/admin_run.go b/admin_run.go index 4dc391326..adfac0378 100644 --- a/admin_run.go +++ b/admin_run.go @@ -61,8 +61,10 @@ const ( type AdminRunsListOptions struct { ListOptions - RunStatus string `url:"filter[status],omitempty"` - Query string `url:"q,omitempty"` + RunStatus string `url:"filter[status],omitempty"` + CreatedBefore string `url:"filter[to],omitempty"` + CreatedAfter string `url:"filter[from],omitempty"` + Query string `url:"q,omitempty"` // Optional: A list of relations to include. See available resources // https://developer.hashicorp.com/terraform/enterprise/api-docs/admin/runs#available-related-resources Include []AdminRunIncludeOpt `url:"include,omitempty"` @@ -123,6 +125,10 @@ func (o *AdminRunsListOptions) valid() error { return nil } + if err := validateAdminRunDateRanges(o.CreatedBefore, o.CreatedAfter); err != nil { + return err + } + if err := validateAdminRunFilterParams(o.RunStatus); err != nil { return err } @@ -130,6 +136,24 @@ func (o *AdminRunsListOptions) valid() error { return nil } +func validateAdminRunDateRanges(before, after string) error { + if validString(&before) { + _, err := time.Parse(time.RFC3339, before) + if err != nil { + return fmt.Errorf("invalid date format for CreatedBefore: '%s', must be in RFC3339 format", before) + } + } + + if validString(&after) { + _, err := time.Parse(time.RFC3339, after) + if err != nil { + return fmt.Errorf("invalid date format for CreatedAfter: '%s', must be in RFC3339 format", after) + } + } + + return nil +} + func validateAdminRunFilterParams(runStatus string) error { // For the platform, an invalid filter value is a semantically understood query that returns an empty set, no error, no warning. But for go-tfe, an invalid value is good enough reason to error prior to a network call to the platform: if validString(&runStatus) { From 0196d300c14a7ac512e2eec4f1b10c56a1b17761 Mon Sep 17 00:00:00 2001 From: Mark DeCrane Date: Thu, 13 Jun 2024 12:31:38 -0400 Subject: [PATCH 2/3] added tests --- admin_run_integration_test.go | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/admin_run_integration_test.go b/admin_run_integration_test.go index b52256099..183e585db 100644 --- a/admin_run_integration_test.go +++ b/admin_run_integration_test.go @@ -227,6 +227,60 @@ func TestAdminRuns_ForceCancel(t *testing.T) { }) } +func TestAdminRuns_ListFilterByDates(t *testing.T) { + skipUnlessEnterprise(t) + + client := testClient(t) + ctx := context.Background() + + org, orgCleanup := createOrganization(t, client) + defer orgCleanup() + + wTest, wTestCleanup := createWorkspace(t, client, org) + defer wTestCleanup() + + timestamp1 := time.Now().Format(time.RFC3339) + rTest1, rCleanup1 := createRun(t, client, wTest) + defer rCleanup1() + + rTest2, rCleanup2 := createRun(t, client, wTest) + defer rCleanup2() + timestamp2 := time.Now().Format(time.RFC3339) + + _, rCleanup3 := createRun(t, client, wTest) + defer rCleanup3() + timestamp3 := time.Now().Format(time.RFC3339) + + t.Run("has valid date ranges", func(t *testing.T) { + rl, err := client.Admin.Runs.List(ctx, &AdminRunsListOptions{ + CreatedAfter: timestamp1, + CreatedBefore: timestamp2, + }) + + require.NoError(t, err) + assert.Equal(t, 2, len(rl.Items)) + assert.Equal(t, adminRunItemsContainsID(rl.Items, rTest1.ID), true) + assert.Equal(t, adminRunItemsContainsID(rl.Items, rTest2.ID), true) + }) + + t.Run("has no items when CreatedAfter and CreatedBefore datetimes has no overlap", func(t *testing.T) { + rl, err := client.Admin.Runs.List(ctx, &AdminRunsListOptions{ + CreatedAfter: timestamp3, + CreatedBefore: timestamp2, + }) + + require.NoError(t, err) + assert.Equal(t, 0, len(rl.Items)) + }) + + t.Run("errors with invalid input for CreatedAfter", func(t *testing.T) { + _, err := client.Admin.Runs.List(ctx, &AdminRunsListOptions{ + CreatedAfter: "invalid", + }) + assert.Error(t, err) + }) +} + func TestAdminRuns_AdminRunsListOptions_valid(t *testing.T) { skipUnlessEnterprise(t) From 6128458d8bdf3e4e195b5b63dcd9a8f9c5b52cb0 Mon Sep 17 00:00:00 2001 From: Mark DeCrane Date: Mon, 17 Jun 2024 12:14:21 -0400 Subject: [PATCH 3/3] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index edf23d61a..c52d3f11c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Adds the `IsUnified` field to `Project`, `Organization` and `Team` by @roncodingenthusiast [#915](https://github.com/hashicorp/go-tfe/pull/915) * Adds Workspace auto-destroy notification types to `NotificationTriggerType` by @notchairmk [#918](https://github.com/hashicorp/go-tfe/pull/918) +* Adds `CreatedAfter` and `CreatedBefore` Date Time filters to `AdminRunsListOptions` by @maed223 [#916](https://github.com/hashicorp/go-tfe/pull/916) # v1.56.0