diff --git a/helper_test.go b/helper_test.go index 54749f70c..0403ae381 100644 --- a/helper_test.go +++ b/helper_test.go @@ -642,7 +642,7 @@ func createRegistryModule(t *testing.T, client *Client, org *Organization) (*Reg ctx := context.Background() options := RegistryModuleCreateOptions{ - Name: String("name"), + Name: String(randomString(t)), Provider: String("provider"), } rm, err := client.RegistryModules.Create(ctx, org.Name, options) diff --git a/mocks/registry_module_mocks.go b/mocks/registry_module_mocks.go index 3766db929..185e75f25 100644 --- a/mocks/registry_module_mocks.go +++ b/mocks/registry_module_mocks.go @@ -122,6 +122,21 @@ func (mr *MockRegistryModulesMockRecorder) DeleteVersion(ctx, moduleID, version return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteVersion", reflect.TypeOf((*MockRegistryModules)(nil).DeleteVersion), ctx, moduleID, version) } +// List mocks base method. +func (m *MockRegistryModules) List(ctx context.Context, organization string, options *tfe.RegistryModuleListOptions) (*tfe.RegistryModuleList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "List", ctx, organization, options) + ret0, _ := ret[0].(*tfe.RegistryModuleList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// List indicates an expected call of List. +func (mr *MockRegistryModulesMockRecorder) List(ctx, organization, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockRegistryModules)(nil).List), ctx, organization, options) +} + // Read mocks base method. func (m *MockRegistryModules) Read(ctx context.Context, moduleID tfe.RegistryModuleID) (*tfe.RegistryModule, error) { m.ctrl.T.Helper() diff --git a/registry_module.go b/registry_module.go index af5d568d5..1e0605f3d 100644 --- a/registry_module.go +++ b/registry_module.go @@ -14,6 +14,9 @@ var _ RegistryModules = (*registryModules)(nil) // // TFE API docs: https://www.terraform.io/docs/cloud/api/modules.html type RegistryModules interface { + // List all the registory modules within an organization + List(ctx context.Context, organization string, options *RegistryModuleListOptions) (*RegistryModuleList, error) + // Create a registry module without a VCS repo Create(ctx context.Context, organization string, options RegistryModuleCreateOptions) (*RegistryModule, error) @@ -81,6 +84,12 @@ type RegistryModuleID struct { Provider string } +// RegistryModuleList represents a list of registry modules. +type RegistryModuleList struct { + *Pagination + Items []*RegistryModule +} + // RegistryModule represents a registry module type RegistryModule struct { ID string `jsonapi:"primary,registry-modules"` @@ -125,6 +134,11 @@ type RegistryModuleVersionStatuses struct { Error string `jsonapi:"attr,error"` } +// RegistryModuleListOptions represents the options for listing registry modules. +type RegistryModuleListOptions struct { + ListOptions +} + // RegistryModuleCreateOptions is used when creating a registry module without a VCS repo type RegistryModuleCreateOptions struct { // Type is a public field utilized by JSON:API to @@ -167,6 +181,27 @@ type RegistryModuleVCSRepoOptions struct { DisplayIdentifier *string `json:"display-identifier"` // Required } +// List all the registory modules within an organization. +func (s *registryModules) List(ctx context.Context, organization string, options *RegistryModuleListOptions) (*RegistryModuleList, error) { + if !validStringID(&organization) { + return nil, ErrInvalidOrg + } + + u := fmt.Sprintf("organizations/%s/registry-modules", url.QueryEscape(organization)) + req, err := s.client.newRequest("GET", u, options) + if err != nil { + return nil, err + } + + ml := &RegistryModuleList{} + err = s.client.do(ctx, req, ml) + if err != nil { + return nil, err + } + + return ml, nil +} + // Upload uploads Terraform configuration files for the provided registry module version. It // requires a path to the configuration files on disk, which will be packaged by // hashicorp/go-slug before being uploaded. diff --git a/registry_module_integration_test.go b/registry_module_integration_test.go index 58cbaee25..60cc5be8a 100644 --- a/registry_module_integration_test.go +++ b/registry_module_integration_test.go @@ -17,6 +17,51 @@ import ( "github.com/stretchr/testify/require" ) +func TestRegistryModulesList(t *testing.T) { + client := testClient(t) + ctx := context.Background() + + orgTest, orgTestCleanup := createOrganization(t, client) + defer orgTestCleanup() + + registryModuleTest1, registryModuleTest1Cleanup := createRegistryModule(t, client, orgTest) + defer registryModuleTest1Cleanup() + registryModuleTest2, registryModuleTest2Cleanup := createRegistryModule(t, client, orgTest) + defer registryModuleTest2Cleanup() + + t.Run("with no list options", func(t *testing.T) { + modl, err := client.RegistryModules.List(ctx, orgTest.Name, &RegistryModuleListOptions{}) + require.NoError(t, err) + assert.Contains(t, modl.Items, registryModuleTest1) + assert.Contains(t, modl.Items, registryModuleTest2) + assert.Equal(t, 1, modl.CurrentPage) + assert.Equal(t, 2, modl.TotalCount) + }) + + t.Run("with list options", func(t *testing.T) { + modl, err := client.RegistryModules.List(ctx, orgTest.Name, &RegistryModuleListOptions{ + ListOptions: ListOptions{ + PageNumber: 999, + PageSize: 100, + }, + }) + require.NoError(t, err) + // Out of range page number, so the items should be empty + assert.Empty(t, modl.Items) + assert.Equal(t, 999, modl.CurrentPage) + + modl, err = client.RegistryModules.List(ctx, orgTest.Name, &RegistryModuleListOptions{ + ListOptions: ListOptions{ + PageNumber: 1, + PageSize: 100, + }, + }) + require.NoError(t, err) + assert.NotEmpty(t, modl.Items) + assert.Equal(t, 1, modl.CurrentPage) + }) +} + func TestRegistryModulesCreate(t *testing.T) { client := testClient(t) ctx := context.Background()