mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-20 13:44:31 +00:00
chore: deprecate cherry-picking on release (#186)
## Why this should be merged Our old strategy of only cherry-picking on release branches made the `main` branch incompatible with dependent repos. ## How this works The goal of the old strategy was to avoid cherry-picking on the same branch to which we would later merge the duplicated, upstream commit. This can instead be achieved by tracking the cherry-picked commits and reverting them as part of the geth sync. Since we already do this for our own changes and a single cherry-pick (see #128), there's no need to use the two approaches simultaneously. This PR deletes the cherry-picking mechanism and removes the release-branch test that enforced its proper usage. It will be followed up by a series of PRs, one per cherry-pick that would have otherwise been placed on release branches. ## How this was tested n/a
This commit is contained in:
parent
7b6ff3e0ff
commit
fd03f3ac29
4 changed files with 4 additions and 210 deletions
|
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2025 the libevm authors.
|
||||
#
|
||||
# The libevm additions to go-ethereum are free software: you can redistribute
|
||||
# them and/or modify them under the terms of the GNU Lesser General Public License
|
||||
# as published by the Free Software Foundation, either version 3 of the License,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# The libevm additions are distributed in the hope that they will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with the go-ethereum library. If not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Usage: run `./cherrypick.sh` on a branch intended to become a release.
|
||||
#
|
||||
# Reads the contents of ./cherrypicks, filters out commits that are already
|
||||
# ancestors of HEAD, and calls `git cherry-pick` with the remaining commit
|
||||
# hashes.
|
||||
|
||||
set -eu;
|
||||
set -o pipefail;
|
||||
|
||||
SELF_DIR=$(dirname "${0}")
|
||||
# The format of the `cherrypicks` file is guaranteed by a test so we can use simple parsing here.
|
||||
CHERRY_PICKS=$(< "${SELF_DIR}/cherrypicks" grep -Ev "^#" | awk '{print $1}')
|
||||
|
||||
commits=()
|
||||
for commit in ${CHERRY_PICKS}; do
|
||||
git merge-base --is-ancestor "${commit}" HEAD && \
|
||||
echo "Skipping ${commit} already in history" && \
|
||||
continue;
|
||||
|
||||
echo "Cherry-picking ${commit}";
|
||||
commits+=("${commit}");
|
||||
done
|
||||
|
||||
if [[ -z "${commits[*]// }" ]]; then # $x// removes whitespace
|
||||
echo "No commits to cherry-pick";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
git cherry-pick -S "${commits[@]}";
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
# Lines starting with # are ignored as comments.
|
||||
# All other lines MUST have the format [<commit> # <first line of commit message>].
|
||||
# Commits MUST be in chronological order.
|
||||
# A test in release_test.go will enforce this / provide the correct lines to copy and paste.
|
||||
#
|
||||
# The very first commit is where libevm branched off geth and is included to confirm that it is skipped.
|
||||
#
|
||||
2bd6bd01d2e8561dd7fc21b631f4a34ac16627a1 # Merge branch 'master' into release/1.13
|
||||
99bbbc0277e34fc3a31512a345ba20874ae98e18 # internal/build, rpc: add missing HTTP response body Close() calls (#29223)
|
||||
1e9bf2a09ed3d82ac1aa69750a556f3ce127721d # core/state: fix bug in statedb.Copy and remove unnecessary preallocation (#29563)
|
||||
69f815f6f5791e0e48160bdad284773d0ffb1ba9 # params: print time value instead of pointer in ConfigCompatError (#29514)
|
||||
e4b8058d5a5832cdebdac7da385cf6d829c0d433 # eth/gasprice: add query limit for FeeHistory to defend DDOS attack (#29644)
|
||||
34b46a2f756da71595ac84eb7f25441f2a5b6ebb # core/state/snapshot: add a missing lock (#30001)
|
||||
159fb1a1db551c544978dc16a5568a4730b4abf3 # crypto: add IsOnCurve check (#31100)
|
||||
da71839a270a353bac92e3108e4b74fb0eefec29 # internal/ethapi: fix panic in debug methods (#31157)
|
||||
|
|
@ -22,23 +22,17 @@ 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) {
|
||||
|
|
@ -46,76 +40,6 @@ func TestMain(m *testing.M) {
|
|||
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/"
|
||||
|
|
@ -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.
|
||||
|
|
@ -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),
|
||||
|
|
@ -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]
|
||||
}
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in a new issue