refactor: move changelog file to updater interface (#15)

This commit is contained in:
Julian Tölle 2024-08-23 22:17:38 +02:00 committed by GitHub
parent 47de2f97bc
commit f0eed8cc56
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 79 additions and 151 deletions

View file

@ -3,14 +3,8 @@ package rp
import (
"bytes"
_ "embed"
"fmt"
"html/template"
"io"
"log"
"os"
"regexp"
"github.com/go-git/go-git/v5"
)
const (
@ -20,8 +14,6 @@ const (
var (
changelogTemplate *template.Template
headerRegex = regexp.MustCompile(`^# Changelog\n`)
)
//go:embed changelog.md.tpl
@ -35,60 +27,6 @@ func init() {
}
}
func UpdateChangelogFile(wt *git.Worktree, newEntry string) error {
file, err := wt.Filesystem.OpenFile(ChangelogFile, os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
return err
}
defer file.Close()
content, err := io.ReadAll(file)
if err != nil {
return err
}
headerIndex := headerRegex.FindIndex(content)
if headerIndex == nil && len(content) != 0 {
return fmt.Errorf("unexpected format of CHANGELOG.md, header does not match")
}
if headerIndex != nil {
// Remove the header from the content
content = content[headerIndex[1]:]
}
err = file.Truncate(0)
if err != nil {
return err
}
_, err = file.Seek(0, io.SeekStart)
if err != nil {
return err
}
_, err = file.Write([]byte(ChangelogHeader + "\n\n" + newEntry))
if err != nil {
return err
}
_, err = file.Write(content)
if err != nil {
return err
}
// Close file to make sure it is written to disk.
err = file.Close()
if err != nil {
return err
}
_, err = wt.Add(ChangelogFile)
if err != nil {
return err
}
return nil
}
func NewChangelogEntry(commits []AnalyzedCommit, version, link, prefix, suffix string) (string, error) {
features := make([]AnalyzedCommit, 0)
fixes := make([]AnalyzedCommit, 0)

View file

@ -1,99 +1,15 @@
package rp
import (
"io"
"testing"
"github.com/go-git/go-git/v5"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/apricote/releaser-pleaser/internal/testutils"
)
func ptr[T any](input T) *T {
return &input
}
func TestUpdateChangelogFile(t *testing.T) {
tests := []struct {
name string
repoFn testutils.Repo
entry string
expectedContent string
wantErr assert.ErrorAssertionFunc
}{
{
name: "empty repo",
repoFn: testutils.WithTestRepo(),
entry: "## v1.0.0\n",
expectedContent: "# Changelog\n\n## v1.0.0\n",
wantErr: assert.NoError,
},
{
name: "repo with well-formatted changelog",
repoFn: testutils.WithTestRepo(testutils.WithCommit("feat: add changelog", testutils.WithFile(ChangelogFile, `# Changelog
## v0.0.1
- Bazzle
## v0.1.0
### Bazuuum
`))),
entry: "## v1.0.0\n\n- Version 1, juhu.\n",
expectedContent: `# Changelog
## v1.0.0
- Version 1, juhu.
## v0.0.1
- Bazzle
## v0.1.0
### Bazuuum
`,
wantErr: assert.NoError,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
repo := tt.repoFn(t)
wt, err := repo.Worktree()
require.NoError(t, err, "failed to get worktree")
err = UpdateChangelogFile(wt, tt.entry)
if !tt.wantErr(t, err) {
return
}
wtStatus, err := wt.Status()
require.NoError(t, err, "failed to get worktree status")
assert.Len(t, wtStatus, 1, "worktree status does not have the expected entry number")
changelogFileStatus := wtStatus.File(ChangelogFile)
assert.Equal(t, git.Unmodified, changelogFileStatus.Worktree, "unexpected file status in worktree")
assert.Equal(t, git.Added, changelogFileStatus.Staging, "unexpected file status in staging")
changelogFile, err := wt.Filesystem.Open(ChangelogFile)
require.NoError(t, err)
defer changelogFile.Close()
changelogFileContent, err := io.ReadAll(changelogFile)
require.NoError(t, err)
assert.Equal(t, tt.expectedContent, string(changelogFileContent))
})
}
}
func Test_NewChangelogEntry(t *testing.T) {
type args struct {
analyzedCommits []AnalyzedCommit

View file

@ -250,11 +250,6 @@ func (rp *ReleaserPleaser) runReconcileReleasePR(ctx context.Context) error {
// Info for updaters
info := ReleaseInfo{Version: nextVersion, ChangelogEntry: changelogEntry}
err = UpdateChangelogFile(worktree, changelogEntry)
if err != nil {
return fmt.Errorf("failed to update changelog file: %w", err)
}
updateFile := func(path string, updaters []Updater) error {
file, err := worktree.Filesystem.OpenFile(path, os.O_RDWR, 0)
if err != nil {
@ -297,6 +292,11 @@ func (rp *ReleaserPleaser) runReconcileReleasePR(ctx context.Context) error {
return nil
}
err = updateFile(ChangelogFile, []Updater{&ChangelogUpdater{}})
if err != nil {
return fmt.Errorf("failed to update changelog file: %w", err)
}
for _, path := range rp.extraFiles {
_, err = worktree.Filesystem.Stat(path)
if err != nil {

View file

@ -1,12 +1,14 @@
package rp
import (
"fmt"
"regexp"
"strings"
)
var (
GenericUpdaterSemVerRegex = regexp.MustCompile(`\d+\.\d+\.\d+(-[\w.]+)?(.*x-releaser-pleaser-version)`)
ChangelogUpdaterHeaderRegex = regexp.MustCompile(`^# Changelog\n`)
)
type ReleaseInfo struct {
@ -26,3 +28,20 @@ func (u *GenericUpdater) UpdateContent(content string, info ReleaseInfo) (string
return GenericUpdaterSemVerRegex.ReplaceAllString(content, version+"${2}"), nil
}
type ChangelogUpdater struct{}
func (u *ChangelogUpdater) UpdateContent(content string, info ReleaseInfo) (string, error) {
headerIndex := ChangelogUpdaterHeaderRegex.FindStringIndex(content)
if headerIndex == nil && len(content) != 0 {
return "", fmt.Errorf("unexpected format of CHANGELOG.md, header does not match")
}
if headerIndex != nil {
// Remove the header from the content
content = content[headerIndex[1]:]
}
content = ChangelogHeader + "\n\n" + info.ChangelogEntry + content
return content, nil
}

View file

@ -72,3 +72,58 @@ func TestGenericUpdater_UpdateContent(t *testing.T) {
})
}
}
func TestChangelogUpdater_UpdateContent(t *testing.T) {
updater := &ChangelogUpdater{}
tests := []updaterTestCase{
{
name: "empty file",
content: "",
info: ReleaseInfo{ChangelogEntry: "## v1.0.0\n"},
want: "# Changelog\n\n## v1.0.0\n",
wantErr: assert.NoError,
},
{
name: "well-formatted changelog",
content: `# Changelog
## v0.0.1
- Bazzle
## v0.1.0
### Bazuuum
`,
info: ReleaseInfo{ChangelogEntry: "## v1.0.0\n\n- Version 1, juhu.\n"},
want: `# Changelog
## v1.0.0
- Version 1, juhu.
## v0.0.1
- Bazzle
## v0.1.0
### Bazuuum
`,
wantErr: assert.NoError,
},
{
name: "error on invalid header",
content: "What even is this file?",
info: ReleaseInfo{ChangelogEntry: "## v1.0.0\n\n- Version 1, juhu.\n"},
want: "",
wantErr: assert.Error,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
runUpdaterTest(t, updater, tt)
})
}
}