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

Add an 'instructions' to Pulumi templates to display them at pulumi new #15813

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
changes:
- type: feat
scope: cli/new
description: Add an 'instructions' option to Pulumi templates and display the instuctions at pulumi new
13 changes: 11 additions & 2 deletions pkg/cmd/pulumi/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"errors"
"fmt"
"io"
"io/fs"
"net/url"
"os"
Expand Down Expand Up @@ -76,13 +77,18 @@ type newArgs struct {
aiPrompt string
aiLanguage httpstate.PulumiAILanguage
templateMode bool
stdout io.Writer
}

func runNew(ctx context.Context, args newArgs) error {
if !args.interactive && !args.yes {
return errors.New("--yes must be passed in to proceed when running in non-interactive mode")
}

if args.stdout == nil {
args.stdout = os.Stdout
}

// Prepare options.
opts := display.Options{
Color: cmdutil.GetGlobalColorization(),
Expand Down Expand Up @@ -254,8 +260,11 @@ func runNew(ctx context.Context, args newArgs) error {
// Show instructions, if we're going to show at least one prompt.
hasAtLeastOnePrompt := (args.name == "") || (args.description == "") || (!args.generateOnly && args.stack == "")
if !args.yes && hasAtLeastOnePrompt {
fmt.Println("This command will walk you through creating a new Pulumi project.")
fmt.Println()
fmt.Fprintln(args.stdout, "This command will walk you through creating a new Pulumi project.")
fmt.Fprintln(args.stdout)
if template.Instructions != "" {
fmt.Fprintln(args.stdout, opts.Color.Colorize(template.Instructions))
}
fmt.Println(
opts.Color.Colorize(
colors.Highlight("Enter a value or leave blank to accept the (default), and press <ENTER>.",
Expand Down
31 changes: 31 additions & 0 deletions pkg/cmd/pulumi/new_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package main

import (
"bytes"
"context"
"crypto/rand"
"encoding/hex"
Expand Down Expand Up @@ -1119,3 +1120,33 @@ func TestSanitizeTemplate(t *testing.T) {
})
}
}

//nolint:paralleltest // changes directory for process
func TestPrintingInstructions(t *testing.T) {
templatePath, _ := filepath.Abs("./testdata/testtemplate")

tempdir := tempProjectDir(t)
chdir(t, tempdir)

uniqueProjectName := filepath.Base(tempdir)
orgStackName := fmt.Sprintf("%s/%s", currentUser(t), stackName)

var stdout bytes.Buffer
args := newArgs{
interactive: true,
generateOnly: true,
prompt: promptMock(uniqueProjectName, orgStackName),
secretsProvider: "default",
templateNameOrURL: templatePath,
stdout: &stdout,
}

err := runNew(context.Background(), args)
assert.NoError(t, err)

// Note that we implicitly test that the coloring symbols are removed correctly.
assert.Contains(t, stdout.String(), `This command will walk you through creating a new Pulumi project.

Test instructions
Line 2.`)
}
8 changes: 8 additions & 0 deletions pkg/cmd/pulumi/testdata/testtemplate/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: ${PROJECT}
description: ${DESCRIPTION}
runtime: nodejs
template:
description: Test description
instructions: |
<{%bold%}>Test instructions<{%reset%}>
Line 2.
2 changes: 2 additions & 0 deletions sdk/go/common/workspace/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ type ProjectTemplate struct {
DisplayName string `json:"displayName,omitempty" yaml:"displayName,omitempty"`
// Description is an optional description of the template.
Description string `json:"description,omitempty" yaml:"description,omitempty"`
// Instructions to be displayed when a user chooses the template.
Instructions string `json:"instructions,omitempty" yaml:"instructions,omitempty"`
// Quickstart contains optional text to be displayed after template creation.
Quickstart string `json:"quickstart,omitempty" yaml:"quickstart,omitempty"`
// Config is an optional template config.
Expand Down
7 changes: 7 additions & 0 deletions sdk/go/common/workspace/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,13 @@
"null"
]
},
"instructions":{
"description":"Instructions to be displayed when a user chooses the template.",
"type":[
"string",
"null"
]
},
"quickstart":{
"description":"Quickstart contains optional text to be displayed after template creation.",
"type":[
Expand Down
16 changes: 9 additions & 7 deletions sdk/go/common/workspace/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,14 @@ func (repo TemplateRepository) PolicyTemplates() ([]PolicyPackTemplate, error) {

// Template represents a project template.
type Template struct {
Dir string // The directory containing Pulumi.yaml.
Name string // The name of the template.
Description string // Description of the template.
Quickstart string // Optional text to be displayed after template creation.
Config map[string]ProjectTemplateConfigValue // Optional template config.
Important bool // Indicates whether the template should be listed by default.
Error error // Non-nil if the template is broken.
Dir string // The directory containing Pulumi.yaml.
Name string // The name of the template.
Description string // Description of the template.
Instructions string // Instructions to be displayed when a user chooses the template.
Quickstart string // Optional text to be displayed after template creation.
Config map[string]ProjectTemplateConfigValue // Optional template config.
Important bool // Indicates whether the template should be listed by default.
Error error // Non-nil if the template is broken.

ProjectName string // Name of the project.
ProjectDescription string // Optional description of the project.
Expand Down Expand Up @@ -470,6 +471,7 @@ func LoadTemplate(path string) (Template, error) {
}
if proj.Template != nil {
template.Description = proj.Template.Description
template.Instructions = proj.Template.Instructions
template.Quickstart = proj.Template.Quickstart
template.Config = proj.Template.Config
template.Important = proj.Template.Important
Expand Down