Skip to content

Commit 6dcc99c

Browse files
authored
no code provisioning in registry modules (#562)
* add update operations for registry modules * add no code properties to registry modules creation * add changelog entry
1 parent 0f28f32 commit 6dcc99c

4 files changed

+145
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
* Add OPA support to the Policy Set APIs by @mrinalirao [#575](https://github.com/hashicorp/go-tfe/pull/575)
1010
* Add OPA support to the Policy APIs by @mrinalirao [#579](https://github.com/hashicorp/go-tfe/pull/579)
11+
* Add support for enabling no-code provisioning in an existing or new `RegistryModule` by @miguelhrocha [#562](https://github.com/hashicorp/go-tfe/pull/562)
1112
* Add Policy Evaluation and Policy Set Outcome APIs by @mrinalirao [#583](https://github.com/hashicorp/go-tfe/pull/583)
1213
* Add OPA support to Task Stage APIs by @mrinalirao [#584](https://github.com/hashicorp/go-tfe/pull/584)
1314

mocks/registry_module_mocks.go

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

registry_module.go

+56
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"log"
7+
"net/http"
78
"net/url"
89
"strings"
910
)
@@ -40,6 +41,9 @@ type RegistryModules interface {
4041
// Delete a specific registry module version
4142
DeleteVersion(ctx context.Context, moduleID RegistryModuleID, version string) error
4243

44+
// Update properties of a registry module
45+
Update(ctx context.Context, moduleID RegistryModuleID, options RegistryModuleUpdateOptions) (*RegistryModule, error)
46+
4347
// Upload Terraform configuration files for the provided registry module version. It
4448
// requires a path to the configuration files on disk, which will be packaged by
4549
// hashicorp/go-slug before being uploaded.
@@ -104,6 +108,7 @@ type RegistryModule struct {
104108
Provider string `jsonapi:"attr,provider"`
105109
RegistryName RegistryName `jsonapi:"attr,registry-name"`
106110
Namespace string `jsonapi:"attr,namespace"`
111+
NoCode bool `jsonapi:"attr,no-code"`
107112
Permissions *RegistryModulePermissions `jsonapi:"attr,permissions"`
108113
Status RegistryModuleStatus `jsonapi:"attr,status"`
109114
VCSRepo *VCSRepo `jsonapi:"attr,vcs-repo"`
@@ -164,6 +169,9 @@ type RegistryModuleCreateOptions struct {
164169
RegistryName RegistryName `jsonapi:"attr,registry-name,omitempty"`
165170
// Optional: The namespace of this module. Required for public modules only.
166171
Namespace string `jsonapi:"attr,namespace,omitempty"`
172+
// Optional: If set to true the module is enabled for no-code provisioning.
173+
// **Note: This field is still in BETA and subject to change.**
174+
NoCode bool `jsonapi:"attr,no-code"`
167175
}
168176

169177
// RegistryModuleCreateVersionOptions is used when creating a registry module version
@@ -189,6 +197,19 @@ type RegistryModuleCreateWithVCSConnectionOptions struct {
189197
VCSRepo *RegistryModuleVCSRepoOptions `jsonapi:"attr,vcs-repo"`
190198
}
191199

200+
// RegistryModuleCreateVersionOptions is used when updating a registry module
201+
type RegistryModuleUpdateOptions struct {
202+
// Type is a public field utilized by JSON:API to
203+
// set the resource type via the field tag.
204+
// It is not a user-defined value and does not need to be set.
205+
// https://jsonapi.org/format/#crud-updating
206+
Type string `jsonapi:"primary,registry-modules"`
207+
208+
// Optional: Flag to enable no-code provisioning for the whole module.
209+
// **Note: This field is still in BETA and subject to change.**
210+
NoCode *bool `jsonapi:"attr,no-code,omitempty"`
211+
}
212+
192213
type RegistryModuleVCSRepoOptions struct {
193214
Identifier *string `json:"identifier"` // Required
194215
OAuthTokenID *string `json:"oauth-token-id"` // Required
@@ -265,6 +286,41 @@ func (r *registryModules) Create(ctx context.Context, organization string, optio
265286
return rm, nil
266287
}
267288

289+
func (r *registryModules) Update(ctx context.Context, moduleID RegistryModuleID, options RegistryModuleUpdateOptions) (*RegistryModule, error) {
290+
if err := moduleID.valid(); err != nil {
291+
return nil, err
292+
}
293+
294+
if moduleID.RegistryName == "" {
295+
log.Println("[WARN] Support for using the RegistryModuleID without RegistryName is deprecated as of release 1.5.0 and may be removed in a future version. The preferred method is to include the RegistryName in RegistryModuleID.")
296+
moduleID.RegistryName = PrivateRegistry
297+
}
298+
299+
if moduleID.RegistryName == PrivateRegistry && strings.TrimSpace(moduleID.Namespace) == "" {
300+
log.Println("[WARN] Support for using the RegistryModuleID without Namespace is deprecated as of release 1.5.0 and may be removed in a future version. The preferred method is to include the Namespace in RegistryModuleID.")
301+
moduleID.Namespace = moduleID.Organization
302+
}
303+
304+
org := url.QueryEscape(moduleID.Organization)
305+
registryName := url.QueryEscape(string(moduleID.RegistryName))
306+
namespace := url.QueryEscape(moduleID.Namespace)
307+
name := url.QueryEscape(moduleID.Name)
308+
provider := url.QueryEscape(moduleID.Provider)
309+
url := fmt.Sprintf("organizations/%s/registry-modules/%s/%s/%s/%s", org, registryName, namespace, name, provider)
310+
311+
req, err := r.client.NewRequest(http.MethodPatch, url, &options)
312+
if err != nil {
313+
return nil, err
314+
}
315+
316+
rm := &RegistryModule{}
317+
if err := req.Do(ctx, rm); err != nil {
318+
return nil, err
319+
}
320+
321+
return rm, nil
322+
}
323+
268324
// CreateVersion creates a new registry module version
269325
func (r *registryModules) CreateVersion(ctx context.Context, moduleID RegistryModuleID, options RegistryModuleCreateVersionOptions) (*RegistryModuleVersion, error) {
270326
if err := moduleID.valid(); err != nil {

registry_module_integration_test.go

+73
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ func TestRegistryModulesCreate(t *testing.T) {
9999
assert.Equal(t, *options.Provider, rm.Provider)
100100
assert.Equal(t, PrivateRegistry, rm.RegistryName)
101101
assert.Equal(t, orgTest.Name, rm.Namespace)
102+
assert.False(t, rm.NoCode, "no-code module attribute should be false by default")
102103

103104
assertRegistryModuleAttributes(t, rm)
104105
})
@@ -116,6 +117,7 @@ func TestRegistryModulesCreate(t *testing.T) {
116117
assert.Equal(t, *options.Provider, rm.Provider)
117118
assert.Equal(t, options.RegistryName, rm.RegistryName)
118119
assert.Equal(t, orgTest.Name, rm.Namespace)
120+
assert.False(t, rm.NoCode, "no-code module attribute should be false by default")
119121

120122
assertRegistryModuleAttributes(t, rm)
121123
})
@@ -134,6 +136,27 @@ func TestRegistryModulesCreate(t *testing.T) {
134136
assert.Equal(t, *options.Provider, rm.Provider)
135137
assert.Equal(t, options.RegistryName, rm.RegistryName)
136138
assert.Equal(t, options.Namespace, rm.Namespace)
139+
assert.False(t, rm.NoCode, "no-code module attribute should be false by default")
140+
141+
assertRegistryModuleAttributes(t, rm)
142+
})
143+
144+
t.Run("with no-code attribute", func(t *testing.T) {
145+
skipIfBeta(t)
146+
options := RegistryModuleCreateOptions{
147+
Name: String("iam"),
148+
Provider: String("aws"),
149+
NoCode: true,
150+
RegistryName: PrivateRegistry,
151+
}
152+
rm, err := client.RegistryModules.Create(ctx, orgTest.Name, options)
153+
require.NoError(t, err)
154+
assert.NotEmpty(t, rm.ID)
155+
assert.Equal(t, *options.Name, rm.Name)
156+
assert.Equal(t, *options.Provider, rm.Provider)
157+
assert.Equal(t, options.RegistryName, rm.RegistryName)
158+
assert.Equal(t, orgTest.Name, rm.Namespace)
159+
assert.Equal(t, options.NoCode, rm.NoCode)
137160

138161
assertRegistryModuleAttributes(t, rm)
139162
})
@@ -224,6 +247,56 @@ func TestRegistryModulesCreate(t *testing.T) {
224247
})
225248
}
226249

250+
func TestRegistryModuleUpdate(t *testing.T) {
251+
skipIfBeta(t)
252+
client := testClient(t)
253+
ctx := context.Background()
254+
255+
orgTest, orgTestCleanup := createOrganization(t, client)
256+
defer orgTestCleanup()
257+
258+
options := RegistryModuleCreateOptions{
259+
Name: String("vault"),
260+
Provider: String("aws"),
261+
RegistryName: PublicRegistry,
262+
Namespace: "hashicorp",
263+
}
264+
rm, err := client.RegistryModules.Create(ctx, orgTest.Name, options)
265+
require.NoError(t, err)
266+
assert.NotEmpty(t, rm.ID)
267+
268+
t.Run("enable no-code", func(t *testing.T) {
269+
options := RegistryModuleUpdateOptions{
270+
NoCode: Bool(true),
271+
}
272+
rm, err := client.RegistryModules.Update(ctx, RegistryModuleID{
273+
Organization: orgTest.Name,
274+
Name: "vault",
275+
Provider: "aws",
276+
Namespace: "hashicorp",
277+
RegistryName: PublicRegistry,
278+
}, options)
279+
require.NoError(t, err)
280+
assert.True(t, rm.NoCode)
281+
})
282+
283+
t.Run("disable no-code", func(t *testing.T) {
284+
options := RegistryModuleUpdateOptions{
285+
NoCode: Bool(false),
286+
}
287+
rm, err := client.RegistryModules.Update(ctx, RegistryModuleID{
288+
Organization: orgTest.Name,
289+
Name: "vault",
290+
Provider: "aws",
291+
Namespace: "hashicorp",
292+
RegistryName: PublicRegistry,
293+
}, options)
294+
require.NoError(t, err)
295+
assert.False(t, rm.NoCode)
296+
})
297+
298+
}
299+
227300
func TestRegistryModulesCreateVersion(t *testing.T) {
228301
client := testClient(t)
229302
ctx := context.Background()

0 commit comments

Comments
 (0)