From 2fa4ee2cacaaa5b7e16c6e6c6a15bd58a6561ee3 Mon Sep 17 00:00:00 2001 From: Chris McDonnell Date: Mon, 10 Feb 2025 22:34:22 -0500 Subject: [PATCH] feat: Support multiple commit prefixes This implementation, unlike that proposed in https://github.com/jesseduffield/lazygit/pull/4253 keeps the yaml schema easy, and does a migration from the single elements to a sequence of elements. --- docs/Config.md | 35 ++++---- pkg/config/app_config.go | 81 ++++++++++++++++--- pkg/config/app_config_test.go | 78 ++++++++++++++++++ pkg/config/user_config.go | 6 +- .../helpers/working_tree_helper.go | 13 +-- .../tests/commit/commit_wip_with_prefix.go | 2 +- .../commit/commit_with_fallthrough_prefix.go | 53 ++++++++++++ .../tests/commit/commit_with_global_prefix.go | 2 +- .../commit_with_non_matching_branch_name.go | 4 +- .../tests/commit/commit_with_prefix.go | 6 +- pkg/integration/tests/test_list.go | 1 + pkg/utils/yaml_utils/yaml_utils.go | 51 +++++++++++- pkg/utils/yaml_utils/yaml_utils_test.go | 78 ++++++++++++++++++ schema/config.json | 50 +++++++----- 14 files changed, 395 insertions(+), 65 deletions(-) create mode 100644 pkg/config/app_config_test.go create mode 100644 pkg/integration/tests/commit/commit_with_fallthrough_prefix.go diff --git a/docs/Config.md b/docs/Config.md index 5d034695b..26fa2efb6 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -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: "" @@ -922,27 +914,40 @@ Where: ## Predefined commit message prefix In situations where certain naming pattern is used for branches and commits, pattern can be used to populate commit message with prefix that is parsed from the branch name. +If you define multiple naming patterns, they will be attempted in order until one matches. -Example: +Example hitting first match: - Branch name: feature/AB-123 -- Commit message: [AB-123] Adding feature +- Generated commit message prefix: [AB-123] + +Example hitting second match: + +- Branch name: CD-456_fix_problem +- Generated commit message prefix: (CD-456) ```yaml git: commitPrefix: - pattern: "^\\w+\\/(\\w+-\\w+).*" - replace: '[$1] ' + - pattern: "^\\w+\\/(\\w+-\\w+).*" + replace: '[$1] ' + - pattern: "^([^_]+)_.*" # Take all text prior to the first underscore + 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` entries will be attempted first. 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] ' ``` > [!IMPORTANT] diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index 5d240b87d..cfdc75e31 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -217,6 +217,26 @@ func loadUserConfig(configFiles []*ConfigFile, base *UserConfig) (*UserConfig, e // from one container to another, or changing the type of a key (e.g. from bool // to an enum). func migrateUserConfig(path string, content []byte) ([]byte, error) { + changedContent, err := computeMigratedConfig(path, content) + if err != nil { + return nil, err + } + + // Write config back if changed + if string(changedContent) != string(content) { + fmt.Println("Provided user config is deprecated but auto-fixable. Attempting to write fixed version back to file...") + if err := os.WriteFile(path, changedContent, 0o644); err != nil { + return nil, fmt.Errorf("While attempting to write back fixed user config to %s, an error occurred: %s", path, err) + } + fmt.Printf("Success. New config written to %s\n", path) + return changedContent, nil + } + + return content, nil +} + +// A pure function helper for testing purposes +func computeMigratedConfig(path string, content []byte) ([]byte, error) { changedContent := content pathsToReplace := []struct { @@ -241,19 +261,18 @@ func migrateUserConfig(path string, content []byte) ([]byte, error) { return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err) } - // Add more migrations here... - - // Write config back if changed - if string(changedContent) != string(content) { - fmt.Println("Provided user config is deprecated but auto-fixable. Attempting to write fixed version back to file...") - if err := os.WriteFile(path, changedContent, 0o644); err != nil { - return nil, fmt.Errorf("While attempting to write back fixed user config to %s, an error occurred: %s", path, err) - } - fmt.Printf("Success. New config written to %s\n", path) - return changedContent, nil + changedContent, err = changeElementToSequence(changedContent, []string{"git", "commitPrefix"}) + if err != nil { + return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err) } - return content, nil + 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... + + return changedContent, nil } func changeNullKeybindingsToDisabled(changedContent []byte) ([]byte, error) { @@ -267,6 +286,46 @@ func changeNullKeybindingsToDisabled(changedContent []byte) ([]byte, error) { }) } +func changeElementToSequence(changedContent []byte, path []string) ([]byte, error) { + return yaml_utils.TransformNode(changedContent, path, func(node *yaml.Node) (bool, error) { + if node.Kind == yaml.MappingNode { + nodeContentCopy := node.Content + node.Kind = yaml.SequenceNode + node.Value = "" + node.Tag = "!!seq" + node.Content = []*yaml.Node{{ + Kind: yaml.MappingNode, + Content: nodeContentCopy, + }} + + return true, nil + } + return false, nil + }) +} + +func changeCommitPrefixesMap(changedContent []byte) ([]byte, error) { + return yaml_utils.TransformNode(changedContent, []string{"git", "commitPrefixes"}, func(prefixesNode *yaml.Node) (bool, error) { + if prefixesNode.Kind == yaml.MappingNode { + for _, contentNode := range prefixesNode.Content { + if contentNode.Kind == yaml.MappingNode { + nodeContentCopy := contentNode.Content + contentNode.Kind = yaml.SequenceNode + contentNode.Value = "" + contentNode.Tag = "!!seq" + contentNode.Content = []*yaml.Node{{ + Kind: yaml.MappingNode, + Content: nodeContentCopy, + }} + + } + } + return true, nil + } + return false, nil + }) +} + func (c *AppConfig) GetDebug() bool { return c.debug } diff --git a/pkg/config/app_config_test.go b/pkg/config/app_config_test.go new file mode 100644 index 000000000..044161104 --- /dev/null +++ b/pkg/config/app_config_test.go @@ -0,0 +1,78 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" +) + +func TestCommitPrefixMigrations(t *testing.T) { + scenarios := []struct { + name string + input string + expected string + }{ + { + "Empty String", + "", + "", + }, { + "Single CommitPrefix Rename", + ` +git: + commitPrefix: + pattern: "^\\w+-\\w+.*" + replace: '[JIRA $0] '`, + ` +git: + commitPrefix: + - pattern: "^\\w+-\\w+.*" + replace: '[JIRA $0] '`, + }, { + "Complicated CommitPrefixes Rename", + ` +git: + commitPrefixes: + foo: + pattern: "^\\w+-\\w+.*" + replace: '[OTHER $0] ' + CrazyName!@#$^*&)_-)[[}{f{[]: + pattern: "^foo.bar*" + replace: '[FUN $0] '`, + ` +git: + commitPrefixes: + foo: + - pattern: "^\\w+-\\w+.*" + replace: '[OTHER $0] ' + CrazyName!@#$^*&)_-)[[}{f{[]: + - pattern: "^foo.bar*" + replace: '[FUN $0] '`, + }, { + "Incomplete Configuration", + "git:", + "git:", + }, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + expectedConfig := GetDefaultConfig() + err := yaml.Unmarshal([]byte(s.expected), expectedConfig) + if err != nil { + t.Error(err) + } + actual, err := computeMigratedConfig("path doesn't matter", []byte(s.input)) + if err != nil { + t.Error(err) + } + actualConfig := GetDefaultConfig() + err = yaml.Unmarshal(actual, actualConfig) + if err != nil { + t.Error(err) + } + assert.Equal(t, expectedConfig, actualConfig) + }) + } +} diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 9d5fb3742..169b67c40 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -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 🚀 @@ -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, diff --git a/pkg/gui/controllers/helpers/working_tree_helper.go b/pkg/gui/controllers/helpers/working_tree_helper.go index 6f6e0eaab..c967fab92 100644 --- a/pkg/gui/controllers/helpers/working_tree_helper.go +++ b/pkg/gui/controllers/helpers/working_tree_helper.go @@ -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 @@ -165,6 +165,7 @@ func (self *WorkingTreeHelper) HandleCommitPress() error { if rgx.MatchString(branchName) { prefix := rgx.ReplaceAllString(branchName, prefixReplace) message = prefix + break } } } @@ -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 } diff --git a/pkg/integration/tests/commit/commit_wip_with_prefix.go b/pkg/integration/tests/commit/commit_wip_with_prefix.go index a39a168fe..6223de04f 100644 --- a/pkg/integration/tests/commit/commit_wip_with_prefix.go +++ b/pkg/integration/tests/commit/commit_wip_with_prefix.go @@ -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") diff --git a/pkg/integration/tests/commit/commit_with_fallthrough_prefix.go b/pkg/integration/tests/commit/commit_with_fallthrough_prefix.go new file mode 100644 index 000000000..801443c59 --- /dev/null +++ b/pkg/integration/tests/commit/commit_with_fallthrough_prefix.go @@ -0,0 +1,53 @@ +package commit + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var CommitWithFallthroughPrefix = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Commit with multiple CommitPrefixConfig", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(cfg *config.AppConfig) { + cfg.GetUserConfig().Git.CommitPrefix = []config.CommitPrefixConfig{ + {Pattern: "^doesntmatch-(\\w+).*", Replace: "[BAD $1]: "}, + {Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[GOOD $1]: "}, + } + cfg.GetUserConfig().Git.CommitPrefixes = map[string][]config.CommitPrefixConfig{ + "DifferentProject": {{Pattern: "^otherthatdoesn'tmatch-(\\w+).*", Replace: "[BAD $1]: "}}, + } + }, + SetupRepo: func(shell *Shell) { + shell.NewBranch("feature/TEST-001") + shell.CreateFile("test-commit-prefix", "This is foo bar") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits(). + IsEmpty() + + t.Views().Files(). + IsFocused(). + PressPrimaryAction(). + Press(keys.Files.CommitChanges) + + t.ExpectPopup().CommitMessagePanel(). + Title(Equals("Commit summary")). + InitialText(Equals("[GOOD TEST-001]: ")). + Type("my commit message"). + Cancel() + + t.Views().Files(). + IsFocused(). + Press(keys.Files.CommitChanges) + + t.ExpectPopup().CommitMessagePanel(). + Title(Equals("Commit summary")). + InitialText(Equals("[GOOD TEST-001]: my commit message")). + Type(". Added something else"). + Confirm() + + t.Views().Commits().Focus() + t.Views().Main().Content(Contains("[GOOD TEST-001]: my commit message. Added something else")) + }, +}) diff --git a/pkg/integration/tests/commit/commit_with_global_prefix.go b/pkg/integration/tests/commit/commit_with_global_prefix.go index f5e67fba3..ceb2314c1 100644 --- a/pkg/integration/tests/commit/commit_with_global_prefix.go +++ b/pkg/integration/tests/commit/commit_with_global_prefix.go @@ -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") diff --git a/pkg/integration/tests/commit/commit_with_non_matching_branch_name.go b/pkg/integration/tests/commit/commit_with_non_matching_branch_name.go index 98f35d6d2..d08264d21 100644 --- a/pkg/integration/tests/commit/commit_with_non_matching_branch_name.go +++ b/pkg/integration/tests/commit/commit_with_non_matching_branch_name.go @@ -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") diff --git a/pkg/integration/tests/commit/commit_with_prefix.go b/pkg/integration/tests/commit/commit_with_prefix.go index fa49b0baf..09bbf63b4 100644 --- a/pkg/integration/tests/commit/commit_with_prefix.go +++ b/pkg/integration/tests/commit/commit_with_prefix.go @@ -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) { diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 1ea9b2b03..6a3830157 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -93,6 +93,7 @@ var tests = []*components.IntegrationTest{ commit.CommitMultiline, commit.CommitSwitchToEditor, commit.CommitWipWithPrefix, + commit.CommitWithFallthroughPrefix, commit.CommitWithGlobalPrefix, commit.CommitWithNonMatchingBranchName, commit.CommitWithPrefix, diff --git a/pkg/utils/yaml_utils/yaml_utils.go b/pkg/utils/yaml_utils/yaml_utils.go index 37d521c6a..d0da6fdf2 100644 --- a/pkg/utils/yaml_utils/yaml_utils.go +++ b/pkg/utils/yaml_utils/yaml_utils.go @@ -99,6 +99,55 @@ func lookupKey(node *yaml.Node, key string) (*yaml.Node, *yaml.Node) { return nil, nil } +// Walks a yaml document to the specified path, and then applies the transformation to that node. +// +// The transform must return true if it made changes to the node. +// If the requested path is not defined in the document, no changes are made to the document. +// +// If no changes are made, the original document is returned. +// If changes are made, a newly marshalled document is returned. (This may result in different indentation for all nodes) +func TransformNode(yamlBytes []byte, path []string, transform func(node *yaml.Node) (bool, error)) ([]byte, error) { + // Parse the YAML file. + var node yaml.Node + err := yaml.Unmarshal(yamlBytes, &node) + if err != nil { + return nil, fmt.Errorf("failed to parse YAML: %w", err) + } + + // Empty document: nothing to do. + if len(node.Content) == 0 { + return yamlBytes, nil + } + + body := node.Content[0] + + if didTransform, err := transformNode(body, path, transform); err != nil || !didTransform { + return yamlBytes, err + } + + // Convert the updated YAML node back to YAML bytes. + updatedYAMLBytes, err := yaml.Marshal(body) + if err != nil { + return nil, fmt.Errorf("failed to convert YAML node to bytes: %w", err) + } + + return updatedYAMLBytes, nil +} + +// A recursive function to walk down the tree. See TransformNode for more details. +func transformNode(node *yaml.Node, path []string, transform func(node *yaml.Node) (bool, error)) (bool, error) { + if len(path) == 0 { + return transform(node) + } + + keyNode, valueNode := lookupKey(node, path[0]) + if keyNode == nil { + return false, nil + } + + return transformNode(valueNode, path[1:], transform) +} + // takes a yaml document in bytes, a path to a key, and a new name for the key. // Will rename the key to the new name if it exists, and do nothing otherwise. func RenameYamlKey(yamlBytes []byte, path []string, newKey string) ([]byte, error) { @@ -106,7 +155,7 @@ func RenameYamlKey(yamlBytes []byte, path []string, newKey string) ([]byte, erro var node yaml.Node err := yaml.Unmarshal(yamlBytes, &node) if err != nil { - return nil, fmt.Errorf("failed to parse YAML: %w", err) + return nil, fmt.Errorf("failed to parse YAML: %w for bytes %s", err, string(yamlBytes)) } // Empty document: nothing to do. diff --git a/pkg/utils/yaml_utils/yaml_utils_test.go b/pkg/utils/yaml_utils/yaml_utils_test.go index a65f0abf8..c98d2d53f 100644 --- a/pkg/utils/yaml_utils/yaml_utils_test.go +++ b/pkg/utils/yaml_utils/yaml_utils_test.go @@ -1,6 +1,7 @@ package yaml_utils import ( + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -314,3 +315,80 @@ func TestWalk_inPlaceChanges(t *testing.T) { }) } } + +func TestTransformNode(t *testing.T) { + transformIntValueToString := func(node *yaml.Node) (bool, error) { + if node.Kind == yaml.ScalarNode { + if node.ShortTag() == "!!int" { + node.Tag = "!!str" + return true, nil + } else if node.ShortTag() == "!!str" { + // We have already transformed it, + return false, nil + } else { + return false, fmt.Errorf("Node was of bad type") + } + } else { + return false, fmt.Errorf("Node was not a scalar") + } + } + + tests := []struct { + name string + in string + path []string + transform func(node *yaml.Node) (bool, error) + expectedOut string + }{ + { + name: "Path not present", + in: "foo: 1", + path: []string{"bar"}, + transform: transformIntValueToString, + expectedOut: "foo: 1", + }, + { + name: "Part of path present", + in: ` +foo: + bar: 2`, + path: []string{"foo", "baz"}, + transform: transformIntValueToString, + expectedOut: ` +foo: + bar: 2`, + }, + { + name: "Successfully Transforms to string", + in: ` +foo: + bar: 2`, + path: []string{"foo", "bar"}, + transform: transformIntValueToString, + expectedOut: `foo: + bar: "2" +`, // Note the indentiation change and newlines because of how it re-marshalls + }, + { + name: "Does nothing when already transformed", + in: ` +foo: + bar: "2"`, + path: []string{"foo", "bar"}, + transform: transformIntValueToString, + expectedOut: ` +foo: + bar: "2"`, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result, err := TransformNode([]byte(test.in), test.path, test.transform) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, test.expectedOut, string(result)) + }) + } +} diff --git a/schema/config.json b/schema/config.json index fff823018..492f923e0 100644 --- a/schema/config.json +++ b/schema/config.json @@ -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", @@ -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" },