-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
User defined commit message templates #40
Changes from all commits
85316d5
569b874
684fde5
57e5995
1375e37
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
name: PR pipeline | ||
|
||
on: pull_request | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: setup go | ||
uses: actions/setup-go@v5 | ||
with: | ||
go-version: 1.22.1 | ||
- name: Install dependencies | ||
run: go get . | ||
- name: build | ||
run: go build -v ./... | ||
test: | ||
runs-on: ubuntu-latest | ||
needs: build | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: setup go | ||
uses: actions/setup-go@v5 | ||
with: | ||
go-version: 1.22.1 | ||
- name: Install dependencies | ||
run: go get . | ||
- name: test | ||
run: go test -json > meteor-TestResults.json | ||
- name: upload results | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: meteor-TestResults | ||
path: meteor-TestResults.json |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,14 +9,18 @@ import ( | |
"github.com/stefanlogue/meteor/pkg/config" | ||
) | ||
|
||
const defaultCommitTitleCharLimit = 48 | ||
const ( | ||
defaultCommitTitleCharLimit = 48 | ||
defaultMessageTemplate = "{{.Type}}{{if .Scope}}({{.Scope}}){{end}}{{if .IsBreakingChange}}!{{end}}: {{.Message}}" | ||
defaultMessageWithTicketTemplate = "{{.TicketNumber}}{{if .Scope}}({{.Scope}}){{end}}{{if .IsBreakingChange}}!{{end}}: <{{.Type}}> {{.Message}}" | ||
) | ||
|
||
// loadConfig loads the config file from the current directory or any parent | ||
func loadConfig(fs afero.Fs) ([]huh.Option[string], []huh.Option[string], []huh.Option[string], bool, int, error) { | ||
func loadConfig(fs afero.Fs) ([]huh.Option[string], []huh.Option[string], []huh.Option[string], bool, int, string, string, error) { | ||
filePath, err := config.FindConfigFile(fs) | ||
if err != nil { | ||
log.Debug("Error finding config file", "error", err) | ||
return config.DefaultPrefixes, nil, nil, true, defaultCommitTitleCharLimit, nil | ||
return config.DefaultPrefixes, nil, nil, true, defaultCommitTitleCharLimit, defaultMessageTemplate, defaultMessageWithTicketTemplate, nil | ||
} | ||
|
||
log.Debug("found config file", "path", filePath) | ||
|
@@ -25,7 +29,7 @@ func loadConfig(fs afero.Fs) ([]huh.Option[string], []huh.Option[string], []huh. | |
|
||
err = c.LoadFile(filePath) | ||
if err != nil { | ||
return nil, nil, nil, true, defaultCommitTitleCharLimit, fmt.Errorf("error parsing config file: %w", err) | ||
return nil, nil, nil, true, defaultCommitTitleCharLimit, defaultMessageTemplate, defaultMessageWithTicketTemplate, fmt.Errorf("error parsing config file: %w", err) | ||
} | ||
|
||
if c.ShowIntro == nil { | ||
|
@@ -38,5 +42,28 @@ func loadConfig(fs afero.Fs) ([]huh.Option[string], []huh.Option[string], []huh. | |
c.CommitTitleCharLimit = &commitTitleCharLimit | ||
} | ||
|
||
return c.Prefixes.Options(), c.Coauthors.Options(), c.Boards.Options(), *c.ShowIntro, *c.CommitTitleCharLimit, nil | ||
var messageTemplate, messageWithTicketTemplate string | ||
if c.MessageTemplate == nil { | ||
messageTemplate = defaultMessageTemplate | ||
} else { | ||
messageTemplate, err = config.ConvertTemplate(*c.MessageTemplate) | ||
if err != nil { | ||
log.Error("Error converting message template", "error", err) | ||
messageTemplate = defaultMessageTemplate | ||
} | ||
} | ||
c.MessageTemplate = &messageTemplate | ||
|
||
if c.MessageWithTicketTemplate == nil { | ||
messageWithTicketTemplate = defaultMessageWithTicketTemplate | ||
} else { | ||
messageWithTicketTemplate, err = config.ConvertTemplate(*c.MessageWithTicketTemplate) | ||
if err != nil { | ||
log.Error("Error converting message with ticket template", "error", err) | ||
messageWithTicketTemplate = defaultMessageWithTicketTemplate | ||
} | ||
} | ||
Comment on lines
+57
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could apply the same pattern I described here |
||
c.MessageWithTicketTemplate = &messageWithTicketTemplate | ||
|
||
return c.Prefixes.Options(), c.Coauthors.Options(), c.Boards.Options(), *c.ShowIntro, *c.CommitTitleCharLimit, messageTemplate, messageWithTicketTemplate, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ import ( | |
"bytes" | ||
"fmt" | ||
"os" | ||
"text/template" | ||
"time" | ||
|
||
"github.com/charmbracelet/log" | ||
|
@@ -85,7 +86,7 @@ func main() { | |
fail("Could not change directory: %s", err) | ||
} | ||
|
||
prefixes, coauthors, boards, showIntro, commitTitleCharLimit, err := loadConfig(AFS) | ||
prefixes, coauthors, boards, showIntro, commitTitleCharLimit, messageTemplate, messageWithTicketTemplate, err := loadConfig(AFS) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could consider returning a struct, there are way too much returned values |
||
if err != nil { | ||
fail("Error: %s", err) | ||
} | ||
|
@@ -183,35 +184,18 @@ func main() { | |
fail("Error: %s", err) | ||
} | ||
|
||
var tmpl *template.Template | ||
if len(newCommit.Board) > 0 && newCommit.Board != "NONE" { | ||
if newCommit.IsBreakingChange { | ||
if len(newCommit.Scope) > 0 { | ||
newCommit.Message = fmt.Sprintf("%s(%s)!: <%s> ", newCommit.TicketNumber, newCommit.Scope, newCommit.Type) | ||
} else { | ||
newCommit.Message = fmt.Sprintf("%s!: <%s> ", newCommit.TicketNumber, newCommit.Type) | ||
} | ||
} else { | ||
if len(newCommit.Scope) > 0 { | ||
newCommit.Message = fmt.Sprintf("%s(%s): <%s> ", newCommit.TicketNumber, newCommit.Scope, newCommit.Type) | ||
} else { | ||
newCommit.Message = fmt.Sprintf("%s: <%s> ", newCommit.TicketNumber, newCommit.Type) | ||
} | ||
} | ||
tmpl = template.Must(template.New("message").Parse(messageWithTicketTemplate)) | ||
} else { | ||
if newCommit.IsBreakingChange { | ||
if len(newCommit.Scope) > 0 { | ||
newCommit.Message = fmt.Sprintf("%s(%s)!: ", newCommit.Type, newCommit.Scope) | ||
} else { | ||
newCommit.Message = fmt.Sprintf("%s!: ", newCommit.Type) | ||
} | ||
} else { | ||
if len(newCommit.Scope) > 0 { | ||
newCommit.Message = fmt.Sprintf("%s(%s): ", newCommit.Type, newCommit.Scope) | ||
} else { | ||
newCommit.Message = fmt.Sprintf("%s: ", newCommit.Type) | ||
} | ||
} | ||
tmpl = template.Must(template.New("message").Parse(messageTemplate)) | ||
} | ||
buf := new(bytes.Buffer) | ||
err = tmpl.Execute(buf, newCommit) | ||
if err != nil { | ||
fail("Error: %s", err) | ||
} | ||
newCommit.Message = buf.String() | ||
|
||
doesWantToCommit := true | ||
messageForm := huh.NewForm( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package config | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
func ConvertTemplate(t string) (string, error) { | ||
if !strings.Contains(t, "@type") || !strings.Contains(t, "@message") { | ||
return t, fmt.Errorf("template must contain @type and @message") | ||
} | ||
t = strings.Replace(t, ":", "{{if .IsBreakingChange}}!{{end}}:", 1) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your template system might be "hacked" if someone provide a `{{ whatever }}`` syntax Maybe you could forbid the presence of |
||
t = strings.ReplaceAll(t, "@type", "{{.Type}}") | ||
t = strings.ReplaceAll(t, "(@scope)", "{{if .Scope}}({{.Scope}}){{end}}") | ||
t = strings.ReplaceAll(t, "@ticket", "{{.TicketNumber}}") | ||
t = strings.ReplaceAll(t, "@message", "{{.Message}}") | ||
return t, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package config | ||
|
||
import "testing" | ||
|
||
func TestConvertTemplate(t *testing.T) { | ||
cases := []struct { | ||
name string | ||
input string | ||
want string | ||
}{ | ||
{"adds breaking change marker", "@type: @message", "{{.Type}}{{if .IsBreakingChange}}!{{end}}: {{.Message}}"}, | ||
{"converts template", "@type(@scope): @message", "{{.Type}}{{if .Scope}}({{.Scope}}){{end}}{{if .IsBreakingChange}}!{{end}}: {{.Message}}"}, | ||
{"converts without scope", "@type: @message", "{{.Type}}{{if .IsBreakingChange}}!{{end}}: {{.Message}}"}, | ||
} | ||
for _, tc := range cases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
got, _ := ConvertTemplate(tc.input) | ||
assertEqual(t, tc.want, got) | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might ne essier to reader