Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions cmd/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type bundleNew struct {
description string
templateName string
connections []string
artifacts []string
outputDir string
paramsDir string
}
Expand Down Expand Up @@ -88,6 +89,7 @@ func NewCmdBundle() *cobra.Command {
bundleNewCmd.Flags().StringVarP(&bundleNewInput.name, "name", "n", "", "Name of the new bundle. Setting this along with --template-name will disable the interactive prompt.")
bundleNewCmd.Flags().StringVarP(&bundleNewInput.description, "description", "d", "", "Description of the new bundle")
bundleNewCmd.Flags().StringVarP(&bundleNewInput.templateName, "template-name", "t", "", "Name of the bundle template to use. Setting this along with --name will disable the interactive prompt.")
bundleNewCmd.Flags().StringSliceVarP(&bundleNewInput.artifacts, "artifacts", "a", []string{}, "Artifacts and names to add to the bundle - example: network=massdriver/vpc")
bundleNewCmd.Flags().StringSliceVarP(&bundleNewInput.connections, "connections", "c", []string{}, "Connections and names to add to the bundle - example: network=massdriver/vpc")
bundleNewCmd.Flags().StringVarP(&bundleNewInput.outputDir, "output-directory", "o", ".", "Directory to output the new bundle")
bundleNewCmd.Flags().StringVarP(&bundleNewInput.paramsDir, "params-directory", "p", "", "Path with existing params to use - opentofu module directory or helm chart values.yaml")
Expand Down Expand Up @@ -209,13 +211,26 @@ func runBundleNewFlags(input *bundleNew) (*templatecache.TemplateData, error) {
}
}

artifactData := make([]templatecache.Artifact, len(input.artifacts))
for i, art := range input.artifacts {
parts := strings.Split(art, "=")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid connection argument: %s", art)
}
artifactData[i] = templatecache.Artifact{
ArtifactDefinition: parts[1],
Name: parts[0],
}
}

templateData := &templatecache.TemplateData{
TemplateRepo: "/massdriver-cloud/application-templates",
OutputDir: input.outputDir,
Name: input.name,
Description: input.description,
TemplateName: input.templateName,
Connections: connectionData,
Artifacts: artifactData,
ExistingParamsPath: input.paramsDir,
}

Expand Down
1 change: 1 addition & 0 deletions docs/generated/mass_bundle_new.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ mass bundle new [flags]
### Options

```
-a, --artifacts strings Artifacts and names to add to the bundle - example: network=massdriver/vpc
-c, --connections strings Connections and names to add to the bundle - example: network=massdriver/vpc
-d, --description string Description of the new bundle
-h, --help help for new
Expand Down
75 changes: 63 additions & 12 deletions pkg/bundle/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ import (

var (
// These look eerily similar, the difference being - vs _
baseRegex = "^[a-z]+[a-z0-9%s]*[a-z0-9]+$"
bundleNameFormat = regexp.MustCompile(fmt.Sprintf(baseRegex, "-"))
connectionNameFormat = regexp.MustCompile(fmt.Sprintf(baseRegex, "_"))
baseRegex = "^[a-z]+[a-z0-9%s]*[a-z0-9]+$"
bundleNameFormat = regexp.MustCompile(fmt.Sprintf(baseRegex, "-"))
linkNameFormat = regexp.MustCompile(fmt.Sprintf(baseRegex, "_"))

baseNameError = "name must be 2 to 53 characters, can only include lowercase letters, numbers and %s, must start with a letter and end with an alphanumeric character [abc%s123, my%scool%sthing]"
bundleNameError = fmt.Sprintf(baseNameError, "dashes", "-", "-", "-")
connNameError = fmt.Sprintf(baseNameError, "underscores", "_", "_", "_")
linkNameError = fmt.Sprintf(baseNameError, "underscores", "_", "_", "_")
)

var massdriverArtifactDefinitions map[string]map[string]any
Expand All @@ -33,7 +33,8 @@ var promptsNew = []func(t *templatecache.TemplateData) error{
getName,
getDescription,
getTemplate,
GetConnections,
getConnections,
getArtifacts,
getOutputDir,
}

Expand Down Expand Up @@ -138,17 +139,17 @@ func getTemplate(t *templatecache.TemplateData) error {
return nil
}

func connNameValidate(name string) error {
func linkNameValidate(name string) error {
if len(name) < 2 || len(name) > 53 {
return errors.New(connNameError)
return errors.New(linkNameError)
}
if !connectionNameFormat.MatchString(name) {
return errors.New(connNameError)
if !linkNameFormat.MatchString(name) {
return errors.New(linkNameError)
}
return nil
}

func GetConnections(t *templatecache.TemplateData) error {
func getConnections(t *templatecache.TemplateData) error {
none := "(None)"

artifactDefinitionsTypes := []string{}
Expand All @@ -175,7 +176,7 @@ func GetConnections(t *templatecache.TemplateData) error {
for _, currentDep := range selectedDeps {
if currentDep == none {
if len(selectedDeps) > 1 {
return fmt.Errorf("if selecting %v, you cannot select other dependecies. selected %#v", none, selectedDeps)
return fmt.Errorf("if selecting %v, you cannot select other connections. selected %#v", none, selectedDeps)
}
return nil
}
Expand All @@ -184,7 +185,7 @@ func GetConnections(t *templatecache.TemplateData) error {

prompt := promptui.Prompt{
Label: `Name`,
Validate: connNameValidate,
Validate: linkNameValidate,
}

result, errName := prompt.Run()
Expand All @@ -202,6 +203,56 @@ func GetConnections(t *templatecache.TemplateData) error {
return nil
}

func getArtifacts(t *templatecache.TemplateData) error {
none := "(None)"

artifactDefinitionsTypes := []string{}
// in 1.23 we can use maps.Keys(), but until then we'll extract the keys manually
for adt := range massdriverArtifactDefinitions {
artifactDefinitionsTypes = append(artifactDefinitionsTypes, adt)
}
sort.StringSlice(artifactDefinitionsTypes).Sort()

var selectedArts []string
multiselect := &survey.MultiSelect{
Message: "What artifacts do you need?\n If you don't need any, just hit enter or select (None)\n",
Options: artifactDefinitionsTypes,
}

err := survey.AskOne(multiselect, &selectedArts)
if err != nil {
return err
}

var artMap []templatecache.Artifact

for _, currentArt := range selectedArts {
if currentArt == none {
if len(selectedArts) > 1 {
return fmt.Errorf("if selecting %v, you cannot select other artifacts. selected %#v", none, selectedArts)
}
return nil
}

fmt.Printf("Please enter a name for the artifact: \"%v\"\nThis will be the variable name used to reference it in your app|bundle IaC\n", currentArt)

prompt := promptui.Prompt{
Label: `Name`,
Validate: linkNameValidate,
}

result, errName := prompt.Run()
if errName != nil {
return errName
}

artMap = append(artMap, templatecache.Artifact{Name: result, ArtifactDefinition: currentArt})
}

t.Artifacts = artMap
return nil
}

func removeIgnoredTemplateDirectories(templates []templatecache.TemplateList) []string {
filteredTemplates := []string{}
for _, repo := range templates {
Expand Down
6 changes: 3 additions & 3 deletions pkg/bundle/prompt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ func TestNameValidate(t *testing.T) {
}
}

func TestConnNameValidate(t *testing.T) {
func TestLinkNameValidate(t *testing.T) {
goodValues := []string{
"ab", "abc", "a1", "a_1", "a__1__2__b",
strings.Repeat("a", 53),
}
for _, val := range goodValues {
if err := connNameValidate(val); err != nil {
if err := linkNameValidate(val); err != nil {
t.Errorf("expected no error for '%s': %v", val, err)
}
}
Expand All @@ -52,7 +52,7 @@ func TestConnNameValidate(t *testing.T) {
"1111", "1-1-1", "----", strings.Repeat("a", 54),
}
for _, val := range badValues {
if err := connNameValidate(val); err == nil {
if err := linkNameValidate(val); err == nil {
t.Errorf("expected error for '%s'", val)
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/bundle/publish_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func TestPackageBundle(t *testing.T) {
}

if len(manifest.Layers) != len(tc.expectedLayers) {
for title, _ := range tc.expectedLayers {
for title := range tc.expectedLayers {
found := false
for _, layer := range manifest.Layers {
if layer.Annotations[ocispec.AnnotationTitle] == title {
Expand Down
6 changes: 6 additions & 0 deletions pkg/templatecache/template_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type TemplateData struct {
OutputDir string `json:"outputDir"`
Type string `json:"type"`
Connections []Connection `json:"connections"`
Artifacts []Artifact `json:"artifacts"`
Envs map[string]string `json:"envs"`

// ParamsSchema is a YAML formatted string
Expand All @@ -29,6 +30,11 @@ type TemplateData struct {
RepoNameEncoded string `json:"repoNameEncoded"`
}

type Artifact struct {
Name string `json:"name"`
ArtifactDefinition string `json:"artifact_definition"`
}

type Connection struct {
Name string `json:"name"`
ArtifactDefinition string `json:"artifact_definition"`
Expand Down
Loading