diff --git a/cmd/uplift/changelog.go b/cmd/uplift/changelog.go index 4bb40254..21621c6b 100644 --- a/cmd/uplift/changelog.go +++ b/cmd/uplift/changelog.go @@ -178,7 +178,7 @@ func setupChangelogContext(opts changelogOptions, out io.Writer) (*context.Conte ctx.Changelog.Exclude = append(ctx.Changelog.Exclude, ctx.Config.Changelog.Exclude...) // By default ensure the ci(uplift): commits are excluded also - ctx.Changelog.Exclude = append(ctx.Changelog.Exclude, "ci(uplift):") + ctx.Changelog.Exclude = append(ctx.Changelog.Exclude, `ci\(uplift\)`) if !ctx.Changelog.All { // Attempt to retrieve the latest 2 tags for generating a changelog entry diff --git a/internal/git/utils.go b/internal/git/utils.go index 982f7eda..223687c7 100644 --- a/internal/git/utils.go +++ b/internal/git/utils.go @@ -431,7 +431,7 @@ func Push() error { // LogBetween retrieves all log entries between two points of time within the // git history of the repository. Supports tags and specific git hashes as its // reference points. From must always be the closest point to HEAD -func LogBetween(from, to string, excludes []string) ([]LogEntry, error) { +func LogBetween(from, to string) ([]LogEntry, error) { fmtFrom := from if fmtFrom == "" { fmtFrom = "HEAD" @@ -446,19 +446,9 @@ func LogBetween(from, to string, excludes []string) ([]LogEntry, error) { args := []string{ "log", fmt.Sprintf("%s%s", fmtFrom, fmtTo), - "--pretty=format:'%H%s'", - } - - // Convert excludes list into git grep commands - if len(excludes) > 0 { - fmtExcludes := make([]string, len(excludes)) - for i := range excludes { - fmtExcludes[i] = fmt.Sprintf("--grep=%s", excludes[i]) - } - fmtExcludes = append(fmtExcludes, "--invert-grep") - - // Append to original set of arguments - args = append(args, fmtExcludes...) + "--pretty=oneline", + "--no-decorate", + "--no-color", } log, err := Clean(Run(args...)) @@ -473,10 +463,12 @@ func LogBetween(from, to string, excludes []string) ([]LogEntry, error) { rows := strings.Split(log, "\n") les := make([]LogEntry, 0, len(rows)) for _, r := range rows { + // Always a single whitespace between the hash and message + hash, message, _ := strings.Cut(r, " ") les = append(les, LogEntry{ - Hash: r[:40], - AbbrevHash: r[:7], - Message: r[40:], + Hash: hash, + AbbrevHash: hash[:7], + Message: message, }) } diff --git a/internal/git/utils_test.go b/internal/git/utils_test.go index 8a6290b2..efa01503 100644 --- a/internal/git/utils_test.go +++ b/internal/git/utils_test.go @@ -674,7 +674,7 @@ func TestLogBetween_TwoTags(t *testing.T) { EmptyCommitAndTag(t, "1.0.0", "first commit") EmptyCommitsAndTag(t, "2.0.0", "second commit", "third commit", "forth commit") - log, err := LogBetween("2.0.0", "1.0.0", []string{}) + log, err := LogBetween("2.0.0", "1.0.0") require.NoError(t, err) require.Len(t, log, 3) @@ -688,7 +688,7 @@ func TestLogBetween_PrereleaseTag(t *testing.T) { EmptyCommitAndTag(t, "0.1.0", "first commit") EmptyCommitsAndTag(t, "0.2.0-beta1+12345", "second commit", "third commit") - log, err := LogBetween("0.2.0-beta1+12345", "0.1.0", []string{}) + log, err := LogBetween("0.2.0-beta1+12345", "0.1.0") require.NoError(t, err) require.Len(t, log, 2) @@ -700,7 +700,7 @@ func TestLogBetween_TwoHashes(t *testing.T) { InitRepo(t) h := EmptyCommits(t, "first commit", "second commit", "third commit", "forth commit") - log, err := LogBetween(h[2], h[1], []string{}) + log, err := LogBetween(h[2], h[1]) require.NoError(t, err) require.Len(t, log, 1) @@ -712,7 +712,7 @@ func TestLogBetween_FromSpecificTag(t *testing.T) { EmptyCommitsAndTag(t, "1.0.0", "first commit", "second commit") EmptyCommit(t, "third commit") - log, err := LogBetween("1.0.0", "", []string{}) + log, err := LogBetween("1.0.0", "") require.NoError(t, err) require.Len(t, log, 3) @@ -725,7 +725,7 @@ func TestLogBetween_FromSpecificHash(t *testing.T) { InitRepo(t) h := EmptyCommits(t, "first commit", "second commit", "third commit", "forth commit") - log, err := LogBetween(h[2], "", []string{}) + log, err := LogBetween(h[2], "") require.NoError(t, err) require.Len(t, log, 4) @@ -739,7 +739,7 @@ func TestLogBetween_ToSpecificHash(t *testing.T) { InitRepo(t) h := EmptyCommits(t, "first commit", "second commit", "third commit", "forth commit") - log, err := LogBetween("", h[2], []string{}) + log, err := LogBetween("", h[2]) require.NoError(t, err) require.Len(t, log, 1) @@ -751,7 +751,7 @@ func TestLogBetween_ToSpecificTag(t *testing.T) { EmptyCommitsAndTag(t, "1.0.0", "first commit", "second commit") EmptyCommit(t, "third commit") - log, err := LogBetween("", "1.0.0", []string{}) + log, err := LogBetween("", "1.0.0") require.NoError(t, err) require.Len(t, log, 1) @@ -762,7 +762,7 @@ func TestLogBetween_All(t *testing.T) { InitRepo(t) EmptyCommits(t, "first commit", "second commit", "third commit") - log, err := LogBetween("", "", []string{}) + log, err := LogBetween("", "") require.NoError(t, err) require.Len(t, log, 4) @@ -789,7 +789,7 @@ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliqu InitRepo(t) EmptyCommits(t, c1, c2, c3) - log, err := LogBetween("", "", []string{}) + log, err := LogBetween("", "") require.NoError(t, err) require.Len(t, log, 4) @@ -802,7 +802,7 @@ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliqu func TestLogBetween_ErrorInvalidRevision(t *testing.T) { InitRepo(t) - _, err := LogBetween("1234567", "", []string{}) + _, err := LogBetween("1234567", "") require.Error(t, err) } @@ -813,40 +813,12 @@ func TestLogBetween_TwoTagsAtSameCommit(t *testing.T) { err := Tag("1.1.0") require.NoError(t, err) - log, err := LogBetween("1.1.0", "1.0.0", []string{}) + log, err := LogBetween("1.1.0", "1.0.0") require.NoError(t, err) assert.Len(t, log, 0) } -func TestLogBetween_Excludes(t *testing.T) { - InitRepo(t) - EmptyCommitAndTag(t, "0.1.0", "first commit") - EmptyCommits(t, "second commit", "exclude: third commit", "ignore: forth commit") - EmptyCommitAndTag(t, "0.2.0", "fifth commit") - - log, err := LogBetween("0.2.0", "0.1.0", []string{"exclude", "ignore"}) - require.NoError(t, err) - - assert.Len(t, log, 2) - assert.Equal(t, log[0].Message, "fifth commit") - assert.Equal(t, log[1].Message, "second commit") -} - -func TestLogBetween_ExcludesWildcards(t *testing.T) { - InitRepo(t) - EmptyCommitAndTag(t, "0.1.0", "first commit") - EmptyCommits(t, "second commit", "exclude: third commit", "exclude(scope): forth commit") - EmptyCommitAndTag(t, "0.2.0", "fifth commit") - - log, err := LogBetween("0.2.0", "0.1.0", []string{"exclude*"}) - require.NoError(t, err) - - assert.Len(t, log, 2) - assert.Equal(t, log[0].Message, "fifth commit") - assert.Equal(t, log[1].Message, "second commit") -} - func TestStaged(t *testing.T) { InitRepo(t) os.WriteFile("test1.txt", []byte(`testing`), 0o644) diff --git a/internal/task/bump/json_test.go b/internal/task/bump/json_test.go index 5f636803..35e015e3 100644 --- a/internal/task/bump/json_test.go +++ b/internal/task/bump/json_test.go @@ -122,6 +122,7 @@ func TestRun_JSONStrictSemVer(t *testing.T) { } func TestRun_JSONDryRun(t *testing.T) { + git.InitRepo(t) path := WriteFile(t, `{"version": "0.1.0"}`) ctx := &context.Context{ diff --git a/internal/task/bump/regex_test.go b/internal/task/bump/regex_test.go index 0c07ca6f..5f6297a8 100644 --- a/internal/task/bump/regex_test.go +++ b/internal/task/bump/regex_test.go @@ -215,6 +215,7 @@ func TestRun_RegexForceSemanticVersion(t *testing.T) { } func TestRun_RegexDryRun(t *testing.T) { + git.InitRepo(t) path := WriteFile(t, "version: 0.1.0") ctx := &context.Context{ diff --git a/internal/task/changelog/changelog.go b/internal/task/changelog/changelog.go index 8cf1a521..7f5f0378 100644 --- a/internal/task/changelog/changelog.go +++ b/internal/task/changelog/changelog.go @@ -28,6 +28,7 @@ import ( "errors" "fmt" "os" + "regexp" "strings" "text/template" "time" @@ -158,11 +159,19 @@ func (t Task) Run(ctx *context.Context) error { func changelogRelease(ctx *context.Context) ([]release, error) { log.WithField("tag", ctx.NextVersion.Raw).Info("determine changes for release") - ents, err := git.LogBetween(ctx.NextVersion.Raw, ctx.CurrentVersion.Raw, ctx.Changelog.Exclude) + ents, err := git.LogBetween(ctx.NextVersion.Raw, ctx.CurrentVersion.Raw) if err != nil { return []release{}, err } + if len(ctx.Changelog.Exclude) > 0 { + log.Info("removing commits based on exclude list") + ents, err = excludeCommits(ents, ctx.Changelog.Exclude) + if err != nil { + return []release{}, err + } + } + if len(ents) == 0 { log.WithFields(log.Fields{ "tag": ctx.NextVersion.Raw, @@ -214,11 +223,19 @@ func changelogReleases(ctx *context.Context) ([]release, error) { } log.WithField("tag", tags[i].Ref).Info("determine changes for release") - ents, err := git.LogBetween(tags[i].Ref, nextTag, ctx.Changelog.Exclude) + ents, err := git.LogBetween(tags[i].Ref, nextTag) if err != nil { return []release{}, err } + if len(ctx.Changelog.Exclude) > 0 { + log.Info("removing commits based on exclude list") + ents, err = excludeCommits(ents, ctx.Changelog.Exclude) + if err != nil { + return []release{}, err + } + } + if len(ents) == 0 { log.WithFields(log.Fields{ "tag": tags[i].Ref, @@ -321,3 +338,24 @@ func reverse(ents []git.LogEntry) { j-- } } + +func excludeCommits(commits []git.LogEntry, excludes []string) ([]git.LogEntry, error) { + filtered := commits + for _, exclude := range excludes { + excludeRgx, err := regexp.Compile(exclude) + if err != nil { + return filtered, err + } + + // Carry out a filtering pass for each defined + filterPass := []git.LogEntry{} + for _, commit := range filtered { + if !excludeRgx.MatchString(commit.Message) { + filterPass = append(filterPass, commit) + } + } + filtered = filterPass + } + + return filtered, nil +}