Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions pkg/bundle/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,28 @@ var ignoredTemplateDirs = map[string]bool{"alpha": true}
func getTemplate(t *templates.TemplateData) error {
templateList, err := templates.List()
if err != nil {
if errors.Is(err, templates.ErrNotConfigured) {
fmt.Println()
fmt.Println("💡 Did you know? You can set up bundle templates for faster development!")
fmt.Println(" Set MASSDRIVER_TEMPLATES_PATH or templates_path in your config profile.")
fmt.Println(" See: https://docs.massdriver.cloud/guides/bundle-templates")
fmt.Println()
fmt.Println(" Continuing without a template - we'll generate a basic massdriver.yaml for you.")
fmt.Println()
t.TemplateName = ""
return nil
}
return err
}

filteredTemplates := removeIgnoredTemplateDirectories(templateList)

if len(filteredTemplates) == 0 {
fmt.Println("No templates found in templates path. Generating a basic massdriver.yaml.")
t.TemplateName = ""
return nil
}

prompt := promptui.Select{
Label: "Template",
Items: filteredTemplates,
Expand Down
69 changes: 69 additions & 0 deletions pkg/commands/bundle/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@ package bundle

import (
"fmt"
"os"
"path"
"path/filepath"

"github.com/massdriver-cloud/mass/pkg/bundle"
"github.com/massdriver-cloud/mass/pkg/provisioners"
"github.com/massdriver-cloud/mass/pkg/templates"
)

func RunNew(data *templates.TemplateData) error {
if data.TemplateName == "" {
return generateBasicBundle(data)
}

if err := templates.Render(data); err != nil {
return fmt.Errorf("failed to render template: %w", err)
}
Expand All @@ -31,3 +37,66 @@ func RunNew(data *templates.TemplateData) error {

return nil
}

func generateBasicBundle(data *templates.TemplateData) error {
if err := os.MkdirAll(data.OutputDir, 0750); err != nil {
return fmt.Errorf("failed to create output directory: %w", err)
}

content := generateMassdriverYAML(data)

outputPath := filepath.Join(data.OutputDir, "massdriver.yaml")
if err := os.WriteFile(outputPath, []byte(content), 0644); err != nil {
return fmt.Errorf("failed to write massdriver.yaml: %w", err)
}

return nil
}

func generateMassdriverYAML(data *templates.TemplateData) string {
yaml := fmt.Sprintf(`# Massdriver Bundle Specification
# https://docs.massdriver.cloud/guides/bundle-yaml-spec

schema: draft-07
name: %q
description: %q
source_url: ""

# steps:
# - path: src
# provisioner: opentofu
# See provisioners: https://docs.massdriver.cloud/provisioners/overview

params:
required: []
properties: {}

`, data.Name, data.Description)

// Add connections
yaml += "connections:\n"
if len(data.Connections) == 0 {
yaml += " required: []\n properties: {}\n"
} else {
yaml += " required:\n"
for _, conn := range data.Connections {
yaml += fmt.Sprintf(" - %s\n", conn.Name)
}
yaml += " properties:\n"
for _, conn := range data.Connections {
yaml += fmt.Sprintf(" %s:\n $ref: %s\n", conn.Name, conn.ArtifactDefinition)
}
}

yaml += `
artifacts:
required: []
properties: {}

ui:
ui:order:
- "*"
`

return yaml
}
84 changes: 84 additions & 0 deletions pkg/commands/bundle/new_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,90 @@ func TestTemplateRender(t *testing.T) {
}
}

func TestGenerateBasicBundleWithoutTemplate(t *testing.T) {
testDir := t.TempDir()
writePath := path.Join(testDir, "my-bundle")

data := &templates.TemplateData{
OutputDir: writePath,
Name: "my-test-bundle",
Description: "A test bundle without a template",
TemplateName: "", // No template
Connections: []templates.Connection{
{Name: "vpc", ArtifactDefinition: "massdriver/aws-vpc"},
{Name: "database", ArtifactDefinition: "massdriver/aws-rds-postgres"},
},
}

err := cmdbundle.RunNew(data)
checkErr(err, t)

// Verify massdriver.yaml was created
content, err := os.ReadFile(path.Join(writePath, "massdriver.yaml"))
checkErr(err, t)

got := &bundle.Bundle{}
err = yaml.Unmarshal(content, got)
checkErr(err, t)

if got.Name != "my-test-bundle" {
t.Errorf("Expected name to be 'my-test-bundle' but got %q", got.Name)
}

if got.Description != "A test bundle without a template" {
t.Errorf("Expected description to be 'A test bundle without a template' but got %q", got.Description)
}

// Check connections
wantConnections := map[string]any{
"required": []any{"vpc", "database"},
"properties": map[string]any{
"vpc": map[string]any{"$ref": "massdriver/aws-vpc"},
"database": map[string]any{"$ref": "massdriver/aws-rds-postgres"},
},
}

if !reflect.DeepEqual(got.Connections, wantConnections) {
t.Errorf("Expected connections to be %v but got %v", wantConnections, got.Connections)
}
}

func TestGenerateBasicBundleNoConnections(t *testing.T) {
testDir := t.TempDir()
writePath := path.Join(testDir, "simple-bundle")

data := &templates.TemplateData{
OutputDir: writePath,
Name: "simple-bundle",
Description: "A simple bundle",
TemplateName: "", // No template
Connections: []templates.Connection{},
}

err := cmdbundle.RunNew(data)
checkErr(err, t)

content, err := os.ReadFile(path.Join(writePath, "massdriver.yaml"))
checkErr(err, t)

got := &bundle.Bundle{}
err = yaml.Unmarshal(content, got)
checkErr(err, t)

if got.Name != "simple-bundle" {
t.Errorf("Expected name to be 'simple-bundle' but got %q", got.Name)
}

wantConnections := map[string]any{
"required": []any{},
"properties": map[string]any{},
}

if !reflect.DeepEqual(got.Connections, wantConnections) {
t.Errorf("Expected connections to be %v but got %v", wantConnections, got.Connections)
}
}

func mockTemplateData(writePath string) *templates.TemplateData {
return &templates.TemplateData{
OutputDir: writePath,
Expand Down
Loading