Skip to content

Commit

Permalink
Normalize name/title logic and translation
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffandersen committed Oct 26, 2017
1 parent 5cac1cc commit 4e16f13
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 163 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Project create failure due to Name/Title change
- Set-role should error before prompts
- Context would panic due to missing session
- Change logic for inferring object title from name

## [0.8.1] - 2017-10-24

Expand Down
5 changes: 4 additions & 1 deletion clients/teams.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
// TeamMembersCount groups a team name with the amount of members the team has
type TeamMembersCount struct {
Name string
Title string
Members int
}

Expand Down Expand Up @@ -62,7 +63,8 @@ func FetchTeamsMembersCount(ctx context.Context, c *iClient.Identity) ([]TeamMem

for _, t := range teams {
id := t.ID.String()
name := string(t.Body.Name)
name := string(t.Body.Label)
title := string(t.Body.Name)

go func() {
members, err := FetchTeamMembers(ctx, id, c)
Expand All @@ -74,6 +76,7 @@ func FetchTeamsMembersCount(ctx context.Context, c *iClient.Identity) ([]TeamMem

res <- TeamMembersCount{
Name: name,
Title: title,
Members: len(members),
}
}()
Expand Down
17 changes: 6 additions & 11 deletions cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func init() {
projectFlag(),
planFlag(),
regionFlag(),
titleFlag(),
cli.StringFlag{
Name: "product",
Usage: "Create a resource for this product",
Expand All @@ -62,7 +63,7 @@ func create(cliCtx *cli.Context) error {
return err
}

resourceTitle, err := optionalArgTitle(cliCtx, 0, "resource")
resourceName, resourceTitle, err := promptNameAndTitle(cliCtx, "resource", true, true)
if err != nil {
return err
}
Expand Down Expand Up @@ -156,7 +157,7 @@ func create(cliCtx *cli.Context) error {
var project *mModels.Project

if len(projects) > 0 {
pidx, _, err := prompts.SelectProject(projects, projectName, true)
pidx, _, err := prompts.SelectProject(projects, projectName, true, true)
if err != nil {
return prompts.HandleSelectError(err, "Could not select project.")
}
Expand All @@ -166,11 +167,6 @@ func create(cliCtx *cli.Context) error {
}
}

resourceTitle, err = prompts.ResourceTitle(resourceTitle, false)
if err != nil {
return cli.NewExitError("Could not name the resource: "+err.Error(), -1)
}

descriptor := "a custom resource"
if !custom {
descriptor = "an instance of " + string(product.Body.Name)
Expand All @@ -182,7 +178,7 @@ func create(cliCtx *cli.Context) error {
}

op, err := createResource(ctx, cfg, teamID, s, client.Provisioning, custom, product, plan, region,
project, resourceTitle, dontWait)
project, resourceName, resourceTitle, dontWait)
if err != nil {
return cli.NewExitError("Could not create resource: "+err.Error(), -1)
}
Expand All @@ -206,7 +202,7 @@ func create(cliCtx *cli.Context) error {

func createResource(ctx context.Context, cfg *config.Config, teamID *manifold.ID, s session.Session,
pClient *provisioning.Provisioning, custom bool, product *cModels.Product, plan *cModels.Plan,
region *cModels.Region, project *mModels.Project, resourceTitle string, dontWait bool) (*pModels.Operation, error) {
region *cModels.Region, project *mModels.Project, resourceName, resourceTitle string, dontWait bool) (*pModels.Operation, error) {

a, err := analytics.New(cfg, s)
if err != nil {
Expand Down Expand Up @@ -243,15 +239,14 @@ func createResource(ctx context.Context, cfg *config.Config, teamID *manifold.ID
typeStr := "operation"
version := int64(1)
state := "provision"
empty := ""
curTime := strfmt.DateTime(time.Now())
op := &pModels.Operation{
ID: ID,
Type: &typeStr,
Version: &version,
Body: &pModels.Provision{
ResourceID: resourceID,
Label: &empty,
Label: &resourceName,
Name: &resourceTitle,
Source: &source,
PlanID: planID,
Expand Down
2 changes: 1 addition & 1 deletion cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func initDir(cliCtx *cli.Context) error {
return errs.ErrNoProjects
}

pIdx, _, err := prompts.SelectProject(ps, projectName, true)
pIdx, _, err := prompts.SelectProject(ps, projectName, true, true)
if err != nil {
return prompts.HandleSelectError(err, "Could not select project.")
}
Expand Down
64 changes: 64 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package main
import (
"fmt"
"os"
"strings"

"github.com/urfave/cli"

"github.com/manifoldco/go-manifold"
"github.com/manifoldco/manifold-cli/config"
"github.com/manifoldco/manifold-cli/plugins"
"github.com/manifoldco/manifold-cli/prompts"
)

var cmds []cli.Command
Expand Down Expand Up @@ -67,3 +70,64 @@ var helpCommand = cli.Command{
return nil
},
}

// generateName makes a title lowercase and replace spaces with dashes
func generateName(title string) manifold.Label {
name := strings.Replace(strings.ToLower(title), " ", "-", -1)
return manifold.Label(name)
}

// generateTitle makes a name capitalized and replace dashes with spaaces
func generateTitle(name string) manifold.Name {
title := strings.Title(strings.Replace(name, "-", " ", -1))
return manifold.Name(title)
}

// promptNameAndTitle encapsulates the logic for accepting a name as the first
// positional argument (optionally), and a title flag (optionally)
// returning generated values accepted by the user
func promptNameAndTitle(ctx *cli.Context, objectName string, shouldInferTitle, allowEmpty bool) (string, string, error) {
// The user may supply a name value as the first positional arg
argName, err := optionalArgName(ctx, 0, "name")
if err != nil {
return "", "", err
}

// The user may supply a title value from a flag, validate it
flagTitle := ctx.String("title")

// Create the title based on the name argument
return createNameAndTitle(ctx, objectName, argName, flagTitle, shouldInferTitle, true, allowEmpty)
}

func createNameAndTitle(ctx *cli.Context, objectName, argName, flagTitle string, shouldInferTitle, shouldAccept, allowEmpty bool) (string, string, error) {
var name, title string

// If no name value is supplied, prompt for it
// otherwise validate the given value
shouldAcceptName := shouldAccept && argName != ""
nameValue, err := prompts.Name(objectName, argName, shouldAcceptName, allowEmpty)
if err != nil {
return name, title, err
}
name = nameValue

// We will automatically validate/accept a title given as flag
shouldAcceptTitle := shouldAccept && flagTitle != ""
// If we shouldn't infer the title, do not automatically accept a title value
if !shouldInferTitle {
shouldAcceptTitle = false
}
defaultTitle := flagTitle
if flagTitle == "" && shouldInferTitle {
// If no flag is present, we will infer the title from the validated name
defaultTitle = string(generateTitle(name))
}
titleValue, err := prompts.Title(objectName, defaultTitle, shouldAcceptTitle, allowEmpty)
if err != nil {
return name, title, err
}
title = titleValue

return name, title, nil
}
61 changes: 24 additions & 37 deletions cmd/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"os"
"strings"

"time"

Expand Down Expand Up @@ -38,8 +37,8 @@ func init() {
{
Name: "create",
Usage: "Create a new project",
Flags: teamFlags,
ArgsUsage: "[project-title]",
Flags: append(teamFlags, titleFlag()),
ArgsUsage: "[project-name]",
Action: middleware.Chain(middleware.EnsureSession,
middleware.LoadTeamPrefs, createProjectCmd),
},
Expand Down Expand Up @@ -117,21 +116,15 @@ func createProjectCmd(cliCtx *cli.Context) error {
return errUserActionAsTeam
}

projectTitle, err := optionalArgTitle(cliCtx, 0, "title")
projectName, projectTitle, err := promptNameAndTitle(cliCtx, "project", true, false)
if err != nil {
return err
}

autoSelect := projectTitle != ""
projectTitle, err = prompts.ProjectTitle(projectTitle, autoSelect)
if err != nil {
return prompts.HandleSelectError(err, "Failed to select project title")
}

params := projectClient.NewPostProjectsParamsWithContext(ctx)
body := &mModels.CreateProjectBody{
Name: manifold.Name(projectTitle),
Label: generateName(projectTitle),
Label: manifold.Label(projectName),
}

if teamID == nil {
Expand Down Expand Up @@ -189,7 +182,7 @@ func listProjectsCmd(cliCtx *cli.Context) error {
fmt.Fprintf(w, "%s\n\n", color.Bold("Project"))

for _, project := range projects {
fmt.Fprintf(w, "%s\n", project.Body.Label)
fmt.Fprintf(w, "%s (%s)\n", project.Body.Label, color.Faint(project.Body.Name))
}
return w.Flush()
}
Expand All @@ -201,49 +194,49 @@ func updateProjectCmd(cliCtx *cli.Context) error {
return err
}

teamID, err := validateTeamID(cliCtx)
if err != nil {
return err
}

projectName, err := optionalArgName(cliCtx, 0, "project")
if err != nil {
return err
}

newProjectTitle, err := validateTitle(cliCtx, "title", "project")
teamID, err := validateTeamID(cliCtx)
if err != nil {
return err
}

projectDescription := cliCtx.String("description")

client, err := api.New(api.Marketplace)
if err != nil {
return err
}

p, err := selectProject(ctx, projectName, teamID, client.Marketplace)
p, err := selectProject(ctx, projectName, teamID, client.Marketplace, false)
if err != nil {
return err
}

autoSelectTitle := newProjectTitle != ""
newProjectTitle, err = prompts.ProjectTitle(newProjectTitle, autoSelectTitle)
providedTitle := cliCtx.String("title")
if providedTitle == "" {
providedTitle = string(p.Body.Name)
}
newName, newTitle, err := createNameAndTitle(cliCtx, "project", string(p.Body.Label), providedTitle, true, false, false)
if err != nil {
return prompts.HandleSelectError(err, "Could not select project")
return err
}

projectDescription := cliCtx.String("description")
autoSelectDescription := projectDescription != ""
if projectDescription == "" {
projectDescription = p.Body.Description
}
projectDescription, err = prompts.ProjectDescription(projectDescription, autoSelectDescription)
if err != nil {
return prompts.HandleSelectError(err, "Could not add description to project")
}

params := projectClient.NewPatchProjectsIDParamsWithContext(ctx)
body := &mModels.PublicUpdateProjectBody{
Name: manifold.Name(newProjectTitle),
Label: generateName(newProjectTitle),
Name: manifold.Name(newTitle),
Label: manifold.Label(newName),
}

if projectDescription != "" {
Expand All @@ -264,7 +257,7 @@ func updateProjectCmd(cliCtx *cli.Context) error {
}

spin.Stop()
fmt.Printf("\nYour project \"%s\" has been updated\n", newProjectTitle)
fmt.Printf("\nYour project \"%s\" has been updated\n", newTitle)
return nil
}

Expand Down Expand Up @@ -295,7 +288,7 @@ func deleteProjectCmd(cliCtx *cli.Context) error {
return err
}

p, err := selectProject(ctx, projectName, teamID, client.Marketplace)
p, err := selectProject(ctx, projectName, teamID, client.Marketplace, true)
if err != nil {
return err
}
Expand Down Expand Up @@ -398,7 +391,7 @@ func addProjectCmd(cliCtx *cli.Context) error {
return cli.NewExitError(fmt.Sprintf("Failed to fetch projects list: %s", err), -1)
}

p, err := selectProject(ctx, projectName, teamID, client.Marketplace)
p, err := selectProject(ctx, projectName, teamID, client.Marketplace, true)
if err != nil {
return err
}
Expand Down Expand Up @@ -637,7 +630,7 @@ func updateResourceProject(ctx context.Context, uid, tid *manifold.ID, r *mModel
}

// selectProject prompts a user to select a project (if selects the one provided automatically)
func selectProject(ctx context.Context, projectName string, teamID *manifold.ID, marketplaceClient *mClient.Marketplace) (*mModels.Project, error) {
func selectProject(ctx context.Context, projectName string, teamID *manifold.ID, marketplaceClient *mClient.Marketplace, showResult bool) (*mModels.Project, error) {
projects, err := clients.FetchProjects(ctx, marketplaceClient, teamID)
if err != nil {
return nil, cli.NewExitError(fmt.Sprintf("Failed to fetch list of projects: %s", err), -1)
Expand All @@ -647,17 +640,11 @@ func selectProject(ctx context.Context, projectName string, teamID *manifold.ID,
return nil, errs.ErrNoProjects
}

idx, _, err := prompts.SelectProject(projects, projectName, false)
idx, _, err := prompts.SelectProject(projects, projectName, false, showResult)
if err != nil {
return nil, prompts.HandleSelectError(err, "Could not select project")
}

p := projects[idx]
return p, nil
}

// generateName makes a title lowercase and replace spaces with dashes
func generateName(title string) manifold.Label {
name := strings.Replace(strings.ToLower(title), " ", "-", -1)
return manifold.Label(name)
}
Loading

0 comments on commit 4e16f13

Please sign in to comment.