Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/loud-breads-raise.md
Original file line number Diff line number Diff line change
@@ -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)
67 changes: 67 additions & 0 deletions packages/commithelper-go/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
77 changes: 72 additions & 5 deletions packages/commithelper-go/main.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
package main

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"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() {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down