diff --git a/cli/templatepush.go b/cli/templatepush.go
index bc5516b092ef9..1b0639e55c2af 100644
--- a/cli/templatepush.go
+++ b/cli/templatepush.go
@@ -163,6 +163,7 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
provisionerTags []string
uploadFlags templateUploadFlags
activate bool
+ create bool
)
client := new(codersdk.Client)
cmd := &clibase.Cmd{
@@ -185,9 +186,13 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
return err
}
+ var createTemplate bool
template, err := client.TemplateByName(inv.Context(), organization.ID, name)
if err != nil {
- return err
+ if !create {
+ return err
+ }
+ createTemplate = true
}
err = uploadFlags.checkForLockfile(inv)
@@ -207,19 +212,24 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
return err
}
- job, err := createValidTemplateVersion(inv, createValidTemplateVersionArgs{
- Name: versionName,
+ args := createValidTemplateVersionArgs{
Message: message,
Client: client,
Organization: organization,
Provisioner: database.ProvisionerType(provisioner),
FileID: resp.ID,
+ ProvisionerTags: tags,
VariablesFile: variablesFile,
Variables: variables,
- Template: &template,
- ReuseParameters: !alwaysPrompt,
- ProvisionerTags: tags,
- })
+ }
+
+ if !createTemplate {
+ args.Name = versionName
+ args.Template = &template
+ args.ReuseParameters = !alwaysPrompt
+ }
+
+ job, err := createValidTemplateVersion(inv, args)
if err != nil {
return err
}
@@ -228,7 +238,19 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
return xerrors.Errorf("job failed: %s", job.Job.Status)
}
- if activate {
+ if createTemplate {
+ _, err = client.CreateTemplate(inv.Context(), organization.ID, codersdk.CreateTemplateRequest{
+ Name: name,
+ VersionID: job.ID,
+ })
+ if err != nil {
+ return err
+ }
+
+ _, _ = fmt.Fprintln(inv.Stdout, "\n"+cliui.DefaultStyles.Wrap.Render(
+ "The "+cliui.DefaultStyles.Keyword.Render(name)+" template has been created at "+cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"! "+
+ "Developers can provision a workspace with this template using:")+"\n")
+ } else if activate {
err = client.UpdateActiveTemplateVersion(inv.Context(), template.ID, codersdk.UpdateActiveTemplateVersion{
ID: job.ID,
})
@@ -290,6 +312,12 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
Default: "true",
Value: clibase.BoolOf(&activate),
},
+ {
+ Flag: "create",
+ Description: "Create the template if it does not exist.",
+ Default: "false",
+ Value: clibase.BoolOf(&create),
+ },
cliui.SkipPromptOption(),
}
cmd.Options = append(cmd.Options, uploadFlags.options()...)
diff --git a/cli/templatepush_test.go b/cli/templatepush_test.go
index c890ea6593b94..88a1ce250543c 100644
--- a/cli/templatepush_test.go
+++ b/cli/templatepush_test.go
@@ -9,6 +9,7 @@ import (
"strings"
"testing"
+ "github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -613,6 +614,52 @@ func TestTemplatePush(t *testing.T) {
require.Equal(t, "second_variable", templateVariables[1].Name)
require.Equal(t, "foobar", templateVariables[1].Value)
})
+
+ t.Run("CreateTemplate", func(t *testing.T) {
+ t.Parallel()
+ client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
+ user := coderdtest.CreateFirstUser(t, client)
+ source := clitest.CreateTemplateVersionSource(t, &echo.Responses{
+ Parse: echo.ParseComplete,
+ ProvisionApply: provisionCompleteWithAgent,
+ })
+
+ const templateName = "my-template"
+ args := []string{
+ "templates",
+ "push",
+ templateName,
+ "--directory", source,
+ "--test.provisioner", string(database.ProvisionerTypeEcho),
+ "--create",
+ }
+ inv, root := clitest.New(t, args...)
+ clitest.SetupConfig(t, client, root)
+ pty := ptytest.New(t).Attach(inv)
+
+ waiter := clitest.StartWithWaiter(t, inv)
+
+ matches := []struct {
+ match string
+ write string
+ }{
+ {match: "Upload", write: "yes"},
+ {match: "template has been created"},
+ }
+ for _, m := range matches {
+ pty.ExpectMatch(m.match)
+ if m.write != "" {
+ pty.WriteLine(m.write)
+ }
+ }
+
+ waiter.RequireSuccess()
+
+ template, err := client.TemplateByName(context.Background(), user.OrganizationID, templateName)
+ require.NoError(t, err)
+ require.Equal(t, templateName, template.Name)
+ require.NotEqual(t, uuid.Nil, template.ActiveVersionID)
+ })
})
}
diff --git a/cli/testdata/coder_templates_push_--help.golden b/cli/testdata/coder_templates_push_--help.golden
index 6aeff1641fd0d..7dc7b2e87ff7f 100644
--- a/cli/testdata/coder_templates_push_--help.golden
+++ b/cli/testdata/coder_templates_push_--help.golden
@@ -10,6 +10,9 @@ Push a new template version from the current directory or as specified by flag
Always prompt all parameters. Does not pull parameter values from
active template version.
+ --create bool (default: false)
+ Create the template if it does not exist.
+
-d, --directory string (default: .)
Specify the directory to create from, use '-' to read tar from stdin.
diff --git a/docs/cli/templates_push.md b/docs/cli/templates_push.md
index 4043de558198b..fb3068ed5b15d 100644
--- a/docs/cli/templates_push.md
+++ b/docs/cli/templates_push.md
@@ -29,6 +29,15 @@ Whether the new template will be marked active.
Always prompt all parameters. Does not pull parameter values from active template version.
+### --create
+
+| | |
+| ------- | ------------------ |
+| Type | bool
|
+| Default | false
|
+
+Create the template if it does not exist.
+
### -d, --directory
| | |