diff --git a/docs/Config.md b/docs/Config.md index 03706e95bbc..0ba31884d6a 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -332,6 +332,11 @@ git: # The commit message to use for a squash merge commit. Can contain "{{selectedRef}}" and "{{currentBranch}}" placeholders. squashMergeMessage: Squash merge {{selectedRef}} into {{currentBranch}} + # Config relating to tagging + tag: + # If true, always create annotated tags (even if the tag message is empty) + alwaysAnnotate: false + # list of branches that are considered 'main' branches, used when displaying commits mainBranches: - master diff --git a/pkg/config/app_config_test.go b/pkg/config/app_config_test.go index c8c7d1d11d7..d16cccc1c25 100644 --- a/pkg/config/app_config_test.go +++ b/pkg/config/app_config_test.go @@ -640,6 +640,11 @@ git: # The commit message to use for a squash merge commit. Can contain "{{selectedRef}}" and "{{currentBranch}}" placeholders. squashMergeMessage: Squash merge {{selectedRef}} into {{currentBranch}} + # Config relating to tagging + tag: + # If true, always create annotated tags (even if the tag message is empty) + alwaysAnnotate: false + # list of branches that are considered 'main' branches, used when displaying commits mainBranches: - master diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 5465a376c11..a98b2256170 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -242,6 +242,8 @@ type GitConfig struct { Commit CommitConfig `yaml:"commit"` // Config relating to merging Merging MergingConfig `yaml:"merging"` + // Config relating to tagging + Tag TagConfig `yaml:"tag"` // list of branches that are considered 'main' branches, used when displaying commits MainBranches []string `yaml:"mainBranches" jsonschema:"uniqueItems=true"` // Prefix to use when skipping hooks. E.g. if set to 'WIP', then pre-commit hooks will be skipped when the commit message starts with 'WIP' @@ -341,6 +343,11 @@ type MergingConfig struct { SquashMergeMessage string `yaml:"squashMergeMessage"` } +type TagConfig struct { + // If true, always create annotated tags (even if the tag message is empty) + AlwaysAnnotate bool `yaml:"alwaysAnnotate"` +} + type LogConfig struct { // One of: 'date-order' | 'author-date-order' | 'topo-order' | 'default' // 'topo-order' makes it easier to read the git log graph, but commits may not @@ -809,6 +816,9 @@ func GetDefaultConfig() *UserConfig { Args: "", SquashMergeMessage: "Squash merge {{selectedRef}} into {{currentBranch}}", }, + Tag: TagConfig{ + AlwaysAnnotate: false, + }, Log: LogConfig{ Order: "topo-order", ShowGraph: "always", diff --git a/pkg/gui/controllers/helpers/tags_helper.go b/pkg/gui/controllers/helpers/tags_helper.go index 6a7e4721948..5671108db5b 100644 --- a/pkg/gui/controllers/helpers/tags_helper.go +++ b/pkg/gui/controllers/helpers/tags_helper.go @@ -38,7 +38,7 @@ func (self *TagsHelper) OpenCreateTagPrompt(ref string, onCreate func()) error { Prompt: prompt, HandleConfirm: func() error { var command *oscommands.CmdObj - if description != "" || self.c.Git().Config.GetGpgTagSign() { + if description != "" || self.c.Git().Config.GetGpgTagSign() || self.c.UserConfig().Git.Tag.AlwaysAnnotate { self.c.LogAction(self.c.Tr.Actions.CreateAnnotatedTag) command = self.c.Git().Tag.CreateAnnotatedObj(tagName, ref, description, force) } else { diff --git a/pkg/integration/components/git.go b/pkg/integration/components/git.go index 1b07e5cf802..248967c3f6a 100644 --- a/pkg/integration/components/git.go +++ b/pkg/integration/components/git.go @@ -21,6 +21,17 @@ func (self *Git) TagNamesAt(ref string, expectedNames []string) *Git { return self.assert([]string{"git", "tag", "--sort=v:refname", "--points-at", ref}, strings.Join(expectedNames, "\n")) } +func (self *Git) TagIsAnnotated(tagName string) *Git { + cmdArgs := []string{"git", "cat-file", "-t", tagName} + expectedOutput := "tag" + + return self.expect(cmdArgs, func(output string) (bool, string) { + isAnnotated := output == expectedOutput + failureMessage := fmt.Sprintf("Expected tag '%s' to be an annotated tag (output 'tag'), but got '%s'", tagName, output) + return isAnnotated, failureMessage + }) +} + func (self *Git) RemoteTagDeleted(ref string, tagName string) *Git { return self.expect([]string{"git", "ls-remote", ref, fmt.Sprintf("refs/tags/%s", tagName)}, func(s string) (bool, string) { return len(s) == 0, fmt.Sprintf("Expected tag %s to have been removed from %s", tagName, ref) diff --git a/pkg/integration/tests/tag/create_annotated_with_config.go b/pkg/integration/tests/tag/create_annotated_with_config.go new file mode 100644 index 00000000000..5a17134783c --- /dev/null +++ b/pkg/integration/tests/tag/create_annotated_with_config.go @@ -0,0 +1,37 @@ +package tag + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var CreateAnnotatedWithConfig = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Create an annotated tag when the alwaysAnnotate config option is enabled", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + config.GetUserConfig().Git.Tag.AlwaysAnnotate = true + }, + SetupRepo: func(shell *Shell) { + shell.EmptyCommit("initial commit") + }, + 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"). + Confirm() + }). + Lines( + MatchesRegexp(`new-tag.*`).IsSelected(), + ). + PressEnter(). + Tap(func() { + t.Git().TagIsAnnotated("new-tag") + }) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index d5f4f5c21af..c56bea5634f 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -405,6 +405,7 @@ var tests = []*components.IntegrationTest{ tag.Checkout, tag.CheckoutWhenBranchWithSameNameExists, tag.CopyToClipboard, + tag.CreateAnnotatedWithConfig, tag.CreateWhileCommitting, tag.CrudAnnotated, tag.CrudLightweight, diff --git a/schema/config.json b/schema/config.json index 9f73e8974c6..9f60aa6e23f 100644 --- a/schema/config.json +++ b/schema/config.json @@ -297,6 +297,10 @@ "$ref": "#/$defs/MergingConfig", "description": "Config relating to merging" }, + "tag": { + "$ref": "#/$defs/TagConfig", + "description": "Config relating to tagging" + }, "mainBranches": { "items": { "type": "string" @@ -1727,6 +1731,18 @@ "type": "object", "description": "Config relating to the spinner." }, + "TagConfig": { + "properties": { + "alwaysAnnotate": { + "type": "boolean", + "description": "If true, always create annotated tags (even if the tag message is empty)", + "default": false + } + }, + "additionalProperties": false, + "type": "object", + "description": "Config relating to tagging" + }, "ThemeConfig": { "properties": { "activeBorderColor": {