feat(release): automate release preparation
This commit is contained in:
90
internal/releaseprep/releaseprep.go
Normal file
90
internal/releaseprep/releaseprep.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package releaseprep
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var versionPattern = regexp.MustCompile(`const String = "[^"]+"`)
|
||||
|
||||
func Prepare(rootDir, version, releaseDate string) error {
|
||||
normalizedVersion := strings.TrimPrefix(strings.TrimSpace(version), "v")
|
||||
if normalizedVersion == "" {
|
||||
return fmt.Errorf("version must not be empty")
|
||||
}
|
||||
|
||||
releaseDate = strings.TrimSpace(releaseDate)
|
||||
if releaseDate == "" {
|
||||
return fmt.Errorf("release date must not be empty")
|
||||
}
|
||||
|
||||
if err := updateVersionFile(rootDir, normalizedVersion); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := updateChangelog(rootDir, normalizedVersion, releaseDate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateVersionFile(rootDir, version string) error {
|
||||
path := filepath.Join(rootDir, "internal", "homesick", "version", "version.go")
|
||||
contents, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read version file: %w", err)
|
||||
}
|
||||
|
||||
updated := versionPattern.ReplaceAllString(string(contents), fmt.Sprintf(`const String = %q`, version))
|
||||
if updated == string(contents) {
|
||||
return fmt.Errorf("version constant not found in %s", path)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(path, []byte(updated), 0o644); err != nil {
|
||||
return fmt.Errorf("write version file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateChangelog(rootDir, version, releaseDate string) error {
|
||||
path := filepath.Join(rootDir, "changelog.md")
|
||||
contents, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read changelog: %w", err)
|
||||
}
|
||||
|
||||
text := string(contents)
|
||||
unreleasedHeader := "## [Unreleased]\n"
|
||||
start := strings.Index(text, unreleasedHeader)
|
||||
if start == -1 {
|
||||
return fmt.Errorf("unreleased section not found in changelog")
|
||||
}
|
||||
|
||||
afterHeader := start + len(unreleasedHeader)
|
||||
nextSectionRelative := strings.Index(text[afterHeader:], "\n## [")
|
||||
if nextSectionRelative == -1 {
|
||||
nextSectionRelative = len(text[afterHeader:])
|
||||
}
|
||||
nextSectionStart := afterHeader + nextSectionRelative
|
||||
unreleasedBody := strings.TrimLeft(text[afterHeader:nextSectionStart], "\n")
|
||||
|
||||
newSection := fmt.Sprintf("## [%s] - %s\n", version, releaseDate)
|
||||
if strings.TrimSpace(unreleasedBody) != "" {
|
||||
newSection += "\n" + unreleasedBody
|
||||
if !strings.HasSuffix(newSection, "\n") {
|
||||
newSection += "\n"
|
||||
}
|
||||
}
|
||||
|
||||
updated := text[:afterHeader] + "\n" + newSection + text[nextSectionStart:]
|
||||
if err := os.WriteFile(path, []byte(updated), 0o644); err != nil {
|
||||
return fmt.Errorf("write changelog: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user