Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WAYP-2742] Support no-code workspace upgrades #935

Merged
merged 9 commits into from
Jul 29, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Enhancements

* Adds support for creating no-code workspaces by @paladin-devops [#927](https://github.com/hashicorp/go-tfe/pull/927)
* Adds support for upgrading no-code workspaces by @paladin-devops [#935](https://github.com/hashicorp/go-tfe/pull/935)

# v1.60.0

Expand Down
15 changes: 15 additions & 0 deletions mocks/registry_no_code_module_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions registry_no_code_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ type RegistryNoCodeModules interface {

// CreateWorkspace creates a workspace using a no-code module.
CreateWorkspace(ctx context.Context, noCodeModuleID string, options *RegistryNoCodeModuleCreateWorkspaceOptions) (*RegistryNoCodeModuleWorkspace, error)

// UpgradeWorkspace initiates an upgrade of an existing no-code module workspace.
UpgradeWorkspace(ctx context.Context, noCodeModuleID string, workspaceID string, options *RegistryNoCodeModuleUpgradeWorkspaceOptions) (*RegistryNoCodeModuleWorkspace, error)
}

type RegistryNoCodeModuleCreateWorkspaceOptions struct {
Expand Down Expand Up @@ -67,6 +70,14 @@ type RegistryNoCodeModuleCreateWorkspaceOptions struct {
SourceURL *string `jsonapi:"attr,source-url,omitempty"`
}

type RegistryNoCodeModuleUpgradeWorkspaceOptions struct {
Type string `jsonapi:"primary,no-code-module-workspace"`

// Variables is the slice of variables to be configured for the no-code
// workspace.
Variables []*Variable `jsonapi:"relation,vars,omitempty"`
}

type RegistryNoCodeModuleWorkspace struct {
Workspace
}
Expand Down Expand Up @@ -284,6 +295,35 @@ func (r *registryNoCodeModules) CreateWorkspace(
return w, nil
}

// UpgradeWorkspace initiates an upgrade of an existing no-code module workspace.
func (r *registryNoCodeModules) UpgradeWorkspace(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also add a comment/description on top of this method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated!

ctx context.Context,
noCodeModuleID string,
workspaceID string,
options *RegistryNoCodeModuleUpgradeWorkspaceOptions,
) (*RegistryNoCodeModuleWorkspace, error) {
if err := options.valid(); err != nil {
return nil, err
}

u := fmt.Sprintf("no-code-modules/%s/workspaces/%s/upgrade",
url.QueryEscape(noCodeModuleID),
workspaceID,
)
req, err := r.client.NewRequest("POST", u, options)
if err != nil {
return nil, err
}

w := &RegistryNoCodeModuleWorkspace{}
err = req.Do(ctx, w)
if err != nil {
return nil, err
}

return w, nil
}

func (o RegistryNoCodeModuleCreateOptions) valid() error {
if o.RegistryModule == nil || o.RegistryModule.ID == "" {
return ErrRequiredRegistryModule
Expand Down Expand Up @@ -315,3 +355,7 @@ func (o *RegistryNoCodeModuleCreateWorkspaceOptions) valid() error {

return nil
}

func (o *RegistryNoCodeModuleUpgradeWorkspaceOptions) valid() error {
return nil
}
115 changes: 115 additions & 0 deletions registry_no_code_module_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,118 @@ func TestRegistryNoCodeModulesCreateWorkspace(t *testing.T) {
r.Error(err)
})
}

func TestRegistryNoCodeModuleWorkspaceUpgrade(t *testing.T) {
skipUnlessBeta(t)

client := testClient(t)
ctx := context.Background()
r := require.New(t)

orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()

org, err := client.Organizations.Read(ctx, orgTest.Name)
r.NoError(err)
r.NotNil(org)

githubIdentifier := os.Getenv("GITHUB_REGISTRY_NO_CODE_MODULE_IDENTIFIER")
if githubIdentifier == "" {
t.Skip("Export a valid GITHUB_REGISTRY_NO_CODE_MODULE_IDENTIFIER before running this test")
}

token, cleanupToken := createOAuthToken(t, client, org)
defer cleanupToken()

rmOpts := RegistryModuleCreateWithVCSConnectionOptions{
VCSRepo: &RegistryModuleVCSRepoOptions{
OrganizationName: String(org.Name),
Identifier: String(githubIdentifier),
Tags: Bool(true),
OAuthTokenID: String(token.ID),
DisplayIdentifier: String(githubIdentifier),
},
InitialVersion: String("1.0.0"),
}

// create the module
rm, err := client.RegistryModules.CreateWithVCSConnection(ctx, rmOpts)
r.NoError(err)

// create the no-code module
ncm, err := client.RegistryNoCodeModules.Create(ctx, org.Name, RegistryNoCodeModuleCreateOptions{
RegistryModule: rm,
Enabled: Bool(true),
VariableOptions: nil,
})
r.NoError(err)
r.NotNil(ncm)

// We sleep for 10 seconds to let the module finish getting ready
time.Sleep(time.Second * 10)

// update the module's pinned version to be 1.0.0
// NOTE: This is done here as an update instead of at create time, because
// that results in the following error:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that behavior expected?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am unsure - I am new to using that API endpoint; however, it seems like it should work with the version # provided.

// Validation failed: Provided version pin is not equal to latest or provided
// string does not represent an existing version of the module.
uncm, err := client.RegistryNoCodeModules.Update(ctx, ncm.ID, RegistryNoCodeModuleUpdateOptions{
RegistryModule: rm,
VersionPin: "1.0.0",
})
r.NoError(err)
r.NotNil(uncm)

// create a workspace, which will be attempted to be updated during the test
wn := fmt.Sprintf("foo-%s", randomString(t))
sn := "my-app"
su := "http://my-app.com"
w, err := client.RegistryNoCodeModules.CreateWorkspace(
ctx,
uncm.ID,
&RegistryNoCodeModuleCreateWorkspaceOptions{
Name: wn,
SourceName: String(sn),
SourceURL: String(su),
},
)
r.NoError(err)
r.NotNil(w)

// update the module's pinned version
uncm, err = client.RegistryNoCodeModules.Update(ctx, ncm.ID, RegistryNoCodeModuleUpdateOptions{
VersionPin: "1.0.1",
})
r.NoError(err)
r.NotNil(uncm)

t.Run("test upgrading a workspace via a no-code module", func(t *testing.T) {
_, err = client.RegistryNoCodeModules.UpgradeWorkspace(
ctx,
ncm.ID,
w.ID,
&RegistryNoCodeModuleUpgradeWorkspaceOptions{},
)
r.NoError(err)
})

t.Run("fail to upgrade workspace with invalid no-code module", func(t *testing.T) {
_, err = client.RegistryNoCodeModules.UpgradeWorkspace(
ctx,
ncm.ID+"-invalid",
w.ID,
&RegistryNoCodeModuleUpgradeWorkspaceOptions{},
)
r.Error(err)
})

t.Run("fail to upgrade workspace with invalid workspace ID", func(t *testing.T) {
_, err = client.RegistryNoCodeModules.UpgradeWorkspace(
ctx,
ncm.ID,
w.ID+"-invalid",
&RegistryNoCodeModuleUpgradeWorkspaceOptions{},
)
r.Error(err)
})
}
Loading