mirror of
https://github.com/lukaszraczylo/semver-generator.git
synced 2026-06-05 22:49:25 +00:00
Fix ignoring strict.force and strict.commit.
This commit is contained in:
@@ -1,16 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/lukaszraczylo/semver-generator/cmd/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
// These functions are now in the utils package
|
|
||||||
// They are kept here as stubs for backward compatibility
|
|
||||||
|
|
||||||
func updatePackage() bool {
|
|
||||||
return utils.UpdatePackage()
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkLatestRelease() (string, bool) {
|
|
||||||
return utils.CheckLatestRelease()
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/lukaszraczylo/semver-generator/cmd/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_checkLatestRelease(t *testing.T) {
|
|
||||||
utils.InitLogger(true)
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
want string
|
|
||||||
want1 bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Check latest release",
|
|
||||||
want1: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
_, got1 := checkLatestRelease()
|
|
||||||
if got1 != tt.want1 {
|
|
||||||
t.Errorf("checkLatestRelease() got1 = %v, want %v", got1, tt.want1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_updatePackage(t *testing.T) {
|
|
||||||
utils.InitLogger(true)
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip("Skipping test in short / CI mode")
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Run autoupdater",
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if got := updatePackage(); got != tt.want {
|
|
||||||
t.Errorf("updatePackage() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+9
-2
@@ -135,18 +135,25 @@ func ListCommits(repo *GitRepository) ([]CommitDetails, error) {
|
|||||||
|
|
||||||
Debug("Listing commits", map[string]interface{}{"commits": tmpResults})
|
Debug("Listing commits", map[string]interface{}{"commits": tmpResults})
|
||||||
|
|
||||||
// Filter commits starting from the specified commit if provided
|
// Filter commits starting after the specified commit if provided
|
||||||
if repo.StartCommit != "" {
|
if repo.StartCommit != "" {
|
||||||
|
found := false
|
||||||
for commitId, cmt := range tmpResults {
|
for commitId, cmt := range tmpResults {
|
||||||
if cmt.Hash == repo.StartCommit {
|
if cmt.Hash == repo.StartCommit {
|
||||||
Debug("Found commit match", map[string]interface{}{
|
Debug("Found commit match", map[string]interface{}{
|
||||||
"commit": cmt.Hash,
|
"commit": cmt.Hash,
|
||||||
"index": commitId,
|
"index": commitId,
|
||||||
})
|
})
|
||||||
repo.Commits = tmpResults[commitId:]
|
// Start from the commit AFTER the specified one
|
||||||
|
repo.Commits = tmpResults[commitId+1:]
|
||||||
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !found {
|
||||||
|
// If specified commit not found, use all commits
|
||||||
|
repo.Commits = tmpResults
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
repo.Commits = tmpResults
|
repo.Commits = tmpResults
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,14 +34,6 @@ type ReleaseAsset struct {
|
|||||||
BrowserDownloadURL string `json:"browser_download_url"`
|
BrowserDownloadURL string `json:"browser_download_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateInfo contains information about an available update
|
|
||||||
type UpdateInfo struct {
|
|
||||||
CurrentVersion string
|
|
||||||
LatestVersion string
|
|
||||||
ReleaseURL string
|
|
||||||
DownloadURL string
|
|
||||||
}
|
|
||||||
|
|
||||||
// httpClient is the HTTP client used for requests (allows mocking in tests)
|
// httpClient is the HTTP client used for requests (allows mocking in tests)
|
||||||
var httpClient = &http.Client{
|
var httpClient = &http.Client{
|
||||||
Timeout: requestTimeout,
|
Timeout: requestTimeout,
|
||||||
@@ -60,30 +52,6 @@ func CheckLatestRelease() (string, bool) {
|
|||||||
return version, true
|
return version, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckForUpdate checks if a newer version is available
|
|
||||||
// Returns UpdateInfo if an update is available, nil otherwise
|
|
||||||
func CheckForUpdate(currentVersion string) *UpdateInfo {
|
|
||||||
release, err := fetchLatestRelease(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
latestVersion := normalizeVersion(release.TagName)
|
|
||||||
current := normalizeVersion(currentVersion)
|
|
||||||
|
|
||||||
if isNewerVersion(latestVersion, current) {
|
|
||||||
downloadURL := findBinaryAsset(release.Assets)
|
|
||||||
return &UpdateInfo{
|
|
||||||
CurrentVersion: current,
|
|
||||||
LatestVersion: latestVersion,
|
|
||||||
ReleaseURL: release.HTMLURL,
|
|
||||||
DownloadURL: downloadURL,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdatePackage downloads and installs the latest version
|
// UpdatePackage downloads and installs the latest version
|
||||||
func UpdatePackage() bool {
|
func UpdatePackage() bool {
|
||||||
Info("Checking for updates", nil)
|
Info("Checking for updates", nil)
|
||||||
@@ -389,49 +357,3 @@ func normalizeVersion(v string) string {
|
|||||||
v = strings.TrimPrefix(v, "V")
|
v = strings.TrimPrefix(v, "V")
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// isNewerVersion compares two semver-like versions
|
|
||||||
// Returns true if latest is newer than current
|
|
||||||
func isNewerVersion(latest, current string) bool {
|
|
||||||
latestParts := parseVersionParts(latest)
|
|
||||||
currentParts := parseVersionParts(current)
|
|
||||||
|
|
||||||
for i := 0; i < len(latestParts) && i < len(currentParts); i++ {
|
|
||||||
if latestParts[i] > currentParts[i] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if latestParts[i] < currentParts[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return len(latestParts) > len(currentParts)
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseVersionParts splits a version string into numeric parts
|
|
||||||
func parseVersionParts(v string) []int {
|
|
||||||
// Remove any suffix like -beta, -rc1, etc.
|
|
||||||
if idx := strings.IndexAny(v, "-+"); idx != -1 {
|
|
||||||
v = v[:idx]
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(v, ".")
|
|
||||||
result := make([]int, 0, len(parts))
|
|
||||||
|
|
||||||
for _, p := range parts {
|
|
||||||
var num int
|
|
||||||
if _, err := fmt.Sscanf(p, "%d", &num); err != nil {
|
|
||||||
// If parsing fails, use 0 for this part
|
|
||||||
num = 0
|
|
||||||
}
|
|
||||||
result = append(result, num)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatUpdateMessage formats a user-friendly update notification
|
|
||||||
func (u *UpdateInfo) FormatUpdateMessage() string {
|
|
||||||
return fmt.Sprintf("New version available: %s (current: %s) - %s",
|
|
||||||
u.LatestVersion, u.CurrentVersion, u.ReleaseURL)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -30,57 +30,6 @@ func TestNormalizeVersion(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseVersionParts(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
input string
|
|
||||||
expected []int
|
|
||||||
}{
|
|
||||||
{"1.0.0", []int{1, 0, 0}},
|
|
||||||
{"2.1.3", []int{2, 1, 3}},
|
|
||||||
{"1.0", []int{1, 0}},
|
|
||||||
{"10.20.30", []int{10, 20, 30}},
|
|
||||||
{"1.0.0-beta", []int{1, 0, 0}},
|
|
||||||
{"1.0.0-rc1", []int{1, 0, 0}},
|
|
||||||
{"1.0.0+build123", []int{1, 0, 0}},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.input, func(t *testing.T) {
|
|
||||||
result := parseVersionParts(tt.input)
|
|
||||||
assert.Equal(t, tt.expected, result)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsNewerVersion(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
latest string
|
|
||||||
current string
|
|
||||||
expected bool
|
|
||||||
}{
|
|
||||||
{"major version bump", "2.0.0", "1.0.0", true},
|
|
||||||
{"minor version bump", "1.1.0", "1.0.0", true},
|
|
||||||
{"patch version bump", "1.0.1", "1.0.0", true},
|
|
||||||
{"same version", "1.0.0", "1.0.0", false},
|
|
||||||
{"current is newer major", "1.0.0", "2.0.0", false},
|
|
||||||
{"current is newer minor", "1.0.0", "1.1.0", false},
|
|
||||||
{"current is newer patch", "1.0.0", "1.0.1", false},
|
|
||||||
{"multi-digit versions", "1.10.0", "1.9.0", true},
|
|
||||||
{"longer version is newer", "1.0.1", "1.0", true},
|
|
||||||
{"shorter version is older", "1.0", "1.0.1", false},
|
|
||||||
{"complex comparison", "2.1.3", "2.1.2", true},
|
|
||||||
{"real world example", "0.2.0", "0.1.0", true},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
result := isNewerVersion(tt.latest, tt.current)
|
|
||||||
assert.Equal(t, tt.expected, result)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFindBinaryAsset(t *testing.T) {
|
func TestFindBinaryAsset(t *testing.T) {
|
||||||
assets := []ReleaseAsset{
|
assets := []ReleaseAsset{
|
||||||
{Name: "semver-gen-1.0.0-linux-amd64.tar.gz", BrowserDownloadURL: "https://example.com/linux-amd64.tar.gz"},
|
{Name: "semver-gen-1.0.0-linux-amd64.tar.gz", BrowserDownloadURL: "https://example.com/linux-amd64.tar.gz"},
|
||||||
@@ -102,19 +51,6 @@ func TestFindBinaryAssetEmpty(t *testing.T) {
|
|||||||
assert.Empty(t, url, "Should return empty string when no assets")
|
assert.Empty(t, url, "Should return empty string when no assets")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateInfo_FormatUpdateMessage(t *testing.T) {
|
|
||||||
info := &UpdateInfo{
|
|
||||||
CurrentVersion: "1.0.0",
|
|
||||||
LatestVersion: "2.0.0",
|
|
||||||
ReleaseURL: "https://github.com/lukaszraczylo/semver-generator/releases/tag/v2.0.0",
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := info.FormatUpdateMessage()
|
|
||||||
assert.Contains(t, msg, "2.0.0")
|
|
||||||
assert.Contains(t, msg, "1.0.0")
|
|
||||||
assert.Contains(t, msg, "https://github.com/lukaszraczylo/semver-generator/releases/tag/v2.0.0")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCheckLatestRelease(t *testing.T) {
|
func TestCheckLatestRelease(t *testing.T) {
|
||||||
// Initialize logger
|
// Initialize logger
|
||||||
InitLogger(false)
|
InitLogger(false)
|
||||||
@@ -141,22 +77,6 @@ func TestCheckLatestRelease(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckForUpdate(t *testing.T) {
|
|
||||||
InitLogger(false)
|
|
||||||
|
|
||||||
// Test with a very old version - should show update available if network works
|
|
||||||
info := CheckForUpdate("0.0.1")
|
|
||||||
// This will either return update info or nil depending on network
|
|
||||||
if info != nil {
|
|
||||||
assert.NotEmpty(t, info.LatestVersion)
|
|
||||||
assert.Equal(t, "0.0.1", info.CurrentVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test with a very new version - should not show update
|
|
||||||
info = CheckForUpdate("999.999.999")
|
|
||||||
assert.Nil(t, info, "Should not show update for future version")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFetchLatestReleaseError(t *testing.T) {
|
func TestFetchLatestReleaseError(t *testing.T) {
|
||||||
InitLogger(false)
|
InitLogger(false)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInitLogger(t *testing.T) {
|
func TestInitLogger(t *testing.T) {
|
||||||
// Test with debug mode enabled
|
// Test with debug mode enabled
|
||||||
logger := InitLogger(true)
|
logger := InitLogger(true)
|
||||||
|
|||||||
+26
-11
@@ -16,22 +16,37 @@ func CalculateSemver(
|
|||||||
tagPrefixes []string,
|
tagPrefixes []string,
|
||||||
) SemVer {
|
) SemVer {
|
||||||
semver := initialSemver
|
semver := initialSemver
|
||||||
|
startIndex := 0
|
||||||
|
|
||||||
for _, commit := range commits {
|
// If respecting existing tags, find the latest tagged commit and start from there
|
||||||
// Check for existing tags if enabled
|
if respectExisting && len(tags) > 0 {
|
||||||
if respectExisting {
|
latestTagIndex := -1
|
||||||
for _, tagHash := range tags {
|
var latestTagName string
|
||||||
if commit.Hash == tagHash.Hash {
|
|
||||||
Debug("Found existing tag", map[string]interface{}{
|
// Find the latest tagged commit (highest index since commits are oldest-first)
|
||||||
"tag": tagHash.Name,
|
for i, commit := range commits {
|
||||||
"commit": strings.TrimSuffix(commit.Message, "\n"),
|
for _, tag := range tags {
|
||||||
})
|
if commit.Hash == tag.Hash {
|
||||||
semver = ParseExistingSemver(tagHash.Name, semver, tagPrefixes)
|
if i > latestTagIndex {
|
||||||
continue
|
latestTagIndex = i
|
||||||
|
latestTagName = tag.Name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we found a tagged commit, use its version and start processing after it
|
||||||
|
if latestTagIndex >= 0 {
|
||||||
|
Debug("Found latest existing tag", map[string]interface{}{
|
||||||
|
"tag": latestTagName,
|
||||||
|
"commit": strings.TrimSuffix(commits[latestTagIndex].Message, "\n"),
|
||||||
|
})
|
||||||
|
semver = ParseExistingSemver(latestTagName, semver, tagPrefixes)
|
||||||
|
startIndex = latestTagIndex + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, commit := range commits[startIndex:] {
|
||||||
// In non-strict mode, increment patch by default
|
// In non-strict mode, increment patch by default
|
||||||
if !strictMode {
|
if !strictMode {
|
||||||
semver.Patch++
|
semver.Patch++
|
||||||
|
|||||||
Reference in New Issue
Block a user