identity: some UX cleanup

Michael Muré created

Change summary

cache/bug_excerpt.go    | 10 +++++-----
cache/filter.go         |  2 +-
commands/root.go        | 23 +++++++++++++++++++++++
commands/termui.go      |  2 +-
commands/user_create.go |  3 ++-
identity/identity.go    | 20 ++++++++++++++++----
input/prompt.go         |  6 +++---
7 files changed, 51 insertions(+), 15 deletions(-)

Detailed changes

cache/bug_excerpt.go 🔗

@@ -8,6 +8,11 @@ import (
 	"github.com/MichaelMure/git-bug/util/lamport"
 )
 
+// Package initialisation used to register the type for (de)serialization
+func init() {
+	gob.Register(BugExcerpt{})
+}
+
 // BugExcerpt hold a subset of the bug values to be able to sort and filter bugs
 // efficiently without having to read and compile each raw bugs.
 type BugExcerpt struct {
@@ -63,11 +68,6 @@ func NewBugExcerpt(b bug.Interface, snap *bug.Snapshot) *BugExcerpt {
 	return e
 }
 
-// Package initialisation used to register the type for (de)serialization
-func init() {
-	gob.Register(BugExcerpt{})
-}
-
 /*
  * Sorting
  */

cache/filter.go 🔗

@@ -6,7 +6,7 @@ import (
 	"github.com/MichaelMure/git-bug/bug"
 )
 
-// Filter is a functor that match a subset of bugs
+// Filter is a predicate that match a subset of bugs
 type Filter func(repoCache *RepoCache, excerpt *BugExcerpt) bool
 
 // StatusFilter return a Filter that match a bug status

commands/root.go 🔗

@@ -6,6 +6,7 @@ import (
 	"os"
 
 	"github.com/MichaelMure/git-bug/bug"
+	"github.com/MichaelMure/git-bug/identity"
 	"github.com/MichaelMure/git-bug/repository"
 	"github.com/spf13/cobra"
 )
@@ -53,6 +54,7 @@ func Execute() {
 	}
 }
 
+// loadRepo is a pre-run function that load the repository for use in a command
 func loadRepo(cmd *cobra.Command, args []string) error {
 	cwd, err := os.Getwd()
 	if err != nil {
@@ -70,3 +72,24 @@ func loadRepo(cmd *cobra.Command, args []string) error {
 
 	return nil
 }
+
+// loadRepoEnsureUser is the same as loadRepo, but also ensure that the user has configured
+// an identity. Use this pre-run function when an error after using the configured user won't
+// do.
+func loadRepoEnsureUser(cmd *cobra.Command, args []string) error {
+	err := loadRepo(cmd, args)
+	if err != nil {
+		return err
+	}
+
+	set, err := identity.IsUserIdentitySet(repo)
+	if err != nil {
+		return err
+	}
+
+	if !set {
+		return identity.ErrNoIdentitySet
+	}
+
+	return nil
+}

commands/termui.go 🔗

@@ -21,7 +21,7 @@ func runTermUI(cmd *cobra.Command, args []string) error {
 var termUICmd = &cobra.Command{
 	Use:     "termui",
 	Short:   "Launch the terminal UI",
-	PreRunE: loadRepo,
+	PreRunE: loadRepoEnsureUser,
 	RunE:    runTermUI,
 }
 

commands/user_create.go 🔗

@@ -2,6 +2,7 @@ package commands
 
 import (
 	"fmt"
+	"os"
 
 	"github.com/MichaelMure/git-bug/cache"
 	"github.com/MichaelMure/git-bug/input"
@@ -57,7 +58,7 @@ func runUserCreate(cmd *cobra.Command, args []string) error {
 		return err
 	}
 
-	fmt.Println()
+	_, _ = fmt.Fprintln(os.Stderr)
 	fmt.Println(id.Id())
 
 	return nil

identity/identity.go 🔗

@@ -4,6 +4,7 @@ package identity
 import (
 	"encoding/json"
 	"fmt"
+	"os"
 	"strings"
 	"time"
 
@@ -20,6 +21,8 @@ const versionEntryName = "version"
 const identityConfigKey = "git-bug.identity"
 
 var ErrNonFastForwardMerge = errors.New("non fast-forward identity merge")
+var ErrNoIdentitySet = errors.New("user identity first needs to be created using \"git bug user create\"")
+var ErrMultipleIdentitiesSet = errors.New("multiple user identities set")
 
 var _ Interface = &Identity{}
 
@@ -213,7 +216,7 @@ func IsUserIdentitySet(repo repository.RepoCommon) (bool, error) {
 	}
 
 	if len(configs) > 1 {
-		return false, fmt.Errorf("multiple identity config exist")
+		return false, ErrMultipleIdentitiesSet
 	}
 
 	return len(configs) == 1, nil
@@ -232,11 +235,11 @@ func GetUserIdentity(repo repository.Repo) (*Identity, error) {
 	}
 
 	if len(configs) == 0 {
-		return nil, fmt.Errorf("no identity set")
+		return nil, ErrNoIdentitySet
 	}
 
 	if len(configs) > 1 {
-		return nil, fmt.Errorf("multiple identity config exist")
+		return nil, ErrMultipleIdentitiesSet
 	}
 
 	var id string
@@ -244,7 +247,16 @@ func GetUserIdentity(repo repository.Repo) (*Identity, error) {
 		id = val
 	}
 
-	return ReadLocal(repo, id)
+	i, err := ReadLocal(repo, id)
+	if err == ErrIdentityNotExist {
+		innerErr := repo.RmConfigs(identityConfigKey)
+		if innerErr != nil {
+			_, _ = fmt.Fprintln(os.Stderr, errors.Wrap(innerErr, "can't clear user identity").Error())
+		}
+		return nil, err
+	}
+
+	return i, nil
 }
 
 func (i *Identity) AddVersion(version *Version) {

input/prompt.go 🔗

@@ -18,9 +18,9 @@ func PromptValueRequired(name string, preValue string) (string, error) {
 func promptValue(name string, preValue string, required bool) (string, error) {
 	for {
 		if preValue != "" {
-			fmt.Printf("%s [%s]: ", name, preValue)
+			_, _ = fmt.Fprintf(os.Stderr, "%s [%s]: ", name, preValue)
 		} else {
-			fmt.Printf("%s: ", name)
+			_, _ = fmt.Fprintf(os.Stderr, "%s: ", name)
 		}
 
 		line, err := bufio.NewReader(os.Stdin).ReadString('\n')
@@ -35,7 +35,7 @@ func promptValue(name string, preValue string, required bool) (string, error) {
 		}
 
 		if required && line == "" {
-			fmt.Printf("%s is empty\n", name)
+			_, _ = fmt.Fprintf(os.Stderr, "%s is empty\n", name)
 			continue
 		}