Skip to content

Commit

Permalink
feat: Support multiple commit prefixes
Browse files Browse the repository at this point in the history
This implementation, unlike that proposed in jesseduffield#4253
keeps the yaml schema easy, and does a migration from the single
elements to a sequence of elements.
  • Loading branch information
ChrisMcD1 committed Feb 13, 2025
1 parent 3915cb6 commit a741cfd
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 91 deletions.
27 changes: 14 additions & 13 deletions docs/Config.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,14 +341,6 @@ git:
# If true, do not allow force pushes
disableForcePushing: false

# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-commit-message-prefix
commitPrefix:
# pattern to match on. E.g. for 'feature/AB-123' to match on the AB-123 use "^\\w+\\/(\\w+-\\w+).*"
pattern: ""

# Replace directive. E.g. for 'feature/AB-123' to start the commit message with 'AB-123 ' use "[$1] "
replace: ""

# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-branch-name-prefix
branchPrefix: ""

Expand Down Expand Up @@ -931,20 +923,29 @@ Example:
```yaml
git:
commitPrefix:
pattern: "^\\w+\\/(\\w+-\\w+).*"
replace: '[$1] '
- pattern: "^\\w+\\/(\\w+-\\w+).*"
replace: '[$1] '
```

If you want repository-specific prefixes, you can map them with `commitPrefixes`. If you have both `commitPrefixes` defined and an entry in `commitPrefixes` for the current repo, the `commitPrefixes` entry is given higher precedence. Repository folder names must be an exact match.
If you want repository-specific prefixes, you can map them with `commitPrefixes`. If you have both entries in `commitPrefix` defined and an repository match in `commitPrefixes` for the current repo, the `commitPrefixes` entry is given higher precedence. Repository folder names must be an exact match.

```yaml
git:
commitPrefixes:
my_project: # This is repository folder name
pattern: "^\\w+\\/(\\w+-\\w+).*"
replace: '[$1] '
- pattern: "^\\w+\\/(\\w+-\\w+).*"
replace: '[$1] '
commitPrefix:
- pattern: "^(\\w+)-.*" # A more general match for any leading word
replace : '[$1] '
- pattern: ".*" # The final fallthrough regex that copies over the whole branch name
replace : '[$0] '
```

> Outside of `my_project`, only the `commitPrefix` entry will be attempted.
Inside of `my_project`, the repository specific pattern will be attempted.
If there is no match, the `commitPrefix` entries will then be attempted in order until a match is found

> [!IMPORTANT]
> The way golang regex works is when you use `$n` in the replacement string, where `n` is a number, it puts the nth captured subgroup at that place. If `n` is out of range because there aren't that many capture groups in the regex, it puts an empty string there.
>
Expand Down
50 changes: 50 additions & 0 deletions pkg/config/app_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"log"
"os"
"path/filepath"
"regexp"
"strings"
"time"

Expand Down Expand Up @@ -241,6 +242,16 @@ func migrateUserConfig(path string, content []byte) ([]byte, error) {
return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
}

changedContent, err = changeElementToSequence(changedContent, "git.commitPrefix")
if err != nil {
return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
}

changedContent, err = changeCommitPrefixesMap(changedContent)
if err != nil {
return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
}

// Add more migrations here...

// Write config back if changed
Expand All @@ -267,6 +278,45 @@ func changeNullKeybindingsToDisabled(changedContent []byte) ([]byte, error) {
})
}

func changeElementToSequence(changedContent []byte, targetPath string) ([]byte, error) {
return yaml_utils.Walk(changedContent, func(node *yaml.Node, path string) bool {
if path == targetPath && node.Kind == yaml.MappingNode {
nodeContentCopy := node.Content
node.Kind = yaml.SequenceNode
node.Value = ""
node.Tag = "tag:yaml.org,2002:seq"
node.Content = []*yaml.Node{{
Kind: yaml.MappingNode,
Content: nodeContentCopy,
}}

return true
}
return false
})
}

func changeCommitPrefixesMap(changedContent []byte) ([]byte, error) {
positiveRegex := regexp.MustCompile(`^git\.commitPrefixes\..+$`)
return yaml_utils.Walk(changedContent, func(node *yaml.Node, path string) bool {
// Checking Column == 13 ensures that we are on the 3rd indented element. Even if the input yaml has 2 space indentation, the parser has turned it into 4 now
if positiveRegex.FindStringIndex(path) != nil && node.Column == 13 && node.Kind == yaml.MappingNode {
fmt.Println("Found a positiveRegex at column", node.Column)
nodeContentCopy := node.Content
node.Kind = yaml.SequenceNode
node.Value = ""
node.Tag = "tag:yaml.org,2002:seq"
node.Content = []*yaml.Node{{
Kind: yaml.MappingNode,
Content: nodeContentCopy,
}}

return true
}
return false
})
}

func (c *AppConfig) GetDebug() bool {
return c.debug
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/config/user_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,9 @@ type GitConfig struct {
// If true, do not allow force pushes
DisableForcePushing bool `yaml:"disableForcePushing"`
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-commit-message-prefix
CommitPrefix *CommitPrefixConfig `yaml:"commitPrefix"`
CommitPrefix []CommitPrefixConfig `yaml:"commitPrefix"`
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-commit-message-prefix
CommitPrefixes map[string]CommitPrefixConfig `yaml:"commitPrefixes"`
CommitPrefixes map[string][]CommitPrefixConfig `yaml:"commitPrefixes"`
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-branch-name-prefix
BranchPrefix string `yaml:"branchPrefix"`
// If true, parse emoji strings in commit messages e.g. render :rocket: as 🚀
Expand Down Expand Up @@ -784,7 +784,7 @@ func GetDefaultConfig() *UserConfig {
BranchLogCmd: "git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium {{branchName}} --",
AllBranchesLogCmd: "git log --graph --all --color=always --abbrev-commit --decorate --date=relative --pretty=medium",
DisableForcePushing: false,
CommitPrefixes: map[string]CommitPrefixConfig(nil),
CommitPrefixes: map[string][]CommitPrefixConfig(nil),
BranchPrefix: "",
ParseEmoji: false,
TruncateCopiedCommitHashesTo: 12,
Expand Down
13 changes: 7 additions & 6 deletions pkg/gui/controllers/helpers/working_tree_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ func (self *WorkingTreeHelper) HandleCommitPress() error {
message := self.c.Contexts().CommitMessage.GetPreservedMessageAndLogError()

if message == "" {
commitPrefixConfig := self.commitPrefixConfigForRepo()
if commitPrefixConfig != nil {
commitPrefixConfigs := self.commitPrefixConfigsForRepo()
for _, commitPrefixConfig := range commitPrefixConfigs {
prefixPattern := commitPrefixConfig.Pattern
prefixReplace := commitPrefixConfig.Replace
branchName := self.refHelper.GetCheckedOutRef().Name
Expand All @@ -165,6 +165,7 @@ func (self *WorkingTreeHelper) HandleCommitPress() error {
if rgx.MatchString(branchName) {
prefix := rgx.ReplaceAllString(branchName, prefixReplace)
message = prefix
break
}
}
}
Expand Down Expand Up @@ -228,11 +229,11 @@ func (self *WorkingTreeHelper) prepareFilesForCommit() error {
return nil
}

func (self *WorkingTreeHelper) commitPrefixConfigForRepo() *config.CommitPrefixConfig {
func (self *WorkingTreeHelper) commitPrefixConfigsForRepo() []config.CommitPrefixConfig {
cfg, ok := self.c.UserConfig().Git.CommitPrefixes[self.c.Git().RepoPaths.RepoName()]
if ok {
return &cfg
return append(cfg, self.c.UserConfig().Git.CommitPrefix...)
} else {
return self.c.UserConfig().Git.CommitPrefix
}

return self.c.UserConfig().Git.CommitPrefix
}
2 changes: 1 addition & 1 deletion pkg/integration/tests/commit/commit_wip_with_prefix.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var CommitWipWithPrefix = NewIntegrationTest(NewIntegrationTestArgs{
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().Git.CommitPrefixes = map[string]config.CommitPrefixConfig{"repo": {Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}}
cfg.GetUserConfig().Git.CommitPrefixes = map[string][]config.CommitPrefixConfig{"repo": {{Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}}}
},
SetupRepo: func(shell *Shell) {
shell.NewBranch("feature/TEST-002")
Expand Down
2 changes: 1 addition & 1 deletion pkg/integration/tests/commit/commit_with_global_prefix.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var CommitWithGlobalPrefix = NewIntegrationTest(NewIntegrationTestArgs{
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().Git.CommitPrefix = &config.CommitPrefixConfig{Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}
cfg.GetUserConfig().Git.CommitPrefix = []config.CommitPrefixConfig{{Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}}
},
SetupRepo: func(shell *Shell) {
shell.NewBranch("feature/TEST-001")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ var CommitWithNonMatchingBranchName = NewIntegrationTest(NewIntegrationTestArgs{
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().Git.CommitPrefix = &config.CommitPrefixConfig{
cfg.GetUserConfig().Git.CommitPrefix = []config.CommitPrefixConfig{{
Pattern: "^\\w+\\/(\\w+-\\w+).*",
Replace: "[$1]: ",
}
}}
},
SetupRepo: func(shell *Shell) {
shell.NewBranch("branchnomatch")
Expand Down
6 changes: 3 additions & 3 deletions pkg/integration/tests/commit/commit_with_prefix.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ var CommitWithPrefix = NewIntegrationTest(NewIntegrationTestArgs{
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().Git.CommitPrefixes = map[string]config.CommitPrefixConfig{
"repo": {
cfg.GetUserConfig().Git.CommitPrefixes = map[string][]config.CommitPrefixConfig{
"repo": {{
Pattern: `^\w+/(\w+-\w+).*`,
Replace: "[$1]: ",
},
}},
}
},
SetupRepo: func(shell *Shell) {
Expand Down
50 changes: 28 additions & 22 deletions schema/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -638,28 +638,7 @@
"default": false
},
"commitPrefix": {
"properties": {
"pattern": {
"type": "string",
"description": "pattern to match on. E.g. for 'feature/AB-123' to match on the AB-123 use \"^\\\\w+\\\\/(\\\\w+-\\\\w+).*\"",
"examples": [
"^\\w+\\/(\\w+-\\w+).*"
]
},
"replace": {
"type": "string",
"description": "Replace directive. E.g. for 'feature/AB-123' to start the commit message with 'AB-123 ' use \"[$1] \"",
"examples": [
"[$1]"
]
}
},
"additionalProperties": false,
"type": "object",
"description": "See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-commit-message-prefix"
},
"commitPrefixes": {
"additionalProperties": {
"items": {
"properties": {
"pattern": {
"type": "string",
Expand All @@ -679,6 +658,33 @@
"additionalProperties": false,
"type": "object"
},
"type": "array",
"description": "See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-commit-message-prefix"
},
"commitPrefixes": {
"additionalProperties": {
"items": {
"properties": {
"pattern": {
"type": "string",
"description": "pattern to match on. E.g. for 'feature/AB-123' to match on the AB-123 use \"^\\\\w+\\\\/(\\\\w+-\\\\w+).*\"",
"examples": [
"^\\w+\\/(\\w+-\\w+).*"
]
},
"replace": {
"type": "string",
"description": "Replace directive. E.g. for 'feature/AB-123' to start the commit message with 'AB-123 ' use \"[$1] \"",
"examples": [
"[$1]"
]
}
},
"additionalProperties": false,
"type": "object"
},
"type": "array"
},
"type": "object",
"description": "See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-commit-message-prefix"
},
Expand Down
Loading

0 comments on commit a741cfd

Please sign in to comment.