Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion libevm/tooling/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ replace github.com/ava-labs/libevm => ../../
require (
github.com/ava-labs/libevm v0.0.0-00010101000000-000000000000
github.com/go-git/go-git/v5 v5.14.0
github.com/google/go-cmp v0.7.0
github.com/stretchr/testify v1.10.0
)

Expand Down
47 changes: 0 additions & 47 deletions libevm/tooling/release/cherrypick.sh

This file was deleted.

15 changes: 0 additions & 15 deletions libevm/tooling/release/cherrypicks

This file was deleted.

151 changes: 4 additions & 147 deletions libevm/tooling/release/release_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,100 +22,24 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"
"slices"
"sort"
"strings"
"testing"
"time"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/ava-labs/libevm/params"

_ "embed"
)

func TestMain(m *testing.M) {
flag.Parse()
os.Exit(m.Run())
}

var (
//go:embed cherrypicks
cherryPicks string
lineFormatRE = regexp.MustCompile(`^([a-fA-F0-9]{40}) # (.*)$`)
)

type parsedLine struct {
hash, commitMsg string
}

func parseCherryPicks(t *testing.T) (rawLines []string, lines []parsedLine) {
t.Helper()
for i, line := range strings.Split(cherryPicks, "\n") {
if line == "" || strings.HasPrefix(line, "#") {
continue
}

switch matches := lineFormatRE.FindStringSubmatch(line); len(matches) {
case 3:
rawLines = append(rawLines, line)
lines = append(lines, parsedLine{
hash: matches[1],
commitMsg: matches[2],
})

default:
t.Errorf("Line %d is improperly formatted: %s", i, line)
}
}
return rawLines, lines
}

func TestCherryPicksFormat(t *testing.T) {
rawLines, lines := parseCherryPicks(t)
if t.Failed() {
t.Fatalf("Required line regexp: %s", lineFormatRE.String())
}

commits := make([]struct {
obj *object.Commit
line parsedLine
}, len(lines))

repo := openGitRepo(t)
for i, line := range lines {
obj, err := repo.CommitObject(plumbing.NewHash(line.hash))
require.NoErrorf(t, err, "%T.CommitObject(%q)", repo, line.hash)

commits[i].obj = obj
commits[i].line = line
}
sort.Slice(commits, func(i, j int) bool {
ci, cj := commits[i].obj, commits[j].obj
return ci.Committer.When.Before(cj.Committer.When)
})

var want []string
for _, c := range commits {
msg := strings.Split(c.obj.Message, "\n")[0]
want = append(
want,
fmt.Sprintf("%s # %s", c.line.hash, msg),
)
}
if diff := cmp.Diff(want, rawLines); diff != "" {
t.Errorf("Commits in `cherrypicks` file out of order or have incorrect commit message(s);\n(-want +got):\n%s", diff)
t.Logf("To fix, copy:\n%s", strings.Join(want, "\n"))
}
}

const (
defaultBranch = "main"
releaseBranchPrefix = "release/"
Expand Down Expand Up @@ -149,20 +73,8 @@ func TestBranchProperties(t *testing.T) {
// 1. They are named release/v${libevm-version};
// 2. The libevm version's [params.ReleaseType] is appropriate for a release
// branch; and
// 3. The commit history is a "linear fork" off the default branch, with only
// certain allowable commits.
//
// We define a "linear fork" as there being a single ancestral commit at which
// the release branch diverged from the default branch, with no merge commits
// after this divergence:
//
// ______________ main
// \___ release/*
//
// The commits in the release branch that are not in the default branch MUST be:
//
// 1. The cherry-pick commits embedded as [cherryPicks], in order; then
// 2. A single, final commit to change the libevm version.
// 3. The commit history since the default branch is only a single commit, to
// change the version.
//
// testReleaseBranch assumes that the git HEAD currently points at either
// `targetBranch` itself, or at a candidate (i.e. PR source) for said branch.
Expand Down Expand Up @@ -199,27 +111,10 @@ func testReleaseBranch(t *testing.T, targetBranch string) {
newCommits := linearCommitsSince(t, history, fork)
logCommits(t, "History since fork from default branch", newCommits)

t.Run("cherry_picked_commits", func(t *testing.T) {
_, cherryPick := parseCherryPicks(t)
wantCommits := commitsFromHashes(t, repo, cherryPick, fork)
logCommits(t, "Expected cherry-picks", wantCommits)
if got, want := len(newCommits), len(wantCommits)+1; got != want {
t.Fatalf("Got %d commits since fork from default; want number to be cherry-picked plus one (%d)", got, want)
}

opt := compareCherryPickedCommits()
if diff := cmp.Diff(wantCommits, newCommits[:len(wantCommits)], opt); diff != "" {
t.Fatalf("Cherry-picked commits for release branch (-want +got):\n%s", diff)
}
})

t.Run("final_commit", func(t *testing.T) {
n := len(newCommits)
last := newCommits[n-1]
require.Len(t, newCommits, 1, "Single commit off default branch")
last := newCommits[0]
penultimate := fork
if n >= 2 {
penultimate = newCommits[n-2]
}

lastCommitDiffs, err := object.DiffTree(
treeFromCommit(t, last),
Expand Down Expand Up @@ -293,25 +188,6 @@ func linearCommitsSince(t *testing.T, iter object.CommitIter, since *object.Comm
return commits
}

func commitsFromHashes(t *testing.T, repo *git.Repository, lines []parsedLine, skipAncestorsOf *object.Commit) []*object.Commit {
t.Helper()

var commits []*object.Commit
for _, l := range lines {
c, err := repo.CommitObject(plumbing.NewHash(l.hash))
require.NoError(t, err)

skip, err := c.IsAncestor(skipAncestorsOf)
require.NoError(t, err)
if skip || c.Hash == skipAncestorsOf.Hash {
continue
}
commits = append(commits, c)
}

return commits
}

func commitMsgFirstLine(c *object.Commit) string {
return strings.Split(c.Message, "\n")[0]
}
Expand All @@ -323,25 +199,6 @@ func logCommits(t *testing.T, header string, commits []*object.Commit) {
}
}

// compareCherryPickedCommits returns a [cmp.Transformer] that converts
// [object.Commit] instances into structs carrying only the pertinent commit
// properties that remain stable when cherry-picked. Note, however, that this
// does not include the actual diffs induced by cherry-picking.
func compareCherryPickedCommits() cmp.Option {
type comparableCommit struct {
MessageFirstLine, Author string
Authored time.Time
}

return cmp.Transformer("gitCommit", func(c *object.Commit) comparableCommit {
return comparableCommit{
MessageFirstLine: commitMsgFirstLine(c),
Author: c.Author.String(),
Authored: c.Author.When,
}
})
}

func treeFromCommit(t *testing.T, c *object.Commit) *object.Tree {
t.Helper()
tree, err := c.Tree()
Expand Down