Skip to content

Commit 58b0c42

Browse files
authored
Merge branch 'main' into add-org-runs-list
2 parents 84ddafa + fdaf8ec commit 58b0c42

File tree

5 files changed

+232
-0
lines changed

5 files changed

+232
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Enhancements
44

55
* Adds `DefaultProject` to `OrganizationUpdateOptions` to support updating an organization's default project. This provides BETA support, which is EXPERIMENTAL, SUBJECT TO CHANGE, and may not be available to all users, by @mkam [#1056](https://github.com/hashicorp/go-tfe/pull/1056)
6+
* Adds `ReadTerraformRegistryModule` to support reading a registry module from Terraform Registry's proxied endpoints by @paladin-devops [#1057](https://github.com/hashicorp/go-tfe/pull/1057)
67
* Adds a new method `ListForOrganization` to list Runs in an organization by @arybolovlev [#1059](https://github.com/hashicorp/go-tfe/pull/1059)
78

89
## Bug fixes

generate_mocks.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,4 @@ mockgen -source=project.go -destination=mocks/project_mocks.go -package=mocks
7777
mockgen -source=registry_no_code_module.go -destination=mocks/registry_no_code_module_mocks.go -package=mocks
7878
mockgen -source=registry_module.go -destination=mocks/registry_module_mocks.go -package=mocks
7979
mockgen -source=workspace_resources.go -destination=mocks/workspace_resources.go -package=mocks
80+
mockgen -source=registry_module.go -destination=mocks/registry_module_mocks.go -package=mocks

mocks/registry_module_mocks.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

registry_module.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ type RegistryModules interface {
4545
// ReadVersion Read a registry module version
4646
ReadVersion(ctx context.Context, moduleID RegistryModuleID, version string) (*RegistryModuleVersion, error)
4747

48+
// ReadTerraformRegistryModule Reads a registry module from the Terraform
49+
// Registry, as opposed to Read or ReadVersion which read from the private
50+
// registry of a Terraform organization.
51+
// https://developer.hashicorp.com/terraform/enterprise/api-docs/private-registry/modules#hcp-terraform-registry-implementation
52+
ReadTerraformRegistryModule(ctx context.Context, moduleID RegistryModuleID, version string) (*TerraformRegistryModule, error)
53+
4854
// Delete a registry module
4955
// Warning: This method is deprecated and will be removed from a future version of go-tfe. Use DeleteByName instead.
5056
Delete(ctx context.Context, organization string, name string) error
@@ -70,6 +76,62 @@ type RegistryModules interface {
7076
UploadTarGzip(ctx context.Context, url string, r io.Reader) error
7177
}
7278

79+
// TerraformRegistryModule contains data about a module from the Terraform Registry.
80+
type TerraformRegistryModule struct {
81+
ID string `json:"id"`
82+
Owner string `json:"owner"`
83+
Namespace string `json:"namespace"`
84+
Name string `json:"name"`
85+
Version string `json:"version"`
86+
Provider string `json:"provider"`
87+
ProviderLogoURL string `json:"provider_logo_url"`
88+
Description string `json:"description"`
89+
Source string `json:"source"`
90+
Tag string `json:"tag"`
91+
PublishedAt string `json:"published_at"`
92+
Downloads int `json:"downloads"`
93+
Verified bool `json:"verified"`
94+
Root Root `json:"root"`
95+
Providers []string `json:"providers"`
96+
Versions []string `json:"versions"`
97+
}
98+
99+
type Root struct {
100+
Path string `json:"path"`
101+
Name string `json:"name"`
102+
Readme string `json:"readme"`
103+
Empty bool `json:"empty"`
104+
Inputs []Input `json:"inputs"`
105+
Outputs []Output `json:"outputs"`
106+
ProviderDependencies []ProviderDependency `json:"provider_dependencies"`
107+
Resources []Resource `json:"resources"`
108+
}
109+
110+
type Input struct {
111+
Name string `json:"name"`
112+
Type string `json:"type"`
113+
Description string `json:"description"`
114+
Default string `json:"default"`
115+
Required bool `json:"required"`
116+
}
117+
118+
type Output struct {
119+
Name string `json:"name"`
120+
Description string `json:"description"`
121+
}
122+
123+
type ProviderDependency struct {
124+
Name string `json:"name"`
125+
Namespace string `json:"namespace"`
126+
Source string `json:"source"`
127+
Version string `json:"version"`
128+
}
129+
130+
type Resource struct {
131+
Name string `json:"name"`
132+
Type string `json:"type"`
133+
}
134+
73135
// registryModules implements RegistryModules.
74136
type registryModules struct {
75137
client *Client
@@ -572,6 +634,38 @@ func (r *registryModules) Read(ctx context.Context, moduleID RegistryModuleID) (
572634

573635
return rm, nil
574636
}
637+
638+
// ReadRegistry fetches a registry module from the Terraform Registry.
639+
func (r *registryModules) ReadTerraformRegistryModule(ctx context.Context, moduleID RegistryModuleID, version string) (*TerraformRegistryModule, error) {
640+
u := fmt.Sprintf(
641+
"https://app.terraform.io/api/registry/v1/modules/%s/%s/%s/%s",
642+
moduleID.Namespace,
643+
moduleID.Name,
644+
moduleID.Provider,
645+
version,
646+
)
647+
if moduleID.RegistryName == PublicRegistry {
648+
u = fmt.Sprintf(
649+
"https://app.terraform.io/api/registry/public/v1/modules/%s/%s/%s/%s",
650+
moduleID.Namespace,
651+
moduleID.Name,
652+
moduleID.Provider,
653+
version,
654+
)
655+
}
656+
req, err := r.client.NewRequest("GET", u, nil)
657+
if err != nil {
658+
return nil, err
659+
}
660+
661+
trm := &TerraformRegistryModule{}
662+
err = req.DoJSON(ctx, trm)
663+
if err != nil {
664+
return nil, err
665+
}
666+
return trm, nil
667+
}
668+
575669
func (r *registryModules) ReadVersion(ctx context.Context, moduleID RegistryModuleID, version string) (*RegistryModuleVersion, error) {
576670
if err := moduleID.valid(); err != nil {
577671
return nil, err

registry_module_integration_test.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"regexp"
1313
"strings"
1414
"testing"
15+
"time"
1516

1617
retryablehttp "github.com/hashicorp/go-retryablehttp"
1718
slug "github.com/hashicorp/go-slug"
@@ -1323,6 +1324,126 @@ func TestRegistryModulesRead(t *testing.T) {
13231324
})
13241325
}
13251326

1327+
func TestRegistryModulesReadTerraformRegistryModule(t *testing.T) {
1328+
client := testClient(t)
1329+
ctx := context.Background()
1330+
r := require.New(t)
1331+
1332+
githubIdentifier := os.Getenv("GITHUB_REGISTRY_NO_CODE_MODULE_IDENTIFIER")
1333+
if githubIdentifier == "" {
1334+
t.Skip("Export a valid GITHUB_REGISTRY_NO_CODE_MODULE_IDENTIFIER before running this test")
1335+
}
1336+
1337+
// NOTE: These test cases use time.Sleep to wait for the module to be ready,
1338+
// an enhancement to these test cases would be to use a polling mechanism to
1339+
// check if the module is ready, and then time out if it is not ready after a
1340+
// certain amount of time.
1341+
1342+
t.Run("fetch module from private registry", func(t *testing.T) {
1343+
orgTest, orgTestCleanup := createOrganization(t, client)
1344+
defer orgTestCleanup()
1345+
1346+
token, cleanupToken := createOAuthToken(t, client, orgTest)
1347+
defer cleanupToken()
1348+
1349+
rmOpts := RegistryModuleCreateWithVCSConnectionOptions{
1350+
VCSRepo: &RegistryModuleVCSRepoOptions{
1351+
OrganizationName: String(orgTest.Name),
1352+
Identifier: String(githubIdentifier),
1353+
Tags: Bool(true),
1354+
OAuthTokenID: String(token.ID),
1355+
DisplayIdentifier: String(githubIdentifier),
1356+
},
1357+
}
1358+
1359+
version := "1.0.0"
1360+
rm, err := client.RegistryModules.CreateWithVCSConnection(ctx, rmOpts)
1361+
r.NoError(err)
1362+
1363+
time.Sleep(time.Second * 10)
1364+
1365+
rmID := RegistryModuleID{
1366+
Organization: orgTest.Name,
1367+
Name: rm.Name,
1368+
Provider: rm.Provider,
1369+
Namespace: rm.Namespace,
1370+
RegistryName: rm.RegistryName,
1371+
}
1372+
tfm, err := client.RegistryModules.ReadTerraformRegistryModule(ctx, rmID, version)
1373+
r.NoError(err)
1374+
r.NotNil(tfm)
1375+
r.Equal(fmt.Sprintf("%s/%s/%s/%s", orgTest.Name, rm.Name, rm.Provider, version), tfm.ID)
1376+
r.Equal(rm.Name, tfm.Name)
1377+
r.Equal("A test Terraform module for use in CI pipelines", tfm.Description)
1378+
r.Equal(rm.Provider, tfm.Provider)
1379+
r.Equal(rm.Namespace, tfm.Namespace)
1380+
r.Equal(version, tfm.Version)
1381+
r.Equal("", tfm.Tag)
1382+
r.Equal(0, tfm.Downloads)
1383+
r.False(tfm.Verified)
1384+
r.NotNil(tfm.Root)
1385+
r.Equal(rm.Name, tfm.Root.Name)
1386+
r.Equal("", tfm.Root.Readme)
1387+
r.False(tfm.Root.Empty)
1388+
r.Len(tfm.Root.Inputs, 1)
1389+
r.Len(tfm.Root.Outputs, 1)
1390+
r.Len(tfm.Root.ProviderDependencies, 1)
1391+
r.Len(tfm.Root.Resources, 1)
1392+
})
1393+
1394+
t.Run("fetch module from public registry", func(t *testing.T) {
1395+
orgTest, orgTestCleanup := createOrganization(t, client)
1396+
defer orgTestCleanup()
1397+
1398+
token, cleanupToken := createOAuthToken(t, client, orgTest)
1399+
defer cleanupToken()
1400+
1401+
rmOpts := RegistryModuleCreateWithVCSConnectionOptions{
1402+
VCSRepo: &RegistryModuleVCSRepoOptions{
1403+
OrganizationName: String(orgTest.Name),
1404+
Identifier: String(githubIdentifier),
1405+
Tags: Bool(true),
1406+
OAuthTokenID: String(token.ID),
1407+
DisplayIdentifier: String(githubIdentifier),
1408+
},
1409+
}
1410+
1411+
version := "1.0.0"
1412+
rm, err := client.RegistryModules.CreateWithVCSConnection(ctx, rmOpts)
1413+
r.NoError(err)
1414+
1415+
time.Sleep(time.Second * 10)
1416+
1417+
rmID := RegistryModuleID{
1418+
Organization: orgTest.Name,
1419+
Name: rm.Name,
1420+
Provider: rm.Provider,
1421+
Namespace: rm.Namespace,
1422+
RegistryName: rm.RegistryName,
1423+
}
1424+
tfm, err := client.RegistryModules.ReadTerraformRegistryModule(ctx, rmID, version)
1425+
r.NoError(err)
1426+
r.NotNil(tfm)
1427+
r.Equal(fmt.Sprintf("%s/%s/%s/%s", orgTest.Name, rm.Name, rm.Provider, version), tfm.ID)
1428+
r.Equal(rm.Name, tfm.Name)
1429+
r.Equal("A test Terraform module for use in CI pipelines", tfm.Description)
1430+
r.Equal(rm.Provider, tfm.Provider)
1431+
r.Equal(rm.Namespace, tfm.Namespace)
1432+
r.Equal(version, tfm.Version)
1433+
r.Equal("", tfm.Tag)
1434+
r.Equal(0, tfm.Downloads)
1435+
r.False(tfm.Verified)
1436+
r.NotNil(tfm.Root)
1437+
r.Equal(rm.Name, tfm.Root.Name)
1438+
r.Equal("", tfm.Root.Readme)
1439+
r.False(tfm.Root.Empty)
1440+
r.Len(tfm.Root.Inputs, 1)
1441+
r.Len(tfm.Root.Outputs, 1)
1442+
r.Len(tfm.Root.ProviderDependencies, 1)
1443+
r.Len(tfm.Root.Resources, 1)
1444+
})
1445+
}
1446+
13261447
func TestRegistryModulesDelete(t *testing.T) {
13271448
client := testClient(t)
13281449
ctx := context.Background()

0 commit comments

Comments
 (0)