Skip to content

Commit f016306

Browse files
committed
Add support for listing Runs in an organization
1 parent d114b5d commit f016306

File tree

2 files changed

+202
-0
lines changed

2 files changed

+202
-0
lines changed

run.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ type Runs interface {
2121
// List all the runs of the given workspace.
2222
List(ctx context.Context, workspaceID string, options *RunListOptions) (*RunList, error)
2323

24+
// List all the runs of the given organization.
25+
ListForOrganization(ctx context.Context, organisation string, options *RunListForOrganizationOptions) (*RunList, error)
26+
2427
// Create a new run with the given options.
2528
Create(ctx context.Context, options RunCreateOptions) (*Run, error)
2629

@@ -250,6 +253,52 @@ type RunListOptions struct {
250253
Include []RunIncludeOpt `url:"include,omitempty"`
251254
}
252255

256+
// RunListForOrganizationOptions represents the options for listing runs for an organization.
257+
type RunListForOrganizationOptions struct {
258+
ListOptions
259+
260+
// Optional: Searches runs that matches the supplied VCS username.
261+
User string `url:"search[user],omitempty"`
262+
263+
// Optional: Searches runs that matches the supplied commit sha.
264+
Commit string `url:"search[commit],omitempty"`
265+
266+
// Optional: Searches for runs that match the VCS username, commit sha, run_id, or run message your specify.
267+
// The presence of search[commit] or search[user] takes priority over this parameter and will be omitted.
268+
Basic string `url:"search[basic],omitempty"`
269+
270+
// Optional: Comma-separated list of acceptable run statuses.
271+
// Options are listed at https://developer.hashicorp.com/terraform/cloud-docs/api-docs/run#run-states,
272+
// or as constants with the RunStatus string type.
273+
Status string `url:"filter[status],omitempty"`
274+
275+
// Optional: Comma-separated list of acceptable run sources.
276+
// Options are listed at https://developer.hashicorp.com/terraform/cloud-docs/api-docs/run#run-sources,
277+
// or as constants with the RunSource string type.
278+
Source string `url:"filter[source],omitempty"`
279+
280+
// Optional: Comma-separated list of acceptable run operation types.
281+
// Options are listed at https://developer.hashicorp.com/terraform/cloud-docs/api-docs/run#run-operations,
282+
// or as constants with the RunOperation string type.
283+
Operation string `url:"filter[operation],omitempty"`
284+
285+
// Optional: Comma-separated list of agent pool names.
286+
AgentPoolNames string `url:"filter[agent_pool_names],omitempty"`
287+
288+
// Optional: Comma-separated list of run status groups.
289+
StatusGroup string `url:"filter[status_group],omitempty"`
290+
291+
// Optional: Comma-separated list of run timeframe.
292+
Timeframe string `url:"filter[timeframe],omitempty"`
293+
294+
// Optional: Comma-separated list of workspace names. The result lists runs that belong to one of the workspaces your specify.
295+
WorkspaceNames string `url:"filter[workspace_names],omitempty"`
296+
297+
// Optional: A list of relations to include. See available resources:
298+
// https://developer.hashicorp.com/terraform/cloud-docs/api-docs/run#available-related-resources
299+
Include []RunIncludeOpt `url:"include,omitempty"`
300+
}
301+
253302
// RunReadOptions represents the options for reading a run.
254303
type RunReadOptions struct {
255304
// Optional: A list of relations to include. See available resources:
@@ -398,6 +447,30 @@ func (s *runs) List(ctx context.Context, workspaceID string, options *RunListOpt
398447
return rl, nil
399448
}
400449

450+
// List all the runs of the given workspace.
451+
func (s *runs) ListForOrganization(ctx context.Context, organization string, options *RunListForOrganizationOptions) (*RunList, error) {
452+
if !validStringID(&organization) {
453+
return nil, ErrInvalidOrg
454+
}
455+
if err := options.valid(); err != nil {
456+
return nil, err
457+
}
458+
459+
u := fmt.Sprintf("organizations/%s/runs", url.PathEscape(organization))
460+
req, err := s.client.NewRequest("GET", u, options)
461+
if err != nil {
462+
return nil, err
463+
}
464+
465+
rl := &RunList{}
466+
err = req.Do(ctx, rl)
467+
if err != nil {
468+
return nil, err
469+
}
470+
471+
return rl, nil
472+
}
473+
401474
// Create a new run with the given options.
402475
func (s *runs) Create(ctx context.Context, options RunCreateOptions) (*Run, error) {
403476
if err := options.valid(); err != nil {
@@ -546,3 +619,7 @@ func (o *RunReadOptions) valid() error {
546619
func (o *RunListOptions) valid() error {
547620
return nil
548621
}
622+
623+
func (o *RunListForOrganizationOptions) valid() error {
624+
return nil
625+
}

run_integration_test.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,3 +720,128 @@ func TestRunCreateOptions_Marshal(t *testing.T) {
720720

721721
assert.Equal(t, string(bodyBytes), expectedBody)
722722
}
723+
724+
func TestRunsListForOrganization(t *testing.T) {
725+
client := testClient(t)
726+
ctx := context.Background()
727+
728+
orgTest, orgTestCleanup := createOrganization(t, client)
729+
defer orgTestCleanup()
730+
731+
apTest, _ := createAgentPool(t, client, orgTest)
732+
733+
wTest, _ := createWorkspaceWithOptions(t, client, orgTest, WorkspaceCreateOptions{
734+
Name: String(randomString(t)),
735+
ExecutionMode: String("agent"),
736+
AgentPoolID: &apTest.ID,
737+
})
738+
rTest1, _ := createRun(t, client, wTest)
739+
rTest2, _ := createRun(t, client, wTest)
740+
741+
t.Run("without list options", func(t *testing.T) {
742+
rl, err := client.Runs.ListForOrganization(ctx, orgTest.Name, nil)
743+
require.NoError(t, err)
744+
745+
found := []string{}
746+
for _, r := range rl.Items {
747+
found = append(found, r.ID)
748+
}
749+
750+
assert.Contains(t, found, rTest1.ID)
751+
assert.Contains(t, found, rTest2.ID)
752+
assert.Equal(t, 1, rl.CurrentPage)
753+
assert.Equal(t, 2, rl.TotalCount)
754+
})
755+
756+
t.Run("without list options and include as nil", func(t *testing.T) {
757+
rl, err := client.Runs.ListForOrganization(ctx, orgTest.Name, &RunListForOrganizationOptions{
758+
Include: []RunIncludeOpt{},
759+
})
760+
require.NoError(t, err)
761+
require.NotEmpty(t, rl.Items)
762+
763+
found := []string{}
764+
for _, r := range rl.Items {
765+
found = append(found, r.ID)
766+
}
767+
768+
assert.Contains(t, found, rTest1.ID)
769+
assert.Contains(t, found, rTest2.ID)
770+
assert.Equal(t, 1, rl.CurrentPage)
771+
assert.Equal(t, 2, rl.TotalCount)
772+
})
773+
774+
t.Run("with list options", func(t *testing.T) {
775+
t.Skip("paging not supported yet in API")
776+
777+
// Request a page number which is out of range. The result should
778+
// be successful, but return no results if the paging options are
779+
// properly passed along.
780+
rl, err := client.Runs.ListForOrganization(ctx, orgTest.Name, &RunListForOrganizationOptions{
781+
ListOptions: ListOptions{
782+
PageNumber: 999,
783+
PageSize: 100,
784+
},
785+
})
786+
require.NoError(t, err)
787+
assert.Empty(t, rl.Items)
788+
assert.Equal(t, 999, rl.CurrentPage)
789+
assert.Equal(t, 2, rl.TotalCount)
790+
})
791+
792+
t.Run("with workspace included", func(t *testing.T) {
793+
rl, err := client.Runs.ListForOrganization(ctx, orgTest.Name, &RunListForOrganizationOptions{
794+
Include: []RunIncludeOpt{RunWorkspace},
795+
})
796+
require.NoError(t, err)
797+
798+
require.NotEmpty(t, rl.Items)
799+
require.NotNil(t, rl.Items[0].Workspace)
800+
assert.NotEmpty(t, rl.Items[0].Workspace.Name)
801+
})
802+
803+
t.Run("without a valid organization name", func(t *testing.T) {
804+
rl, err := client.Runs.ListForOrganization(ctx, badIdentifier, nil)
805+
assert.Nil(t, rl)
806+
assert.EqualError(t, err, ErrInvalidOrg.Error())
807+
})
808+
809+
t.Run("with filter by agent pool", func(t *testing.T) {
810+
rl, err := client.Runs.ListForOrganization(ctx, orgTest.Name, &RunListForOrganizationOptions{
811+
AgentPoolNames: apTest.Name,
812+
})
813+
require.NoError(t, err)
814+
815+
found := make([]string, len(rl.Items))
816+
for i, r := range rl.Items {
817+
found[i] = r.ID
818+
}
819+
820+
assert.Contains(t, found, rTest1.ID)
821+
assert.Contains(t, found, rTest2.ID)
822+
assert.Equal(t, 1, rl.CurrentPage)
823+
assert.Equal(t, 2, rl.TotalCount)
824+
})
825+
826+
t.Run("with filter by workspace", func(t *testing.T) {
827+
rl, err := client.Runs.ListForOrganization(ctx, orgTest.Name, &RunListForOrganizationOptions{
828+
WorkspaceNames: wTest.Name,
829+
Include: []RunIncludeOpt{RunWorkspace},
830+
})
831+
require.NoError(t, err)
832+
833+
found := make([]string, len(rl.Items))
834+
for i, r := range rl.Items {
835+
found[i] = r.ID
836+
}
837+
838+
assert.Contains(t, found, rTest1.ID)
839+
assert.Contains(t, found, rTest2.ID)
840+
require.NotNil(t, rl.Items[0].Workspace)
841+
assert.NotEmpty(t, rl.Items[0].Workspace.Name)
842+
require.NotNil(t, rl.Items[1].Workspace)
843+
assert.NotEmpty(t, rl.Items[1].Workspace.Name)
844+
assert.Equal(t, 1, rl.CurrentPage)
845+
assert.Equal(t, 2, rl.TotalCount)
846+
})
847+
}

0 commit comments

Comments
 (0)