-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #36 from hashicorp/WAYP-2335-waypoint-update-templ…
…ates [WAYP-2335] `waypoint templates update` command
- Loading branch information
Showing
3 changed files
with
320 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
internal/commands/waypoint/template/template_update_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package template | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/go-openapi/runtime/client" | ||
"github.com/hashicorp/hcp/internal/pkg/cmd" | ||
"github.com/hashicorp/hcp/internal/pkg/format" | ||
"github.com/hashicorp/hcp/internal/pkg/iostreams" | ||
"github.com/hashicorp/hcp/internal/pkg/profile" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestCmdTemplateUpdate(t *testing.T) { | ||
t.Parallel() | ||
|
||
cases := []struct { | ||
Name string | ||
Args []string | ||
Profile func(t *testing.T) *profile.Profile | ||
Error string | ||
Expect *TemplateOpts | ||
}{ | ||
{ | ||
Name: "No Org", | ||
Profile: profile.TestProfile, | ||
Args: []string{}, | ||
Error: "Organization ID must be configured", | ||
}, | ||
{ | ||
Name: "no args", | ||
Profile: func(t *testing.T) *profile.Profile { | ||
return profile.TestProfile(t).SetOrgID("123") | ||
}, | ||
Args: []string{}, | ||
Error: "accepts 1 arg(s), received 0", | ||
}, | ||
{ | ||
Name: "happy", | ||
Profile: func(t *testing.T) *profile.Profile { | ||
return profile.TestProfile(t).SetOrgID("123") | ||
}, | ||
Args: []string{ | ||
"-n=cli-test", | ||
"--new-name=cli-test-new", | ||
"-s", "A template created using the CLI.", | ||
"--tfc-project-id", "prj-abcdefghij", | ||
"--tfc-project-name", "test", | ||
"--tfc-no-code-module-source", "private/waypoint/waypoint-nocode-module/null", | ||
"--tfc-no-code-module-version", "0.0.1", | ||
"-l", "cli", | ||
"-d", "A template created with the CLI.", | ||
"-t", "cli=true", | ||
"--readme-markdown-template-file", "readme_test.txt", | ||
}, | ||
Expect: &TemplateOpts{ | ||
Name: "cli-test", | ||
UpdatedName: "cli-test-new", | ||
Summary: "A template created using the CLI.", | ||
Description: "A template created with the CLI.", | ||
TerraformCloudProjectID: "prj-abcdefghij", | ||
TerraformCloudProjectName: "test", | ||
TerraformNoCodeModuleSource: "private/waypoint/waypoint-nocode-module/null", | ||
TerraformNoCodeModuleVersion: "0.0.1", | ||
ReadmeMarkdownTemplateFile: "readme_test.txt", | ||
Labels: []string{"cli"}, | ||
Tags: map[string]string{"cli": "true"}, | ||
}, | ||
}, | ||
} | ||
|
||
for _, c := range cases { | ||
c := c | ||
t.Run(c.Name, func(t *testing.T) { | ||
t.Parallel() | ||
|
||
r := require.New(t) | ||
|
||
// Create a context. | ||
io := iostreams.Test() | ||
ctx := &cmd.Context{ | ||
IO: io, | ||
Profile: c.Profile(t), | ||
Output: format.New(io), | ||
HCP: &client.Runtime{}, | ||
ShutdownCtx: context.Background(), | ||
} | ||
|
||
var tplOpts TemplateOpts | ||
tplOpts.testFunc = func(c *cmd.Command, args []string) error { | ||
return nil | ||
} | ||
cmd := NewCmdUpdate(ctx, &tplOpts) | ||
cmd.SetIO(io) | ||
|
||
cmd.Run(c.Args) | ||
|
||
if c.Expect != nil { | ||
r.NotNil(c.Expect) | ||
|
||
r.Equal(c.Expect.Name, tplOpts.Name) | ||
r.Equal(c.Expect.UpdatedName, tplOpts.UpdatedName) | ||
r.Equal(c.Expect.Description, tplOpts.Description) | ||
r.Equal(c.Expect.Summary, tplOpts.Summary) | ||
r.Equal(c.Expect.TerraformCloudProjectID, tplOpts.TerraformCloudProjectID) | ||
r.Equal(c.Expect.TerraformCloudProjectName, tplOpts.TerraformCloudProjectName) | ||
r.Equal(c.Expect.TerraformNoCodeModuleSource, tplOpts.TerraformNoCodeModuleSource) | ||
r.Equal(c.Expect.TerraformNoCodeModuleVersion, tplOpts.TerraformNoCodeModuleVersion) | ||
r.Equal(c.Expect.ReadmeMarkdownTemplateFile, tplOpts.ReadmeMarkdownTemplateFile) | ||
r.Equal(c.Expect.Labels, tplOpts.Labels) | ||
r.Equal(c.Expect.Tags, tplOpts.Tags) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
package template | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/hashicorp/hcp-sdk-go/clients/cloud-waypoint-service/preview/2023-08-18/client/waypoint_service" | ||
"github.com/hashicorp/hcp-sdk-go/clients/cloud-waypoint-service/preview/2023-08-18/models" | ||
"github.com/hashicorp/hcp/internal/pkg/cmd" | ||
"github.com/hashicorp/hcp/internal/pkg/flagvalue" | ||
"github.com/hashicorp/hcp/internal/pkg/heredoc" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
func NewCmdUpdate(ctx *cmd.Context, opts *TemplateOpts) *cmd.Command { | ||
cmd := &cmd.Command{ | ||
Name: "update", | ||
ShortHelp: "Update an existing HCP Waypoint template.", | ||
LongHelp: "Update an existing HCP Waypoint template. This will update" + | ||
" the template with the provided information.", | ||
Examples: []cmd.Example{ | ||
{ | ||
Preamble: "Create a new HCP Waypoint template:", | ||
Command: heredoc.New(ctx.IO, heredoc.WithPreserveNewlines()).Must(` | ||
$ hcp waypoint templates update -n my-template \ | ||
-s "My Template Summary" \ | ||
-d "My Template Description" \ | ||
-readme-markdown-template-file "README.tpl" \ | ||
-tfc-no-code-module-source "app.terraform.io/hashicorp/dir/template" \ | ||
-tfc-no-code-module-version "1.0.2" \ | ||
-tfc-project-name "my-tfc-project" \ | ||
-tfc-project-id "prj-123456 \ | ||
-l "label1" \ | ||
-l "label2" | ||
`), | ||
}, | ||
}, | ||
RunF: func(c *cmd.Command, args []string) error { | ||
if opts.testFunc != nil { | ||
return opts.testFunc(c, args) | ||
} | ||
return templateUpdate(opts) | ||
}, | ||
PersistentPreRun: func(c *cmd.Command, args []string) error { | ||
return cmd.RequireOrgAndProject(ctx) | ||
}, | ||
Flags: cmd.Flags{ | ||
Local: []*cmd.Flag{ | ||
{ | ||
Name: "name", | ||
Shorthand: "n", | ||
DisplayValue: "NAME", | ||
Description: "The name of the template to be updated.", | ||
Value: flagvalue.Simple("", &opts.Name), | ||
Required: true, | ||
}, | ||
{ | ||
Name: "new-name", | ||
DisplayValue: "NEW_NAME", | ||
Description: "The new name of the template.", | ||
Value: flagvalue.Simple("", &opts.UpdatedName), | ||
Hidden: true, | ||
}, | ||
{ | ||
Name: "summary", | ||
Shorthand: "s", | ||
DisplayValue: "SUMMARY", | ||
Description: "The summary of the template.", | ||
Value: flagvalue.Simple("", &opts.Summary), | ||
}, | ||
{ | ||
Name: "description", | ||
Shorthand: "d", | ||
DisplayValue: "DESCRIPTION", | ||
Description: "The description of the template.", | ||
Value: flagvalue.Simple("", &opts.Description), | ||
}, | ||
{ | ||
Name: "readme-markdown-template-file", | ||
DisplayValue: "README_MARKDOWN_TEMPLATE_FILE_PATH", | ||
Description: "The file containing the README markdown template.", | ||
Value: flagvalue.Simple("", &opts.ReadmeMarkdownTemplateFile), | ||
}, | ||
{ | ||
Name: "label", | ||
Shorthand: "l", | ||
DisplayValue: "LABEL", | ||
Description: "A label to apply to the template.", | ||
Repeatable: true, | ||
Value: flagvalue.SimpleSlice(nil, &opts.Labels), | ||
}, | ||
{ | ||
Name: "tag", | ||
Shorthand: "t", | ||
DisplayValue: "KEY=VALUE", | ||
Description: "A tag to apply to the template.", | ||
Repeatable: true, | ||
Value: flagvalue.SimpleMap(nil, &opts.Tags), | ||
Hidden: true, | ||
}, | ||
{ | ||
Name: "tfc-no-code-module-source", | ||
DisplayValue: "TFC_NO_CODE_MODULE_SOURCE", | ||
Description: heredoc.New(ctx.IO).Must(` | ||
The source of the Terraform no-code module. | ||
The expected format is "NAMESPACE/NAME/PROVIDER". An | ||
optional "HOSTNAME/" can be added at the beginning for | ||
a private registry. | ||
`), | ||
Value: flagvalue.Simple("", &opts.TerraformNoCodeModuleSource), | ||
}, | ||
{ | ||
Name: "tfc-no-code-module-version", | ||
DisplayValue: "TFC_NO_CODE_MODULE_VERSION", | ||
Description: "The version of the Terraform no-code module.", | ||
Value: flagvalue.Simple("", &opts.TerraformNoCodeModuleVersion), | ||
}, | ||
{ | ||
Name: "tfc-project-name", | ||
DisplayValue: "TFC_PROJECT_NAME", | ||
Description: "The name of the Terraform Cloud project where" + | ||
" applications using this template will be created.", | ||
Value: flagvalue.Simple("", &opts.TerraformCloudProjectName), | ||
}, | ||
{ | ||
Name: "tfc-project-id", | ||
DisplayValue: "TFC_PROJECT_ID", | ||
Description: "The ID of the Terraform Cloud project where" + | ||
" applications using this template will be created.", | ||
Value: flagvalue.Simple("", &opts.TerraformCloudProjectID), | ||
}, | ||
}, | ||
}, | ||
} | ||
return cmd | ||
} | ||
|
||
func templateUpdate(opts *TemplateOpts) error { | ||
ns, err := opts.Namespace() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var tags []*models.HashicorpCloudWaypointTag | ||
for k, v := range opts.Tags { | ||
tags = append(tags, &models.HashicorpCloudWaypointTag{ | ||
Key: k, | ||
Value: v, | ||
}) | ||
} | ||
|
||
var readmeTpl []byte | ||
if opts.ReadmeMarkdownTemplateFile != "" { | ||
readmeTpl, err = os.ReadFile(opts.ReadmeMarkdownTemplateFile) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to read file %q", opts.ReadmeMarkdownTemplateFile) | ||
} | ||
} | ||
|
||
updatedTpl := &models.HashicorpCloudWaypointApplicationTemplate{ | ||
Name: opts.UpdatedName, | ||
Summary: opts.Summary, | ||
Description: opts.Description, | ||
ReadmeMarkdownTemplate: readmeTpl, | ||
Labels: opts.Labels, | ||
Tags: tags, | ||
TerraformNocodeModule: &models.HashicorpCloudWaypointTerraformNocodeModule{ | ||
Source: opts.TerraformNoCodeModuleSource, | ||
Version: opts.TerraformNoCodeModuleVersion, | ||
}, | ||
TerraformCloudWorkspaceDetails: &models.HashicorpCloudWaypointTerraformCloudWorkspaceDetails{ | ||
Name: opts.TerraformCloudProjectName, | ||
ProjectID: opts.TerraformCloudProjectID, | ||
}, | ||
} | ||
|
||
_, err = opts.WS.WaypointServiceUpdateApplicationTemplate2( | ||
&waypoint_service.WaypointServiceUpdateApplicationTemplate2Params{ | ||
NamespaceID: ns.ID, | ||
Context: opts.Ctx, | ||
ExistingApplicationTemplateName: opts.Name, | ||
Body: &models.HashicorpCloudWaypointWaypointServiceUpdateApplicationTemplateBody{ | ||
ApplicationTemplate: updatedTpl, | ||
}, | ||
}, nil, | ||
) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to update template %q", opts.Name) | ||
} | ||
|
||
fmt.Fprintf(opts.IO.Err(), "Template %q updated.", opts.ID) | ||
|
||
return nil | ||
} |