Skip to content

Commit 0e3b3f3

Browse files
authored
Use merge base to find original version of transport resources (#135564) (#135728)
Transport version generation relies on finding the original contents of transport resources before they may have been modified by the current branch. Currently it looks directly at the upstream main branch. Yet that means newly generated ids could leave holes if the branch is out of date with upstream main. Instead, this commit now uses the merge base of the branch. The merge base is calculcated against upstream main. This allows generation to be locally consistent with the branch. The generated id may already be used on main, but that will be detected by a merge conflict in the upper bound before merging the PR. Additionally if in the middle of a merge, like with resolveTransportVersionConflict, the MERGE_HEAD is used as the base so that the regenerated ids will be based on the state at the end of the merge.
1 parent c6dec22 commit 0e3b3f3

File tree

5 files changed

+113
-43
lines changed

5 files changed

+113
-43
lines changed

build-tools-internal/src/integTest/groovy/org/elasticsearch/gradle/internal/transport/AbstractTransportVersionFuncTest.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ class AbstractTransportVersionFuncTest extends AbstractGradleFuncTest {
116116
include ':myplugin'
117117
"""
118118
propertiesFile << """
119-
org.elasticsearch.transports.upstreamRef=main
119+
org.elasticsearch.transport.upstreamRef=main
120120
"""
121121
versionPropertiesFile.text = versionPropertiesFile.text.replace("9.1.0", "9.2.0")
122122

build-tools-internal/src/integTest/groovy/org/elasticsearch/gradle/internal/transport/ResolveTransportVersionConflictFuncTest.groovy

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,44 @@ class ResolveTransportVersionConflictFuncTest extends AbstractTransportVersionFu
8787
assertUpperBound("9.1", "new_tv,8012002")
8888
assertUpperBound("8.19", "new_tv,7123002")
8989
}
90+
91+
def "no new transport version is idempotent"() {
92+
when:
93+
def result = runResolveAndValidateTask().build()
94+
95+
then:
96+
assertResolveAndValidateSuccess(result)
97+
assertUpperBound("9.2", "existing_92,8123000")
98+
}
99+
100+
def "upstream changes don't affect merge"() {
101+
given:
102+
// setup main with 2 commits, but we will only merge in the first one
103+
execute("git checkout main")
104+
referableAndReferencedTransportVersion("upstream_new_tv1", "8124000")
105+
transportVersionUpperBound("9.2", "upstream_new_tv1", "8124000")
106+
execute("git add .")
107+
execute("git commit -m update1")
108+
String toMerge = execute("git rev-parse HEAD")
109+
referableAndReferencedTransportVersion("upstream_new_tv2", "8125000")
110+
transportVersionUpperBound("9.2", "upstream_new_tv2", "8125000")
111+
execute("git add .")
112+
execute("git commit -m update2")
113+
execute("git checkout test")
114+
// now commit a conflict on the test branch, a new TV
115+
referableAndReferencedTransportVersion("branch_new_tv", "8124000")
116+
transportVersionUpperBound("9.2", "branch_new_tv", "8124000")
117+
execute("git add .")
118+
execute("git commit -m branch")
119+
// and finally initiate the merge
120+
System.out.println("Merging commit " + toMerge);
121+
execute("git merge " + toMerge, testProjectDir.root, true);
122+
123+
when:
124+
def result = runResolveAndValidateTask().build()
125+
126+
then:
127+
assertResolveAndValidateSuccess(result)
128+
assertUpperBound("9.2", "branch_new_tv,8125000")
129+
}
90130
}

build-tools-internal/src/integTest/groovy/org/elasticsearch/gradle/internal/transport/TransportVersionGenerationFuncTest.groovy

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,4 +496,21 @@ class TransportVersionGenerationFuncTest extends AbstractTransportVersionFuncTes
496496
assertUpperBound("9.2", "new_tv,8124000")
497497
assertReferableDefinition("new_tv", "8124000")
498498
}
499+
500+
def "generation is idempotent on upstream changes"() {
501+
given:
502+
execute("git checkout main")
503+
referableAndReferencedTransportVersion("new_tv", "8124000")
504+
transportVersionUpperBound("9.2", "new_tv", "8124000")
505+
execute("git add .")
506+
execute("git commit -m update")
507+
execute("git checkout test")
508+
509+
when:
510+
def result = runGenerateAndValidateTask().build()
511+
512+
then:
513+
assertGenerateAndValidateSuccess(result)
514+
assertUpperBound("9.2", "existing_92,8123000")
515+
}
499516
}

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/transport/TransportVersionResourcesService.java

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
public abstract class TransportVersionResourcesService implements BuildService<TransportVersionResourcesService.Parameters> {
5959

6060
private static final Logger logger = Logging.getLogger(TransportVersionResourcesService.class);
61+
private static final String UPSTREAM_REMOTE_NAME = "transport-version-resources-upstream";
6162

6263
public interface Parameters extends BuildServiceParameters {
6364
DirectoryProperty getTransportResourcesDirectory();
@@ -80,17 +81,16 @@ record IdAndDefinition(TransportVersionId id, TransportVersionDefinition definit
8081

8182
private final Path transportResourcesDir;
8283
private final Path rootDir;
83-
private final AtomicReference<String> upstreamRefName = new AtomicReference<>();
84+
private final String upstreamRefOverride;
85+
private final AtomicReference<String> baseRefName = new AtomicReference<>();
8486
private final AtomicReference<Set<String>> upstreamResources = new AtomicReference<>(null);
8587
private final AtomicReference<Set<String>> changedResources = new AtomicReference<>(null);
8688

8789
@Inject
8890
public TransportVersionResourcesService(Parameters params) {
8991
this.transportResourcesDir = params.getTransportResourcesDirectory().get().getAsFile().toPath();
9092
this.rootDir = params.getRootDirectory().get().getAsFile().toPath();
91-
if (params.getUpstreamRefOverride().isPresent()) {
92-
upstreamRefName.set(params.getUpstreamRefOverride().get());
93-
}
93+
upstreamRefOverride = params.getUpstreamRefOverride().getOrNull();
9494
}
9595

9696
/**
@@ -258,52 +258,65 @@ private Path getUpperBoundRelativePath(String name) {
258258
return UPPER_BOUNDS_DIR.resolve(name + ".csv");
259259
}
260260

261-
private String getUpstreamRefName() {
262-
if (upstreamRefName.get() == null) {
263-
synchronized (upstreamRefName) {
264-
String remotesOutput = gitCommand("remote").strip();
265-
261+
private String getBaseRefName() {
262+
if (baseRefName.get() == null) {
263+
synchronized (baseRefName) {
266264
String refName;
267-
if (remotesOutput.isEmpty()) {
268-
refName = "main"; // fallback to local main if no remotes, this happens in tests
265+
// the existence of the MERGE_HEAD ref means we are in the middle of a merge, and should use that as our base
266+
String gitDir = gitCommand("rev-parse", "--git-dir").strip();
267+
if (Files.exists(Path.of(gitDir).resolve("MERGE_HEAD"))) {
268+
refName = gitCommand("rev-parse", "--verify", "MERGE_HEAD").strip();
269269
} else {
270-
List<String> remoteNames = List.of(remotesOutput.split("\n"));
271-
String transportVersionRemoteName = "transport-version-resources-upstream";
272-
if (remoteNames.contains(transportVersionRemoteName) == false) {
273-
// our special remote doesn't exist yet, so create it
274-
String upstreamUrl = null;
275-
for (String remoteName : remoteNames) {
276-
String getUrlOutput = gitCommand("remote", "get-url", remoteName).strip();
277-
if (getUrlOutput.startsWith("[email protected]:elastic/")
278-
|| getUrlOutput.startsWith("https://github.com/elastic/")) {
279-
upstreamUrl = getUrlOutput;
280-
}
281-
}
282-
283-
if (upstreamUrl != null) {
284-
gitCommand("remote", "add", transportVersionRemoteName, upstreamUrl);
285-
} else {
286-
throw new RuntimeException("No elastic github remotes found to copy");
287-
}
288-
}
289-
290-
// make sure the remote main ref is up to date
291-
gitCommand("fetch", transportVersionRemoteName, "main");
292-
293-
refName = transportVersionRemoteName + "/main";
270+
String upstreamRef = findUpstreamRef();
271+
refName = gitCommand("merge-base", upstreamRef, "HEAD").strip();
272+
}
273+
274+
baseRefName.set(refName);
275+
}
276+
}
277+
return baseRefName.get();
278+
}
279+
280+
private String findUpstreamRef() {
281+
if (upstreamRefOverride != null) {
282+
return upstreamRefOverride;
283+
}
284+
285+
String remotesOutput = gitCommand("remote").strip();
286+
if (remotesOutput.isEmpty()) {
287+
throw new RuntimeException(
288+
"No remotes found. If this is a test set gradle property " + "org.elasticsearch.transport.upstreamRef"
289+
);
290+
}
291+
List<String> remoteNames = List.of(remotesOutput.split("\n"));
292+
if (remoteNames.contains(UPSTREAM_REMOTE_NAME) == false) {
293+
// our special remote doesn't exist yet, so create it
294+
String upstreamUrl = null;
295+
for (String remoteName : remoteNames) {
296+
String getUrlOutput = gitCommand("remote", "get-url", remoteName).strip();
297+
if (getUrlOutput.startsWith("[email protected]:elastic/") || getUrlOutput.startsWith("https://github.com/elastic/")) {
298+
upstreamUrl = getUrlOutput;
294299
}
295-
upstreamRefName.set(refName);
300+
}
296301

302+
if (upstreamUrl != null) {
303+
gitCommand("remote", "add", UPSTREAM_REMOTE_NAME, upstreamUrl);
304+
} else {
305+
throw new RuntimeException("No elastic github remotes found to copy");
297306
}
298307
}
299-
return upstreamRefName.get();
308+
309+
// make sure the remote main ref is up to date
310+
gitCommand("fetch", UPSTREAM_REMOTE_NAME, "main");
311+
312+
return UPSTREAM_REMOTE_NAME + "/main";
300313
}
301314

302315
// Return the transport version resources paths that exist in upstream
303316
private Set<String> getUpstreamResources() {
304317
if (upstreamResources.get() == null) {
305318
synchronized (upstreamResources) {
306-
String output = gitCommand("ls-tree", "--name-only", "-r", getUpstreamRefName(), ".");
319+
String output = gitCommand("ls-tree", "--name-only", "-r", getBaseRefName(), ".");
307320

308321
HashSet<String> resources = new HashSet<>();
309322
Collections.addAll(resources, output.split("\n")); // git always outputs LF
@@ -319,7 +332,7 @@ private Set<String> getChangedResources() {
319332
synchronized (changedResources) {
320333
HashSet<String> resources = new HashSet<>();
321334

322-
String diffOutput = gitCommand("diff", "--name-only", "--relative", getUpstreamRefName(), ".");
335+
String diffOutput = gitCommand("diff", "--name-only", "--relative", getBaseRefName(), ".");
323336
if (diffOutput.strip().isEmpty() == false) {
324337
Collections.addAll(resources, diffOutput.split("\n")); // git always outputs LF
325338
}
@@ -357,7 +370,7 @@ private <T> T getUpstreamFile(Path resourcePath, BiFunction<Path, String, T> par
357370
return null;
358371
}
359372

360-
String content = gitCommand("show", getUpstreamRefName() + ":./" + pathString).strip();
373+
String content = gitCommand("show", getBaseRefName() + ":./" + pathString).strip();
361374
return parser.apply(resourcePath, content);
362375
}
363376

build-tools/src/testFixtures/groovy/org/elasticsearch/gradle/fixtures/AbstractGradleFuncTest.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,10 @@ abstract class AbstractGradleFuncTest extends Specification {
211211
"""
212212
}
213213

214-
String execute(String command, File workingDir = testProjectDir.root) {
214+
String execute(String command, File workingDir = testProjectDir.root, boolean ignoreFailure = false) {
215215
def proc = command.execute(Collections.emptyList(), workingDir)
216216
proc.waitFor()
217-
if (proc.exitValue()) {
217+
if (proc.exitValue() && ignoreFailure == false) {
218218
String msg = """Error running command ${command}:
219219
Sysout: ${proc.inputStream.text}
220220
Syserr: ${proc.errorStream.text}

0 commit comments

Comments
 (0)