Merge pull request #433 from MichaelMure/remove-bug-2

Add the 'rm' command
This commit is contained in:
Michael Muré 2020-07-28 14:41:35 +02:00 committed by GitHub
commit 51c887ff9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 233 additions and 18 deletions

View File

@ -109,8 +109,8 @@ func ReadLocalBug(repo repository.ClockedRepo, id entity.Id) (*Bug, error) {
}
// ReadRemoteBug will read a remote bug from its hash
func ReadRemoteBug(repo repository.ClockedRepo, remote string, id string) (*Bug, error) {
ref := fmt.Sprintf(bugsRemoteRefPattern, remote) + id
func ReadRemoteBug(repo repository.ClockedRepo, remote string, id entity.Id) (*Bug, error) {
ref := fmt.Sprintf(bugsRemoteRefPattern, remote) + id.String()
return readBug(repo, ref)
}
@ -242,9 +242,54 @@ func readBug(repo repository.ClockedRepo, ref string) (*Bug, error) {
return &bug, nil
}
func RemoveLocalBug(repo repository.ClockedRepo, id entity.Id) error {
ref := bugsRefPattern + id.String()
return repo.RemoveRef(ref)
// RemoveBug will remove a local bug from its entity.Id
func RemoveBug(repo repository.ClockedRepo, id entity.Id) error {
var fullMatches []string
refs, err := repo.ListRefs(bugsRefPattern + id.String())
if err != nil {
return err
}
if len(refs) > 1 {
return NewErrMultipleMatchBug(refsToIds(refs))
}
if len(refs) == 1 {
// we have the bug locally
fullMatches = append(fullMatches, refs[0])
}
remotes, err := repo.GetRemotes()
if err != nil {
return err
}
for remote := range remotes {
remotePrefix := fmt.Sprintf(bugsRemoteRefPattern+id.String(), remote)
remoteRefs, err := repo.ListRefs(remotePrefix)
if err != nil {
return err
}
if len(remoteRefs) > 1 {
return NewErrMultipleMatchBug(refsToIds(refs))
}
if len(remoteRefs) == 1 {
// found the bug in a remote
fullMatches = append(fullMatches, remoteRefs[0])
}
}
if len(fullMatches) == 0 {
return ErrBugNotExist
}
for _, ref := range fullMatches {
err = repo.RemoveRef(ref)
if err != nil {
return err
}
}
return nil
}
type StreamedBug struct {
@ -305,13 +350,17 @@ func refsToIds(refs []string) []entity.Id {
ids := make([]entity.Id, len(refs))
for i, ref := range refs {
split := strings.Split(ref, "/")
ids[i] = entity.Id(split[len(split)-1])
ids[i] = refToId(ref)
}
return ids
}
func refToId(ref string) entity.Id {
split := strings.Split(ref, "/")
return entity.Id(split[len(split)-1])
}
// Validate check if the Bug data is valid
func (bug *Bug) Validate() error {
// non-empty

View File

@ -1,10 +1,12 @@
package bug
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/MichaelMure/git-bug/identity"
"github.com/MichaelMure/git-bug/repository"
@ -64,7 +66,7 @@ func TestBugValidity(t *testing.T) {
}
}
func TestBugCommitLoadRemove(t *testing.T) {
func TestBugCommitLoad(t *testing.T) {
bug1 := NewBug()
rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
@ -100,16 +102,6 @@ func TestBugCommitLoadRemove(t *testing.T) {
bug3, err := ReadLocalBug(repo, bug1.Id())
assert.NoError(t, err)
equivalentBug(t, bug1, bug3)
err = RemoveLocalBug(repo, bug1.Id())
assert.NoError(t, err)
streamedBugs := ReadAllLocalBugs(repo)
count := 0
for range streamedBugs {
count++
}
assert.Equal(t, 0, count)
}
func equivalentBug(t *testing.T, expected, actual *Bug) {
@ -123,3 +115,64 @@ func equivalentBug(t *testing.T, expected, actual *Bug) {
assert.Equal(t, expected, actual)
}
func TestBugRemove(t *testing.T) {
repo := repository.CreateTestRepo(false)
remoteA := repository.CreateTestRepo(true)
remoteB := repository.CreateTestRepo(true)
defer repository.CleanupTestRepos(repo, remoteA, remoteB)
err := repo.AddRemote("remoteA", "file://"+remoteA.GetPath())
require.NoError(t, err)
err = repo.AddRemote("remoteB", "file://"+remoteB.GetPath())
require.NoError(t, err)
// generate a bunch of bugs
rene := identity.NewIdentity("René Descartes", "rene@descartes.fr")
err = rene.Commit(repo)
require.NoError(t, err)
for i := 0; i < 100; i++ {
b := NewBug()
createOp := NewCreateOp(rene, time.Now().Unix(), "title", fmt.Sprintf("message%v", i), nil)
b.Append(createOp)
err = b.Commit(repo)
require.NoError(t, err)
}
// and one more for testing
b := NewBug()
createOp := NewCreateOp(rene, time.Now().Unix(), "title", "message", nil)
b.Append(createOp)
err = b.Commit(repo)
require.NoError(t, err)
_, err = Push(repo, "remoteA")
require.NoError(t, err)
_, err = Push(repo, "remoteB")
require.NoError(t, err)
_, err = Fetch(repo, "remoteA")
require.NoError(t, err)
_, err = Fetch(repo, "remoteB")
require.NoError(t, err)
err = RemoveBug(repo, b.Id())
require.NoError(t, err)
_, err = ReadLocalBug(repo, b.Id())
require.Error(t, ErrBugNotExist, err)
_, err = ReadRemoteBug(repo, "remoteA", b.Id())
require.Error(t, ErrBugNotExist, err)
_, err = ReadRemoteBug(repo, "remoteB", b.Id())
require.Error(t, ErrBugNotExist, err)
ids, err := ListLocalIds(repo)
require.NoError(t, err)
require.Len(t, ids, 100)
}

View File

@ -359,3 +359,19 @@ func (c *RepoCache) NewBugRaw(author *IdentityCache, unixTime int64, title strin
return cached, op, nil
}
// RemoveBug removes a bug from the cache and repo given a bug id prefix
func (c *RepoCache) RemoveBug(prefix string) error {
b, err := c.ResolveBugPrefix(prefix)
if err != nil {
return err
}
err = bug.RemoveBug(c.repo, b.Id())
delete(c.bugs, b.Id())
delete(c.bugExcerpts, b.Id())
return c.writeBugCache()
}

View File

@ -1,10 +1,14 @@
package cache
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/MichaelMure/git-bug/bug"
"github.com/MichaelMure/git-bug/query"
"github.com/MichaelMure/git-bug/repository"
)
@ -157,3 +161,52 @@ func TestPushPull(t *testing.T) {
require.Len(t, cacheA.AllBugsIds(), 2)
}
func TestRemove(t *testing.T) {
repo := repository.CreateTestRepo(false)
remoteA := repository.CreateTestRepo(true)
remoteB := repository.CreateTestRepo(true)
defer repository.CleanupTestRepos(repo, remoteA, remoteB)
err := repo.AddRemote("remoteA", "file://"+remoteA.GetPath())
require.NoError(t, err)
err = repo.AddRemote("remoteB", "file://"+remoteB.GetPath())
require.NoError(t, err)
repoCache, err := NewRepoCache(repo)
require.NoError(t, err)
// generate a bunch of bugs
rene, err := repoCache.NewIdentity("René Descartes", "rene@descartes.fr")
require.NoError(t, err)
for i := 0; i < 100; i++ {
_, _, err := repoCache.NewBugRaw(rene, time.Now().Unix(), "title", fmt.Sprintf("message%v", i), nil, nil)
require.NoError(t, err)
}
// and one more for testing
b1, _, err := repoCache.NewBugRaw(rene, time.Now().Unix(), "title", "message", nil, nil)
require.NoError(t, err)
_, err = repoCache.Push("remoteA")
require.NoError(t, err)
_, err = repoCache.Push("remoteB")
require.NoError(t, err)
_, err = repoCache.Fetch("remoteA")
require.NoError(t, err)
_, err = repoCache.Fetch("remoteB")
require.NoError(t, err)
err = repoCache.RemoveBug(b1.Id().String())
require.NoError(t, err)
assert.Equal(t, 100, len(repoCache.bugs))
assert.Equal(t, 100, len(repoCache.bugExcerpts))
_, err = repoCache.ResolveBug(b1.Id())
assert.Error(t, bug.ErrBugNotExist, err)
}

43
commands/rm.go Normal file
View File

@ -0,0 +1,43 @@
package commands
import (
"errors"
"github.com/spf13/cobra"
)
func newRmCommand() *cobra.Command {
env := newEnv()
cmd := &cobra.Command{
Use: "rm <id>",
Short: "Remove an existing bug.",
Long: "Remove an existing bug in the local repository. Note removing bugs that were imported from bridges will not remove the bug on the remote, and will only remove the local copy of the bug.",
PreRunE: loadBackendEnsureUser(env),
PostRunE: closeBackend(env),
RunE: func(cmd *cobra.Command, args []string) error {
return runRm(env, args)
},
}
flags := cmd.Flags()
flags.SortFlags = false
return cmd
}
func runRm(env *Env, args []string) (err error) {
if len(args) == 0 {
return errors.New("you must provide a bug prefix to remove")
}
err = env.backend.RemoveBug(args[0])
if err != nil {
return
}
env.out.Printf("bug %s removed\n", args[0])
return
}

View File

@ -71,6 +71,7 @@ _git_bug() {
cmd.AddCommand(newLsLabelCommand())
cmd.AddCommand(newPullCommand())
cmd.AddCommand(newPushCommand())
cmd.AddCommand(newRmCommand())
cmd.AddCommand(newSelectCommand())
cmd.AddCommand(newShowCommand())
cmd.AddCommand(newStatusCommand())