1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-04-25 12:24:47 +02:00

Add option to delete local and remote tag

This commit is contained in:
Anvar Umuraliev 2025-01-27 17:43:48 +01:00 committed by Jesse Duffield
parent abf914c923
commit 7db8fb8e9c
5 changed files with 145 additions and 0 deletions

View File

@ -177,6 +177,59 @@ func (self *TagsController) remoteDelete(tag *models.Tag) error {
return nil return nil
} }
func (self *TagsController) localAndRemoteDelete(tag *models.Tag) error {
title := utils.ResolvePlaceholderString(
self.c.Tr.SelectRemoteTagUpstream,
map[string]string{
"tagName": tag.Name,
},
)
self.c.Prompt(types.PromptOpts{
Title: title,
InitialContent: "origin",
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRemoteSuggestionsFunc(),
HandleConfirm: func(upstream string) error {
confirmTitle := utils.ResolvePlaceholderString(
self.c.Tr.DeleteTagTitle,
map[string]string{
"tagName": tag.Name,
},
)
confirmPrompt := utils.ResolvePlaceholderString(
self.c.Tr.DeleteLocalAndRemoteTagPrompt,
map[string]string{
"tagName": tag.Name,
"upstream": upstream,
},
)
self.c.Confirm(types.ConfirmOpts{
Title: confirmTitle,
Prompt: confirmPrompt,
HandleConfirm: func() error {
return self.c.WithInlineStatus(tag, types.ItemOperationDeleting, context.TAGS_CONTEXT_KEY, func(task gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.DeleteRemoteTag)
if err := self.c.Git().Remote.DeleteRemoteTag(task, upstream, tag.Name); err != nil {
return err
}
self.c.LogAction(self.c.Tr.Actions.DeleteLocalTag)
if err := self.c.Git().Tag.LocalDelete(tag.Name); err != nil {
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}})
})
},
})
return nil
},
})
return nil
}
func (self *TagsController) delete(tag *models.Tag) error { func (self *TagsController) delete(tag *models.Tag) error {
menuTitle := utils.ResolvePlaceholderString( menuTitle := utils.ResolvePlaceholderString(
self.c.Tr.DeleteTagTitle, self.c.Tr.DeleteTagTitle,
@ -201,6 +254,14 @@ func (self *TagsController) delete(tag *models.Tag) error {
return self.remoteDelete(tag) return self.remoteDelete(tag)
}, },
}, },
{
Label: self.c.Tr.DeleteLocalAndRemoteTag,
Key: 'b',
OpensMenu: true,
OnPress: func() error {
return self.localAndRemoteDelete(tag)
},
},
} }
return self.c.Menu(types.CreateMenuOptions{ return self.c.Menu(types.CreateMenuOptions{

View File

@ -518,8 +518,10 @@ type TranslationSet struct {
DeleteTagTitle string DeleteTagTitle string
DeleteLocalTag string DeleteLocalTag string
DeleteRemoteTag string DeleteRemoteTag string
DeleteLocalAndRemoteTag string
SelectRemoteTagUpstream string SelectRemoteTagUpstream string
DeleteRemoteTagPrompt string DeleteRemoteTagPrompt string
DeleteLocalAndRemoteTagPrompt string
RemoteTagDeletedMessage string RemoteTagDeletedMessage string
PushTagTitle string PushTagTitle string
PushTag string PushTag string
@ -1539,9 +1541,11 @@ func EnglishTranslationSet() *TranslationSet {
DeleteTagTitle: "Delete tag '{{.tagName}}'?", DeleteTagTitle: "Delete tag '{{.tagName}}'?",
DeleteLocalTag: "Delete local tag", DeleteLocalTag: "Delete local tag",
DeleteRemoteTag: "Delete remote tag", DeleteRemoteTag: "Delete remote tag",
DeleteLocalAndRemoteTag: "Delete local and remote tag",
RemoteTagDeletedMessage: "Remote tag deleted", RemoteTagDeletedMessage: "Remote tag deleted",
SelectRemoteTagUpstream: "Remote from which to remove tag '{{.tagName}}':", SelectRemoteTagUpstream: "Remote from which to remove tag '{{.tagName}}':",
DeleteRemoteTagPrompt: "Are you sure you want to delete the remote tag '{{.tagName}}' from '{{.upstream}}'?", DeleteRemoteTagPrompt: "Are you sure you want to delete the remote tag '{{.tagName}}' from '{{.upstream}}'?",
DeleteLocalAndRemoteTagPrompt: "Are you sure you want to delete '{{.tagName}}' from both your machine and from '{{.upstream}}'?",
PushTagTitle: "Remote to push tag '{{.tagName}}' to:", PushTagTitle: "Remote to push tag '{{.tagName}}' to:",
// Using 'push tag' rather than just 'push' to disambiguate from a global push // Using 'push tag' rather than just 'push' to disambiguate from a global push
PushTag: "Push tag", PushTag: "Push tag",

View File

@ -190,6 +190,10 @@ func (self *Shell) Revert(ref string) *Shell {
return self.RunCommand([]string{"git", "revert", ref}) return self.RunCommand([]string{"git", "revert", ref})
} }
func (self *Shell) AssertRemoteTagNotFound(upstream, name string) *Shell {
return self.RunCommandExpectError([]string{"git", "ls-remote", "--exit-code", upstream, fmt.Sprintf("refs/tags/%s", name)})
}
func (self *Shell) CreateLightweightTag(name string, ref string) *Shell { func (self *Shell) CreateLightweightTag(name string, ref string) *Shell {
return self.RunCommand([]string{"git", "tag", name, ref}) return self.RunCommand([]string{"git", "tag", name, ref})
} }

View File

@ -0,0 +1,75 @@
package tag
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var DeleteLocalAndRemote = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Create and delete both local and remote annotated tag",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.EmptyCommit("initial commit")
shell.CloneIntoRemote("origin")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Tags().
Focus().
IsEmpty().
Press(keys.Universal.New).
Tap(func() {
t.ExpectPopup().CommitMessagePanel().
Title(Equals("Tag name")).
Type("new-tag").
SwitchToDescription().
Title(Equals("Tag description")).
Type("message").
SwitchToSummary().
Confirm()
}).
Lines(
MatchesRegexp(`new-tag.*message`).IsSelected(),
).
Press(keys.Universal.Push).
Tap(func() {
t.ExpectPopup().Prompt().
Title(Equals("Remote to push tag 'new-tag' to:")).
InitialText(Equals("origin")).
SuggestionLines(
Contains("origin"),
).
Confirm()
}).
Press(keys.Universal.Remove).
Tap(func() {
t.ExpectPopup().
Menu().
Title(Equals("Delete tag 'new-tag'?")).
Select(Contains("Delete local and remote tag")).
Confirm()
}).
Tap(func() {
t.ExpectPopup().Prompt().
Title(Equals("Remote from which to remove tag 'new-tag':")).
InitialText(Equals("origin")).
SuggestionLines(
Contains("origin"),
).
Confirm()
}).
Tap(func() {
t.ExpectPopup().
Confirmation().
Title(Equals("Delete tag 'new-tag'?")).
Content(Equals("Are you sure you want to delete 'new-tag' from both your machine and from 'origin'?")).
Confirm()
}).
IsEmpty().
Press(keys.Universal.New).
Tap(func() {
t.Shell().AssertRemoteTagNotFound("origin", "new-tag")
})
},
})

View File

@ -356,6 +356,7 @@ var tests = []*components.IntegrationTest{
tag.CreateWhileCommitting, tag.CreateWhileCommitting,
tag.CrudAnnotated, tag.CrudAnnotated,
tag.CrudLightweight, tag.CrudLightweight,
tag.DeleteLocalAndRemote,
tag.ForceTagAnnotated, tag.ForceTagAnnotated,
tag.ForceTagLightweight, tag.ForceTagLightweight,
tag.Reset, tag.Reset,