diff --git a/.changeset/loud-breads-raise.md b/.changeset/loud-breads-raise.md new file mode 100644 index 0000000..9cc36f7 --- /dev/null +++ b/.changeset/loud-breads-raise.md @@ -0,0 +1,7 @@ +--- +"@naverpay/commithelper-go": minor +--- + +[commithelper-go] Add support for custom commit message templates + +PR: [[commithelper-go] Add support for custom commit message templates](https://github.com/NaverPayDev/cli/pull/50) diff --git a/packages/commithelper-go/README.md b/packages/commithelper-go/README.md index 028fe6c..aba51e5 100644 --- a/packages/commithelper-go/README.md +++ b/packages/commithelper-go/README.md @@ -96,6 +96,73 @@ This is Basic rule of `.commithelperrc.json`. - Defines branch prefixes that are blocked from committing. `main`, `master`, `develop` branch is blocked by default. +#### template + +- Defines a custom format for commit messages using Go template syntax. +- If not specified, uses the default format: `[{{.Prefix}}] {{.Message}}` +- Available template variables: + - `{{.Message}}`: Original commit message + - `{{.Number}}`: Issue number extracted from branch name + - `{{.Repo}}`: Repository name (empty string if not specified in rules) + - `{{.Prefix}}`: Full prefix (`#123` or `org/repo#123`) + +##### Template Examples + +**Example 1: Add issue reference at the end** + +```json +{ + "rules": { + "feature": null + }, + "template": "{{.Message}}\n\nRef. #{{.Number}}" +} +``` + +Result: + +``` +:memo: Update documentation + +Ref. #123 +``` + +**Example 2: Custom format with repository** + +```json +{ + "rules": { + "qa": "your-org/your-repo" + }, + "template": "{{.Message}}\n\nSee: {{.Prefix}}" +} +``` + +Result: + +``` +:bug: Fix login bug + +See: your-org/your-repo#456 +``` + +**Example 3: Conditional formatting** + +```json +{ + "rules": { + "feature": null + }, + "template": "[{{.Prefix}}] {{.Message}}" +} +``` + +Result: + +``` +[#123] :sparkles: Add new feature +``` + ### Example ```json diff --git a/packages/commithelper-go/main.go b/packages/commithelper-go/main.go index bb6df9c..981debb 100644 --- a/packages/commithelper-go/main.go +++ b/packages/commithelper-go/main.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "encoding/json" "fmt" "io/ioutil" @@ -8,11 +9,20 @@ import ( "os/exec" "regexp" "strings" + "text/template" ) type Config struct { - Rules map[string]*string `json:"rules"` - Protect []string `json:"protect"` + Rules map[string]*string `json:"rules"` + Protect []string `json:"protect"` + Template *string `json:"template,omitempty"` +} + +type TemplateData struct { + Message string + Number string + Repo string + Prefix string } func main() { @@ -63,9 +73,9 @@ func main() { os.Exit(1) } - prefix := generatePrefix(branchName, config) - if prefix != "" { - commitMessage = fmt.Sprintf("[%s] %s", prefix, commitMessage) + templateData := generateTemplateData(branchName, config, commitMessage) + if templateData != nil { + commitMessage = applyTemplate(config, templateData) } if _, err := os.Stat(input); err == nil { @@ -147,6 +157,63 @@ func generatePrefix(branchName string, config Config) string { return fmt.Sprintf("%s#%s", *repo, issueNumber) } +func generateTemplateData(branchName string, config Config, message string) *TemplateData { + pattern := regexp.MustCompile(`^(\w+)/(\d+).*`) + matches := pattern.FindStringSubmatch(branchName) + if len(matches) < 3 { + return nil + } + + prefixKey := matches[1] + issueNumber := matches[2] + + repo, exists := config.Rules[prefixKey] + if !exists { + return nil + } + + var repoName string + var prefix string + if repo == nil { + repoName = "" + prefix = fmt.Sprintf("#%s", issueNumber) + } else { + repoName = *repo + prefix = fmt.Sprintf("%s#%s", *repo, issueNumber) + } + + return &TemplateData{ + Message: message, + Number: issueNumber, + Repo: repoName, + Prefix: prefix, + } +} + +func applyTemplate(config Config, data *TemplateData) string { + // If no template is configured, use default format + if config.Template == nil || *config.Template == "" { + return fmt.Sprintf("[%s] %s", data.Prefix, data.Message) + } + + tmpl, err := template.New("commit").Parse(*config.Template) + if err != nil { + fmt.Printf("Error parsing template: %v\n", err) + // Fallback to default format + return fmt.Sprintf("[%s] %s", data.Prefix, data.Message) + } + + var buf bytes.Buffer + err = tmpl.Execute(&buf, data) + if err != nil { + fmt.Printf("Error executing template: %v\n", err) + // Fallback to default format + return fmt.Sprintf("[%s] %s", data.Prefix, data.Message) + } + + return buf.String() +} + func isProtectedBranch(branchName string, protectedBranches []string) bool { for _, protected := range protectedBranches { if branchName == protected {