Merge pull request #417 from MichaelMure/remove-legacy-identity

Michael Muré created

identity: remove support for legacy identity

Change summary

bug/op_add_comment_test.go  |  15 ++
bug/op_create_test.go       |  17 ++
bug/op_edit_comment_test.go |  20 ++
bug/op_label_change_test.go |  17 ++
bug/op_noop_test.go         |  17 ++
bug/op_set_metadata_test.go |  21 +++
bug/op_set_status_test.go   |  17 ++
bug/op_set_title_test.go    |  17 ++
bug/operation_pack.go       |  11 +
bug/operation_pack_test.go  |  29 +++-
bug/operation_test.go       |  12 +-
cache/bug_excerpt.go        |  12 -
cache/filter.go             |  15 -
cache/repo_cache.go         |   3 
commands/ls.go              |  40 ++-----
identity/bare.go            | 218 ---------------------------------------
identity/bare_test.go       |  37 ------
identity/common.go          |  13 --
identity/identity.go        |   2 
identity/version.go         |   1 
termui/bug_table.go         |  22 +--
21 files changed, 178 insertions(+), 378 deletions(-)

Detailed changes

bug/op_add_comment_test.go 🔗

@@ -6,12 +6,18 @@ import (
 	"time"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 
 	"github.com/MichaelMure/git-bug/identity"
+	"github.com/MichaelMure/git-bug/repository"
 )
 
 func TestAddCommentSerialize(t *testing.T) {
-	var rene = identity.NewBare("René Descartes", "rene@descartes.fr")
+	repo := repository.NewMockRepoForTest()
+	rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
+	err := rene.Commit(repo)
+	require.NoError(t, err)
+
 	unix := time.Now().Unix()
 	before := NewAddCommentOp(rene, unix, "message", nil)
 
@@ -22,9 +28,12 @@ func TestAddCommentSerialize(t *testing.T) {
 	err = json.Unmarshal(data, &after)
 	assert.NoError(t, err)
 
-	// enforce creating the IDs
+	// enforce creating the ID
 	before.Id()
-	rene.Id()
+
+	// Replace the identity stub with the real thing
+	assert.Equal(t, rene.Id(), after.base().Author.Id())
+	after.Author = rene
 
 	assert.Equal(t, before, &after)
 }

bug/op_create_test.go 🔗

@@ -6,14 +6,16 @@ import (
 	"time"
 
 	"github.com/MichaelMure/git-bug/identity"
+	"github.com/MichaelMure/git-bug/repository"
 	"github.com/MichaelMure/git-bug/util/timestamp"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func TestCreate(t *testing.T) {
 	snapshot := Snapshot{}
 
-	rene := identity.NewBare("René Descartes", "rene@descartes.fr")
+	rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
 	unix := time.Now().Unix()
 
 	create := NewCreateOp(rene, unix, "title", "message", nil)
@@ -50,7 +52,11 @@ func TestCreate(t *testing.T) {
 }
 
 func TestCreateSerialize(t *testing.T) {
-	var rene = identity.NewBare("René Descartes", "rene@descartes.fr")
+	repo := repository.NewMockRepoForTest()
+	rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
+	err := rene.Commit(repo)
+	require.NoError(t, err)
+
 	unix := time.Now().Unix()
 	before := NewCreateOp(rene, unix, "title", "message", nil)
 
@@ -61,9 +67,12 @@ func TestCreateSerialize(t *testing.T) {
 	err = json.Unmarshal(data, &after)
 	assert.NoError(t, err)
 
-	// enforce creating the IDs
+	// enforce creating the ID
 	before.Id()
-	rene.Id()
+
+	// Replace the identity stub with the real thing
+	assert.Equal(t, rene.Id(), after.base().Author.Id())
+	after.Author = rene
 
 	assert.Equal(t, before, &after)
 }

bug/op_edit_comment_test.go 🔗

@@ -9,12 +9,17 @@ import (
 	"github.com/stretchr/testify/require"
 
 	"github.com/MichaelMure/git-bug/identity"
+	"github.com/MichaelMure/git-bug/repository"
 )
 
 func TestEdit(t *testing.T) {
 	snapshot := Snapshot{}
 
-	rene := identity.NewBare("René Descartes", "rene@descartes.fr")
+	repo := repository.NewMockRepoForTest()
+	rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
+	err := rene.Commit(repo)
+	require.NoError(t, err)
+
 	unix := time.Now().Unix()
 
 	create := NewCreateOp(rene, unix, "title", "create", nil)
@@ -74,7 +79,11 @@ func TestEdit(t *testing.T) {
 }
 
 func TestEditCommentSerialize(t *testing.T) {
-	var rene = identity.NewBare("René Descartes", "rene@descartes.fr")
+	repo := repository.NewMockRepoForTest()
+	rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
+	err := rene.Commit(repo)
+	require.NoError(t, err)
+
 	unix := time.Now().Unix()
 	before := NewEditCommentOp(rene, unix, "target", "message", nil)
 
@@ -85,9 +94,12 @@ func TestEditCommentSerialize(t *testing.T) {
 	err = json.Unmarshal(data, &after)
 	assert.NoError(t, err)
 
-	// enforce creating the IDs
+	// enforce creating the ID
 	before.Id()
-	rene.Id()
+
+	// Replace the identity stub with the real thing
+	assert.Equal(t, rene.Id(), after.base().Author.Id())
+	after.Author = rene
 
 	assert.Equal(t, before, &after)
 }

bug/op_label_change_test.go 🔗

@@ -5,12 +5,20 @@ import (
 	"testing"
 	"time"
 
+	"github.com/stretchr/testify/require"
+
 	"github.com/MichaelMure/git-bug/identity"
+	"github.com/MichaelMure/git-bug/repository"
+
 	"github.com/stretchr/testify/assert"
 )
 
 func TestLabelChangeSerialize(t *testing.T) {
-	var rene = identity.NewBare("René Descartes", "rene@descartes.fr")
+	repo := repository.NewMockRepoForTest()
+	rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
+	err := rene.Commit(repo)
+	require.NoError(t, err)
+
 	unix := time.Now().Unix()
 	before := NewLabelChangeOperation(rene, unix, []Label{"added"}, []Label{"removed"})
 
@@ -21,9 +29,12 @@ func TestLabelChangeSerialize(t *testing.T) {
 	err = json.Unmarshal(data, &after)
 	assert.NoError(t, err)
 
-	// enforce creating the IDs
+	// enforce creating the ID
 	before.Id()
-	rene.Id()
+
+	// Replace the identity stub with the real thing
+	assert.Equal(t, rene.Id(), after.base().Author.Id())
+	after.Author = rene
 
 	assert.Equal(t, before, &after)
 }

bug/op_noop_test.go 🔗

@@ -5,12 +5,20 @@ import (
 	"testing"
 	"time"
 
+	"github.com/stretchr/testify/require"
+
 	"github.com/MichaelMure/git-bug/identity"
+	"github.com/MichaelMure/git-bug/repository"
+
 	"github.com/stretchr/testify/assert"
 )
 
 func TestNoopSerialize(t *testing.T) {
-	var rene = identity.NewBare("René Descartes", "rene@descartes.fr")
+	repo := repository.NewMockRepoForTest()
+	rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
+	err := rene.Commit(repo)
+	require.NoError(t, err)
+
 	unix := time.Now().Unix()
 	before := NewNoOpOp(rene, unix)
 
@@ -21,9 +29,12 @@ func TestNoopSerialize(t *testing.T) {
 	err = json.Unmarshal(data, &after)
 	assert.NoError(t, err)
 
-	// enforce creating the IDs
+	// enforce creating the ID
 	before.Id()
-	rene.Id()
+
+	// Replace the identity stub with the real thing
+	assert.Equal(t, rene.Id(), after.base().Author.Id())
+	after.Author = rene
 
 	assert.Equal(t, before, &after)
 }

bug/op_set_metadata_test.go 🔗

@@ -6,6 +6,8 @@ import (
 	"time"
 
 	"github.com/MichaelMure/git-bug/identity"
+	"github.com/MichaelMure/git-bug/repository"
+
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
@@ -13,7 +15,11 @@ import (
 func TestSetMetadata(t *testing.T) {
 	snapshot := Snapshot{}
 
-	rene := identity.NewBare("René Descartes", "rene@descartes.fr")
+	repo := repository.NewMockRepoForTest()
+	rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
+	err := rene.Commit(repo)
+	require.NoError(t, err)
+
 	unix := time.Now().Unix()
 
 	create := NewCreateOp(rene, unix, "title", "create", nil)
@@ -93,7 +99,11 @@ func TestSetMetadata(t *testing.T) {
 }
 
 func TestSetMetadataSerialize(t *testing.T) {
-	var rene = identity.NewBare("René Descartes", "rene@descartes.fr")
+	repo := repository.NewMockRepoForTest()
+	rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
+	err := rene.Commit(repo)
+	require.NoError(t, err)
+
 	unix := time.Now().Unix()
 	before := NewSetMetadataOp(rene, unix, "message", map[string]string{
 		"key1": "value1",
@@ -107,9 +117,12 @@ func TestSetMetadataSerialize(t *testing.T) {
 	err = json.Unmarshal(data, &after)
 	assert.NoError(t, err)
 
-	// enforce creating the IDs
+	// enforce creating the ID
 	before.Id()
-	rene.Id()
+
+	// Replace the identity stub with the real thing
+	assert.Equal(t, rene.Id(), after.base().Author.Id())
+	after.Author = rene
 
 	assert.Equal(t, before, &after)
 }

bug/op_set_status_test.go 🔗

@@ -5,12 +5,20 @@ import (
 	"testing"
 	"time"
 
+	"github.com/stretchr/testify/require"
+
 	"github.com/MichaelMure/git-bug/identity"
+	"github.com/MichaelMure/git-bug/repository"
+
 	"github.com/stretchr/testify/assert"
 )
 
 func TestSetStatusSerialize(t *testing.T) {
-	var rene = identity.NewBare("René Descartes", "rene@descartes.fr")
+	repo := repository.NewMockRepoForTest()
+	rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
+	err := rene.Commit(repo)
+	require.NoError(t, err)
+
 	unix := time.Now().Unix()
 	before := NewSetStatusOp(rene, unix, ClosedStatus)
 
@@ -21,9 +29,12 @@ func TestSetStatusSerialize(t *testing.T) {
 	err = json.Unmarshal(data, &after)
 	assert.NoError(t, err)
 
-	// enforce creating the IDs
+	// enforce creating the ID
 	before.Id()
-	rene.Id()
+
+	// Replace the identity stub with the real thing
+	assert.Equal(t, rene.Id(), after.base().Author.Id())
+	after.Author = rene
 
 	assert.Equal(t, before, &after)
 }

bug/op_set_title_test.go 🔗

@@ -5,12 +5,20 @@ import (
 	"testing"
 	"time"
 
+	"github.com/stretchr/testify/require"
+
 	"github.com/MichaelMure/git-bug/identity"
+	"github.com/MichaelMure/git-bug/repository"
+
 	"github.com/stretchr/testify/assert"
 )
 
 func TestSetTitleSerialize(t *testing.T) {
-	var rene = identity.NewBare("René Descartes", "rene@descartes.fr")
+	repo := repository.NewMockRepoForTest()
+	rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
+	err := rene.Commit(repo)
+	require.NoError(t, err)
+
 	unix := time.Now().Unix()
 	before := NewSetTitleOp(rene, unix, "title", "was")
 
@@ -21,9 +29,12 @@ func TestSetTitleSerialize(t *testing.T) {
 	err = json.Unmarshal(data, &after)
 	assert.NoError(t, err)
 
-	// enforce creating the IDs
+	// enforce creating the ID
 	before.Id()
-	rene.Id()
+
+	// Replace the identity stub with the real thing
+	assert.Equal(t, rene.Id(), after.base().Author.Id())
+	after.Author = rene
 
 	assert.Equal(t, before, &after)
 }

bug/operation_pack.go 🔗

@@ -9,7 +9,9 @@ import (
 	"github.com/MichaelMure/git-bug/repository"
 )
 
-const formatVersion = 1
+// 1: original format
+// 2: no more legacy identities
+const formatVersion = 2
 
 // OperationPack represent an ordered set of operation to apply
 // to a Bug. These operations are stored in a single Git commit.
@@ -44,8 +46,11 @@ func (opp *OperationPack) UnmarshalJSON(data []byte) error {
 		return err
 	}
 
-	if aux.Version != formatVersion {
-		return fmt.Errorf("unknown format version %v", aux.Version)
+	if aux.Version < formatVersion {
+		return fmt.Errorf("outdated repository format, please use https://github.com/MichaelMure/git-bug-migration to upgrade")
+	}
+	if aux.Version > formatVersion {
+		return fmt.Errorf("your version of git-bug is too old for this repository (version %v), please upgrade to the latest version", aux.Version)
 	}
 
 	for _, raw := range aux.Operations {

bug/operation_pack_test.go 🔗

@@ -15,7 +15,11 @@ import (
 func TestOperationPackSerialize(t *testing.T) {
 	opp := &OperationPack{}
 
-	rene := identity.NewBare("René Descartes", "rene@descartes.fr")
+	repo := repository.NewMockRepoForTest()
+	rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
+	err := rene.Commit(repo)
+	require.NoError(t, err)
+
 	createOp := NewCreateOp(rene, time.Now().Unix(), "title", "message", nil)
 	setTitleOp := NewSetTitleOp(rene, time.Now().Unix(), "title2", "title1")
 	addCommentOp := NewAddCommentOp(rene, time.Now().Unix(), "message2", nil)
@@ -49,16 +53,27 @@ func TestOperationPackSerialize(t *testing.T) {
 	err = json.Unmarshal(data, &opp2)
 	assert.NoError(t, err)
 
-	ensureIDs(t, opp)
+	ensureIds(opp)
+	ensureAuthors(t, opp, opp2)
 
 	assert.Equal(t, opp, opp2)
 }
 
-func ensureIDs(t *testing.T, opp *OperationPack) {
+func ensureIds(opp *OperationPack) {
 	for _, op := range opp.Operations {
-		id := op.Id()
-		require.NoError(t, id.Validate())
-		id = op.GetAuthor().Id()
-		require.NoError(t, id.Validate())
+		op.Id()
+	}
+}
+
+func ensureAuthors(t *testing.T, opp1 *OperationPack, opp2 *OperationPack) {
+	require.Equal(t, len(opp1.Operations), len(opp2.Operations))
+	for i := 0; i < len(opp1.Operations); i++ {
+		op1 := opp1.Operations[i]
+		op2 := opp2.Operations[i]
+
+		// ensure we have equivalent authors (IdentityStub vs Identity) then
+		// enforce equality
+		require.Equal(t, op1.base().Author.Id(), op2.base().Author.Id())
+		op1.base().Author = op2.base().Author
 	}
 }

bug/operation_test.go 🔗

@@ -88,32 +88,32 @@ func TestID(t *testing.T) {
 	}
 
 	for _, repo := range repos {
-		rene := identity.NewBare("René Descartes", "rene@descartes.fr")
+		rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
+		err := rene.Commit(repo)
+		require.NoError(t, err)
 
 		b, op, err := Create(rene, time.Now().Unix(), "title", "message")
-		require.Nil(t, err)
+		require.NoError(t, err)
 
 		id1 := op.Id()
 		require.NoError(t, id1.Validate())
 
 		err = b.Commit(repo)
-		require.Nil(t, err)
+		require.NoError(t, err)
 
 		op2 := b.FirstOp()
 
 		id2 := op2.Id()
 		require.NoError(t, id2.Validate())
-
 		require.Equal(t, id1, id2)
 
 		b2, err := ReadLocal(repo, b.Id())
-		require.Nil(t, err)
+		require.NoError(t, err)
 
 		op3 := b2.FirstOp()
 
 		id3 := op3.Id()
 		require.NoError(t, id3.Validate())
-
 		require.Equal(t, id1, id3)
 	}
 }

cache/bug_excerpt.go 🔗

@@ -26,6 +26,7 @@ type BugExcerpt struct {
 	CreateUnixTime    int64
 	EditUnixTime      int64
 
+	AuthorId     entity.Id
 	Status       bug.Status
 	Labels       []bug.Label
 	Title        string
@@ -33,12 +34,6 @@ type BugExcerpt struct {
 	Actors       []entity.Id
 	Participants []entity.Id
 
-	// If author is identity.Bare, LegacyAuthor is set
-	// If author is identity.Identity, AuthorId is set and data is deported
-	// in a IdentityExcerpt
-	LegacyAuthor LegacyAuthorExcerpt
-	AuthorId     entity.Id
-
 	CreateMetadata map[string]string
 }
 
@@ -94,11 +89,6 @@ func NewBugExcerpt(b bug.Interface, snap *bug.Snapshot) *BugExcerpt {
 	switch snap.Author.(type) {
 	case *identity.Identity, *IdentityCache:
 		e.AuthorId = snap.Author.Id()
-	case *identity.Bare:
-		e.LegacyAuthor = LegacyAuthorExcerpt{
-			Login: snap.Author.Login(),
-			Name:  snap.Author.Name(),
-		}
 	default:
 		panic("unhandled identity type")
 	}

cache/filter.go 🔗

@@ -29,19 +29,12 @@ func AuthorFilter(query string) Filter {
 	return func(excerpt *BugExcerpt, resolver resolver) bool {
 		query = strings.ToLower(query)
 
-		// Normal identity
-		if excerpt.AuthorId != "" {
-			author, err := resolver.ResolveIdentityExcerpt(excerpt.AuthorId)
-			if err != nil {
-				panic(err)
-			}
-
-			return author.Match(query)
+		author, err := resolver.ResolveIdentityExcerpt(excerpt.AuthorId)
+		if err != nil {
+			panic(err)
 		}
 
-		// Legacy identity support
-		return strings.Contains(strings.ToLower(excerpt.LegacyAuthor.Name), query) ||
-			strings.Contains(strings.ToLower(excerpt.LegacyAuthor.Login), query)
+		return author.Match(query)
 	}
 }
 

cache/repo_cache.go 🔗

@@ -19,7 +19,8 @@ import (
 
 // 1: original format
 // 2: added cache for identities with a reference in the bug cache
-const formatVersion = 2
+// 3: no more legacy identity
+const formatVersion = 3
 
 // The maximum number of bugs loaded in memory. After that, eviction will be done.
 const defaultMaxLoadedBugs = 1000

commands/ls.go 🔗

@@ -151,15 +151,11 @@ func lsJsonFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
 			Metadata:   b.CreateMetadata,
 		}
 
-		if b.AuthorId != "" {
-			author, err := env.backend.ResolveIdentityExcerpt(b.AuthorId)
-			if err != nil {
-				return err
-			}
-			jsonBug.Author = NewJSONIdentityFromExcerpt(author)
-		} else {
-			jsonBug.Author = NewJSONIdentityFromLegacyExcerpt(&b.LegacyAuthor)
+		author, err := env.backend.ResolveIdentityExcerpt(b.AuthorId)
+		if err != nil {
+			return err
 		}
+		jsonBug.Author = NewJSONIdentityFromExcerpt(author)
 
 		jsonBug.Actors = make([]JSONIdentity, len(b.Actors))
 		for i, element := range b.Actors {
@@ -188,15 +184,9 @@ func lsJsonFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
 
 func lsDefaultFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
 	for _, b := range bugExcerpts {
-		var name string
-		if b.AuthorId != "" {
-			author, err := env.backend.ResolveIdentityExcerpt(b.AuthorId)
-			if err != nil {
-				return err
-			}
-			name = author.DisplayName()
-		} else {
-			name = b.LegacyAuthor.DisplayName()
+		author, err := env.backend.ResolveIdentityExcerpt(b.AuthorId)
+		if err != nil {
+			return err
 		}
 
 		var labelsTxt strings.Builder
@@ -210,7 +200,7 @@ func lsDefaultFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
 		// truncate + pad if needed
 		labelsFmt := text.TruncateMax(labelsTxt.String(), 10)
 		titleFmt := text.LeftPadMaxLine(strings.TrimSpace(b.Title), 50-text.Len(labelsFmt), 0)
-		authorFmt := text.LeftPadMaxLine(name, 15, 0)
+		authorFmt := text.LeftPadMaxLine(author.DisplayName(), 15, 0)
 
 		comments := fmt.Sprintf("%3d 💬", b.LenComments-1)
 		if b.LenComments-1 <= 0 {
@@ -261,15 +251,9 @@ func lsOrgmodeFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
 			title = b.Title
 		}
 
-		var name string
-		if b.AuthorId != "" {
-			author, err := env.backend.ResolveIdentityExcerpt(b.AuthorId)
-			if err != nil {
-				return err
-			}
-			name = author.DisplayName()
-		} else {
-			name = b.LegacyAuthor.DisplayName()
+		author, err := env.backend.ResolveIdentityExcerpt(b.AuthorId)
+		if err != nil {
+			return err
 		}
 
 		var labels strings.Builder
@@ -286,7 +270,7 @@ func lsOrgmodeFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
 			status,
 			b.Id.Human(),
 			formatTime(b.CreateTime()),
-			name,
+			author.DisplayName(),
 			title,
 			labels.String(),
 		)

identity/bare.go 🔗

@@ -1,218 +0,0 @@
-package identity
-
-import (
-	"crypto/sha256"
-	"encoding/json"
-	"fmt"
-	"strings"
-
-	"github.com/MichaelMure/git-bug/entity"
-	"github.com/MichaelMure/git-bug/repository"
-	"github.com/MichaelMure/git-bug/util/lamport"
-	"github.com/MichaelMure/git-bug/util/text"
-	"github.com/MichaelMure/git-bug/util/timestamp"
-)
-
-var _ Interface = &Bare{}
-var _ entity.Interface = &Bare{}
-
-// Bare is a very minimal identity, designed to be fully embedded directly along
-// other data.
-//
-// in particular, this identity is designed to be compatible with the handling of
-// identities in the early version of git-bug.
-// Deprecated: legacy identity for compat, might make sense to ditch entirely for
-// simplicity but that would be a breaking change.
-type Bare struct {
-	id        entity.Id
-	name      string
-	email     string
-	login     string
-	avatarUrl string
-}
-
-func NewBare(name string, email string) *Bare {
-	return &Bare{id: entity.UnsetId, name: name, email: email}
-}
-
-func NewBareFull(name string, email string, login string, avatarUrl string) *Bare {
-	return &Bare{id: entity.UnsetId, name: name, email: email, login: login, avatarUrl: avatarUrl}
-}
-
-func deriveId(data []byte) entity.Id {
-	sum := sha256.Sum256(data)
-	return entity.Id(fmt.Sprintf("%x", sum))
-}
-
-type bareIdentityJSON struct {
-	Name      string `json:"name,omitempty"`
-	Email     string `json:"email,omitempty"`
-	Login     string `json:"login,omitempty"`
-	AvatarUrl string `json:"avatar_url,omitempty"`
-}
-
-func (i *Bare) MarshalJSON() ([]byte, error) {
-	return json.Marshal(bareIdentityJSON{
-		Name:      i.name,
-		Email:     i.email,
-		Login:     i.login,
-		AvatarUrl: i.avatarUrl,
-	})
-}
-
-func (i *Bare) UnmarshalJSON(data []byte) error {
-	// Compute the Id when loading the op from disk.
-	i.id = deriveId(data)
-
-	aux := bareIdentityJSON{}
-
-	if err := json.Unmarshal(data, &aux); err != nil {
-		return err
-	}
-
-	i.name = aux.Name
-	i.email = aux.Email
-	i.login = aux.Login
-	i.avatarUrl = aux.AvatarUrl
-
-	return nil
-}
-
-// Id return the Identity identifier
-func (i *Bare) Id() entity.Id {
-	// We don't have a proper Id at hand, so let's hash all the data to get one.
-
-	if i.id == "" {
-		// something went really wrong
-		panic("identity's id not set")
-	}
-	if i.id == entity.UnsetId {
-		// This means we are trying to get the identity identifier *before* it has been stored
-		// As the Id is computed based on the actual bytes written on the disk, we are going to predict
-		// those and then get the Id. This is safe as it will be the exact same code writing on disk later.
-
-		data, err := json.Marshal(i)
-		if err != nil {
-			panic(err)
-		}
-
-		i.id = deriveId(data)
-	}
-	return i.id
-}
-
-// Name return the last version of the name
-func (i *Bare) Name() string {
-	return i.name
-}
-
-// Email return the last version of the email
-func (i *Bare) Email() string {
-	return i.email
-}
-
-// Login return the last version of the login
-func (i *Bare) Login() string {
-	return i.login
-}
-
-// AvatarUrl return the last version of the Avatar URL
-func (i *Bare) AvatarUrl() string {
-	return i.avatarUrl
-}
-
-// Keys return the last version of the valid keys
-func (i *Bare) Keys() []*Key {
-	return nil
-}
-
-// ValidKeysAtTime return the set of keys valid at a given lamport time
-func (i *Bare) ValidKeysAtTime(_ lamport.Time) []*Key {
-	return nil
-}
-
-// DisplayName return a non-empty string to display, representing the
-// identity, based on the non-empty values.
-func (i *Bare) DisplayName() string {
-	switch {
-	case i.name == "" && i.login != "":
-		return i.login
-	case i.name != "" && i.login == "":
-		return i.name
-	case i.name != "" && i.login != "":
-		return fmt.Sprintf("%s (%s)", i.name, i.login)
-	}
-
-	panic("invalid person data")
-}
-
-// Validate check if the Identity data is valid
-func (i *Bare) Validate() error {
-	if text.Empty(i.name) && text.Empty(i.login) {
-		return fmt.Errorf("either name or login should be set")
-	}
-
-	if strings.Contains(i.name, "\n") {
-		return fmt.Errorf("name should be a single line")
-	}
-
-	if !text.Safe(i.name) {
-		return fmt.Errorf("name is not fully printable")
-	}
-
-	if strings.Contains(i.login, "\n") {
-		return fmt.Errorf("login should be a single line")
-	}
-
-	if !text.Safe(i.login) {
-		return fmt.Errorf("login is not fully printable")
-	}
-
-	if strings.Contains(i.email, "\n") {
-		return fmt.Errorf("email should be a single line")
-	}
-
-	if !text.Safe(i.email) {
-		return fmt.Errorf("email is not fully printable")
-	}
-
-	if i.avatarUrl != "" && !text.ValidUrl(i.avatarUrl) {
-		return fmt.Errorf("avatarUrl is not a valid URL")
-	}
-
-	return nil
-}
-
-// Write the identity into the Repository. In particular, this ensure that
-// the Id is properly set.
-func (i *Bare) CommitWithRepo(repo repository.ClockedRepo) error {
-	// Nothing to do, everything is directly embedded
-	return nil
-}
-
-// If needed, write the identity into the Repository. In particular, this
-// ensure that the Id is properly set.
-func (i *Bare) CommitAsNeededWithRepo(repo repository.ClockedRepo) error {
-	// Nothing to do, everything is directly embedded
-	return nil
-}
-
-// IsProtected return true if the chain of git commits started to be signed.
-// If that's the case, only signed commit with a valid key for this identity can be added.
-func (i *Bare) IsProtected() bool {
-	return false
-}
-
-// LastModificationLamportTime return the Lamport time at which the last version of the identity became valid.
-func (i *Bare) LastModificationLamport() lamport.Time {
-	return 0
-}
-
-// LastModification return the timestamp at which the last version of the identity became valid.
-func (i *Bare) LastModification() timestamp.Timestamp {
-	return 0
-}
-
-func (i *Bare) NeedCommit() bool {
-	return false
-}

identity/bare_test.go 🔗

@@ -1,37 +0,0 @@
-package identity
-
-import (
-	"encoding/json"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-
-	"github.com/MichaelMure/git-bug/entity"
-)
-
-func TestBare_Id(t *testing.T) {
-	i := NewBare("name", "email")
-	id := i.Id()
-	expected := entity.Id("e18b853fbd89d5d40ca24811539c9a800c705abd9232f396954e8ca8bb63fa8a")
-	assert.Equal(t, expected, id)
-}
-
-func TestBareSerialize(t *testing.T) {
-	before := &Bare{
-		login:     "login",
-		email:     "email",
-		name:      "name",
-		avatarUrl: "avatar",
-	}
-
-	data, err := json.Marshal(before)
-	assert.NoError(t, err)
-
-	var after Bare
-	err = json.Unmarshal(data, &after)
-	assert.NoError(t, err)
-
-	before.id = after.id
-
-	assert.Equal(t, before, &after)
-}

identity/common.go 🔗

@@ -33,18 +33,5 @@ func UnmarshalJSON(raw json.RawMessage) (Interface, error) {
 		return nil, err
 	}
 
-	// Fallback on a legacy Bare identity
-	b := &Bare{}
-
-	err = json.Unmarshal(raw, b)
-	if err == nil && (b.name != "" || b.login != "") {
-		return b, nil
-	}
-
-	// abort if we have an error other than the wrong type
-	if _, ok := err.(*json.UnmarshalTypeError); err != nil && !ok {
-		return nil, err
-	}
-
 	return nil, fmt.Errorf("unknown identity type")
 }

identity/identity.go 🔗

@@ -441,7 +441,7 @@ func (i *Identity) lastVersion() *Version {
 
 // Id return the Identity identifier
 func (i *Identity) Id() entity.Id {
-	if i.id == "" {
+	if i.id == "" || i.id == entity.UnsetId {
 		// simply panic as it would be a coding error
 		// (using an id of an identity not stored yet)
 		panic("no id yet")

identity/version.go 🔗

@@ -13,6 +13,7 @@ import (
 	"github.com/MichaelMure/git-bug/util/text"
 )
 
+// 1: original format
 const formatVersion = 1
 
 // Version is a complete set of information about an Identity at a point in time.

termui/bug_table.go 🔗

@@ -5,7 +5,7 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/MichaelMure/go-term-text"
+	text "github.com/MichaelMure/go-term-text"
 	"github.com/awesome-gocui/gocui"
 	"github.com/dustin/go-humanize"
 
@@ -314,33 +314,25 @@ func (bt *bugTable) render(v *gocui.View, maxX int) {
 			labelsTxt.WriteString(lc256.Unescape())
 		}
 
-		var authorDisplayName string
-		if excerpt.AuthorId != "" {
-			author, err := bt.repo.ResolveIdentityExcerpt(excerpt.AuthorId)
-			if err != nil {
-				panic(err)
-			}
-			authorDisplayName = author.DisplayName()
-		} else {
-			authorDisplayName = excerpt.LegacyAuthor.DisplayName()
+		author, err := bt.repo.ResolveIdentityExcerpt(excerpt.AuthorId)
+		if err != nil {
+			panic(err)
 		}
 
-		lastEditTime := excerpt.EditTime()
-
 		id := text.LeftPadMaxLine(excerpt.Id.Human(), columnWidths["id"], 0)
 		status := text.LeftPadMaxLine(excerpt.Status.String(), columnWidths["status"], 0)
 		labels := text.TruncateMax(labelsTxt.String(), minInt(columnWidths["title"]-2, 10))
 		title := text.LeftPadMaxLine(strings.TrimSpace(excerpt.Title), columnWidths["title"]-text.Len(labels), 0)
-		author := text.LeftPadMaxLine(authorDisplayName, columnWidths["author"], 0)
+		authorTxt := text.LeftPadMaxLine(author.DisplayName(), columnWidths["author"], 0)
 		comments := text.LeftPadMaxLine(summaryTxt, columnWidths["comments"], 0)
-		lastEdit := text.LeftPadMaxLine(humanize.Time(lastEditTime), columnWidths["lastEdit"], 1)
+		lastEdit := text.LeftPadMaxLine(humanize.Time(excerpt.EditTime()), columnWidths["lastEdit"], 1)
 
 		_, _ = fmt.Fprintf(v, "%s %s %s%s %s %s %s\n",
 			colors.Cyan(id),
 			colors.Yellow(status),
 			title,
 			labels,
-			colors.Magenta(author),
+			colors.Magenta(authorTxt),
 			comments,
 			lastEdit,
 		)