diff --git a/dependency_updater/dependency_updater.go b/dependency_updater/dependency_updater.go index e2c547a3..56204d77 100644 --- a/dependency_updater/dependency_updater.go +++ b/dependency_updater/dependency_updater.go @@ -185,9 +185,10 @@ func getVersionAndCommit(ctx context.Context, client *github.Client, dependencie currentTag := dependencies[dependencyType].Tag tagPrefix := dependencies[dependencyType].TagPrefix - if dependencies[dependencyType].Tracking == "tag" { + if dependencies[dependencyType].Tracking == "tag" || dependencies[dependencyType].Tracking == "release" { // Collect all valid tags across all pages, then find the max version var validTags []*github.RepositoryTag + trackingMode := dependencies[dependencyType].Tracking for { tags, resp, err := client.Repositories.ListTags( @@ -206,6 +207,19 @@ func getVersionAndCommit(ctx context.Context, client *github.Client, dependencie continue } + // Filter based on tracking mode: + // - "release": only stable releases (no prerelease suffix) + // - "tag": releases and RC versions only (exclude -synctest, -alpha, etc.) + if trackingMode == "release" { + if !IsReleaseVersion(*tag.Name, tagPrefix) { + continue + } + } else if trackingMode == "tag" { + if !IsReleaseOrRCVersion(*tag.Name, tagPrefix) { + continue + } + } + // Check if this is a valid upgrade (not a downgrade) if err := ValidateVersionUpgrade(currentTag, *tag.Name, tagPrefix); err != nil { continue diff --git a/dependency_updater/version.go b/dependency_updater/version.go index 0c1dbbe2..31a0a56e 100644 --- a/dependency_updater/version.go +++ b/dependency_updater/version.go @@ -11,6 +11,9 @@ import ( // rcPattern matches various RC formats: -rc1, -rc.1, -rc-1, -RC1, etc. var rcPattern = regexp.MustCompile(`(?i)-rc[.-]?(\d+)`) +// rcOnlyPattern is used to check if a version contains ONLY an RC prerelease (not -synctest, -alpha, etc.) +var rcOnlyPattern = regexp.MustCompile(`(?i)^-rc[.-]?\d+$`) + // ParseVersion extracts and normalizes a semantic version from a tag string. // It handles tagPrefix stripping, v-prefix normalization, and RC format normalization. func ParseVersion(tag string, tagPrefix string) (*semver.Version, error) { @@ -90,3 +93,44 @@ func CompareVersions(v1Tag, v2Tag, tagPrefix string) (int, error) { } return v1.Compare(v2), nil } + +// IsReleaseVersion returns true if the tag is a stable release (no prerelease suffix). +// Examples: +// - "v1.0.0" -> true +// - "v1.0.0-rc1" -> false +// - "v1.0.0-synctest.0" -> false +func IsReleaseVersion(tag string, tagPrefix string) bool { + v, err := ParseVersion(tag, tagPrefix) + if err != nil { + return false + } + return v.Prerelease() == "" +} + +// IsRCVersion returns true if the tag is a release candidate version. +// This matches versions with -rc, -rc.N, -rc-N, -rcN suffixes. +// Examples: +// - "v1.0.0-rc1" -> true +// - "v1.0.0-rc.2" -> true +// - "v1.0.0" -> false (stable release, not RC) +// - "v1.0.0-synctest.0" -> false (not an RC) +// - "v1.0.0-alpha" -> false (not an RC) +func IsRCVersion(tag string, tagPrefix string) bool { + v, err := ParseVersion(tag, tagPrefix) + if err != nil { + return false + } + prerelease := v.Prerelease() + if prerelease == "" { + return false + } + // Check if the prerelease is ONLY an RC format (e.g., "rc.1", "rc1", "rc-1") + // We need to check the original format before normalization + return rcOnlyPattern.MatchString("-" + prerelease) +} + +// IsReleaseOrRCVersion returns true if the tag is either a stable release or an RC version. +// This excludes other prereleases like -alpha, -beta, -synctest, etc. +func IsReleaseOrRCVersion(tag string, tagPrefix string) bool { + return IsReleaseVersion(tag, tagPrefix) || IsRCVersion(tag, tagPrefix) +} diff --git a/dependency_updater/version_test.go b/dependency_updater/version_test.go index bc1944f4..3413cb4a 100644 --- a/dependency_updater/version_test.go +++ b/dependency_updater/version_test.go @@ -152,6 +152,124 @@ func TestCompareVersions(t *testing.T) { } } +func TestIsReleaseVersion(t *testing.T) { + tests := []struct { + tag string + tagPrefix string + want bool + }{ + // Stable releases + {"v1.0.0", "", true}, + {"v0.2.2", "", true}, + {"1.35.3", "", true}, // nethermind style + {"v1.101603.5", "", true}, // op-geth style + + // With prefix + {"op-node/v1.16.2", "op-node", true}, + + // Pre-release versions (should return false) + {"v1.0.0-rc1", "", false}, + {"v1.0.0-rc.1", "", false}, + {"v1.0.0-rc-1", "", false}, + {"v1.0.0-synctest.0", "", false}, + {"v1.0.0-alpha", "", false}, + {"v1.0.0-beta.1", "", false}, + {"op-node/v1.16.6-synctest.0", "op-node", false}, + {"op-node/v1.16.3-rc1", "op-node", false}, + + // Invalid versions (should return false) + {"not-a-version", "", false}, + {"", "", false}, + } + + for _, tt := range tests { + t.Run(tt.tag, func(t *testing.T) { + got := IsReleaseVersion(tt.tag, tt.tagPrefix) + if got != tt.want { + t.Errorf("IsReleaseVersion(%q, %q) = %v, want %v", tt.tag, tt.tagPrefix, got, tt.want) + } + }) + } +} + +func TestIsRCVersion(t *testing.T) { + tests := []struct { + tag string + tagPrefix string + want bool + }{ + // RC versions + {"v1.0.0-rc1", "", true}, + {"v1.0.0-rc.1", "", true}, + {"v1.0.0-rc-1", "", true}, + {"v1.0.0-RC1", "", true}, + {"v1.0.0-rc12", "", true}, + {"op-node/v1.16.3-rc1", "op-node", true}, + {"op-node/v1.16.3-rc.2", "op-node", true}, + + // Stable releases (not RC) + {"v1.0.0", "", false}, + {"v0.2.2", "", false}, + {"op-node/v1.16.2", "op-node", false}, + + // Other pre-release versions (not RC) + {"v1.0.0-synctest.0", "", false}, + {"op-node/v1.16.6-synctest.0", "op-node", false}, + {"v1.0.0-alpha", "", false}, + {"v1.0.0-beta.1", "", false}, + {"v1.0.0-alpha.rc1", "", false}, // rc is part of another prerelease + + // Invalid versions + {"not-a-version", "", false}, + {"", "", false}, + } + + for _, tt := range tests { + t.Run(tt.tag, func(t *testing.T) { + got := IsRCVersion(tt.tag, tt.tagPrefix) + if got != tt.want { + t.Errorf("IsRCVersion(%q, %q) = %v, want %v", tt.tag, tt.tagPrefix, got, tt.want) + } + }) + } +} + +func TestIsReleaseOrRCVersion(t *testing.T) { + tests := []struct { + tag string + tagPrefix string + want bool + }{ + // Stable releases - should pass + {"v1.0.0", "", true}, + {"v0.2.2", "", true}, + {"op-node/v1.16.2", "op-node", true}, + + // RC versions - should pass + {"v1.0.0-rc1", "", true}, + {"v1.0.0-rc.1", "", true}, + {"op-node/v1.16.3-rc1", "op-node", true}, + + // Other pre-release versions - should NOT pass + {"v1.0.0-synctest.0", "", false}, + {"op-node/v1.16.6-synctest.0", "op-node", false}, + {"v1.0.0-alpha", "", false}, + {"v1.0.0-beta.1", "", false}, + + // Invalid versions + {"not-a-version", "", false}, + } + + for _, tt := range tests { + t.Run(tt.tag, func(t *testing.T) { + got := IsReleaseOrRCVersion(tt.tag, tt.tagPrefix) + if got != tt.want { + t.Errorf("IsReleaseOrRCVersion(%q, %q) = %v, want %v", tt.tag, tt.tagPrefix, got, tt.want) + } + }) + } +} + func TestRCVersionOrdering(t *testing.T) { // Verify that RC versions are ordered correctly versions := []string{ diff --git a/versions.env b/versions.env index 966dcc08..535b158e 100644 --- a/versions.env +++ b/versions.env @@ -1,6 +1,6 @@ -export BASE_RETH_NODE_COMMIT=4a580faec0b560eb65d6ee2f620efb7b044a649d +export BASE_RETH_NODE_COMMIT=bb1b4571bebb8a9cd8ff1ec8758001fdc32758e8 export BASE_RETH_NODE_REPO=https://github.com/base/base.git -export BASE_RETH_NODE_TAG=v0.2.2 +export BASE_RETH_NODE_TAG=v0.3.0 export NETHERMIND_COMMIT=d9febbce240491e8f918d41a4ffd06385a746b6c export NETHERMIND_REPO=https://github.com/NethermindEth/nethermind.git export NETHERMIND_TAG=1.35.3 diff --git a/versions.json b/versions.json index 555afa2d..82698cbf 100644 --- a/versions.json +++ b/versions.json @@ -1,24 +1,24 @@ { "base_reth_node": { - "tag": "v0.2.2", - "commit": "4a580faec0b560eb65d6ee2f620efb7b044a649d", + "tag": "v0.3.0", + "commit": "bb1b4571bebb8a9cd8ff1ec8758001fdc32758e8", "owner": "base", "repo": "base", - "tracking": "tag" + "tracking": "release" }, "nethermind": { "tag": "1.35.3", "commit": "d9febbce240491e8f918d41a4ffd06385a746b6c", "owner": "NethermindEth", "repo": "nethermind", - "tracking": "tag" + "tracking": "release" }, "op_geth": { "tag": "v1.101603.5", "commit": "904a088c5cc1eeec21a1ffa47327dc20a809e642", "owner": "ethereum-optimism", "repo": "op-geth", - "tracking": "tag" + "tracking": "release" }, "op_node": { "tag": "op-node/v1.16.2", @@ -26,13 +26,13 @@ "tagPrefix": "op-node", "owner": "ethereum-optimism", "repo": "optimism", - "tracking": "tag" + "tracking": "release" }, "op_reth": { "tag": "v1.9.3", "commit": "27a8c0f5a6dfb27dea84c5751776ecabdd069646", "owner": "paradigmxyz", "repo": "reth", - "tracking": "tag" + "tracking": "release" } } \ No newline at end of file