Skip to content

Commit e164060

Browse files
committed
Use merge base to find original version of transport resources
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 c6d1ede commit e164060

File tree

5 files changed

+104
-43
lines changed

5 files changed

+104
-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: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,35 @@ class ResolveTransportVersionConflictFuncTest extends AbstractTransportVersionFu
9696
assertResolveAndValidateSuccess(result)
9797
assertUpperBound("9.2", "existing_92,8123000")
9898
}
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+
}
99130
}

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
@@ -504,4 +504,21 @@ class TransportVersionGenerationFuncTest extends AbstractTransportVersionFuncTes
504504
assertUpperBound("9.2", "new_tv,8124000")
505505
assertReferableDefinition("new_tv", "8124000")
506506
}
507+
508+
def "generation is idempotent on upstream changes"() {
509+
given:
510+
execute("git checkout main")
511+
referableAndReferencedTransportVersion("new_tv", "8124000")
512+
transportVersionUpperBound("9.2", "new_tv", "8124000")
513+
execute("git add .")
514+
execute("git commit -m update")
515+
execute("git checkout test")
516+
517+
when:
518+
def result = runGenerateAndValidateTask().build()
519+
520+
then:
521+
assertGenerateAndValidateSuccess(result)
522+
assertUpperBound("9.2", "existing_92,8123000")
523+
}
507524
}

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
@@ -76,17 +76,16 @@ public interface Parameters extends BuildServiceParameters {
7676

7777
private final Path transportResourcesDir;
7878
private final Path rootDir;
79-
private final AtomicReference<String> upstreamRefName = new AtomicReference<>();
79+
private final String upstreamRefOverride;
80+
private final AtomicReference<String> baseRefName = new AtomicReference<>();
8081
private final AtomicReference<Set<String>> upstreamResources = new AtomicReference<>(null);
8182
private final AtomicReference<Set<String>> changedResources = new AtomicReference<>(null);
8283

8384
@Inject
8485
public TransportVersionResourcesService(Parameters params) {
8586
this.transportResourcesDir = params.getTransportResourcesDirectory().get().getAsFile().toPath();
8687
this.rootDir = params.getRootDirectory().get().getAsFile().toPath();
87-
if (params.getUpstreamRefOverride().isPresent()) {
88-
upstreamRefName.set(params.getUpstreamRefOverride().get());
89-
}
88+
upstreamRefOverride = params.getUpstreamRefOverride().getOrNull();
9089
}
9190

9291
/**
@@ -240,52 +239,66 @@ private Path getUpperBoundRelativePath(String name) {
240239
return UPPER_BOUNDS_DIR.resolve(name + ".csv");
241240
}
242241

243-
private String getUpstreamRefName() {
244-
if (upstreamRefName.get() == null) {
245-
synchronized (upstreamRefName) {
246-
String remotesOutput = gitCommand("remote").strip();
247-
242+
private String getBaseRefName() {
243+
if (baseRefName.get() == null) {
244+
synchronized (baseRefName) {
248245
String refName;
249-
if (remotesOutput.isEmpty()) {
250-
refName = "main"; // fallback to local main if no remotes, this happens in tests
246+
// the existence of the MERGE_HEAD ref means we are in the middle of a merge, and should use that as our base
247+
String gitDir = gitCommand("rev-parse", "--git-dir").strip();
248+
if (Files.exists(Path.of(gitDir).resolve("MERGE_HEAD"))) {
249+
refName = gitCommand("rev-parse", "--verify", "MERGE_HEAD").strip();
251250
} else {
252-
List<String> remoteNames = List.of(remotesOutput.split("\n"));
253-
String transportVersionRemoteName = "transport-version-resources-upstream";
254-
if (remoteNames.contains(transportVersionRemoteName) == false) {
255-
// our special remote doesn't exist yet, so create it
256-
String upstreamUrl = null;
257-
for (String remoteName : remoteNames) {
258-
String getUrlOutput = gitCommand("remote", "get-url", remoteName).strip();
259-
if (getUrlOutput.startsWith("[email protected]:elastic/")
260-
|| getUrlOutput.startsWith("https://github.com/elastic/")) {
261-
upstreamUrl = getUrlOutput;
262-
}
263-
}
264-
265-
if (upstreamUrl != null) {
266-
gitCommand("remote", "add", transportVersionRemoteName, upstreamUrl);
267-
} else {
268-
throw new RuntimeException("No elastic github remotes found to copy");
269-
}
270-
}
271-
272-
// make sure the remote main ref is up to date
273-
gitCommand("fetch", transportVersionRemoteName, "main");
274-
275-
refName = transportVersionRemoteName + "/main";
251+
String upstreamRef = findUpstreamRef();
252+
refName = gitCommand("merge-base", upstreamRef, "HEAD").strip();
253+
}
254+
255+
baseRefName.set(refName);
256+
}
257+
}
258+
return baseRefName.get();
259+
}
260+
261+
private String findUpstreamRef() {
262+
if (upstreamRefOverride != null) {
263+
return upstreamRefOverride;
264+
}
265+
266+
String remotesOutput = gitCommand("remote").strip();
267+
if (remotesOutput.isEmpty()) {
268+
throw new RuntimeException("No remotes found. If this is a test set gradle property " +
269+
"org.elasticsearch.transport.upstreamRef");
270+
}
271+
List<String> remoteNames = List.of(remotesOutput.split("\n"));
272+
String transportVersionRemoteName = "transport-version-resources-upstream";
273+
if (remoteNames.contains(transportVersionRemoteName) == false) {
274+
// our special remote doesn't exist yet, so create it
275+
String upstreamUrl = null;
276+
for (String remoteName : remoteNames) {
277+
String getUrlOutput = gitCommand("remote", "get-url", remoteName).strip();
278+
if (getUrlOutput.startsWith("[email protected]:elastic/")
279+
|| getUrlOutput.startsWith("https://github.com/elastic/")) {
280+
upstreamUrl = getUrlOutput;
276281
}
277-
upstreamRefName.set(refName);
282+
}
278283

284+
if (upstreamUrl != null) {
285+
gitCommand("remote", "add", transportVersionRemoteName, upstreamUrl);
286+
} else {
287+
throw new RuntimeException("No elastic github remotes found to copy");
279288
}
280289
}
281-
return upstreamRefName.get();
290+
291+
// make sure the remote main ref is up to date
292+
gitCommand("fetch", transportVersionRemoteName, "main");
293+
294+
return transportVersionRemoteName + "/main";
282295
}
283296

284297
// Return the transport version resources paths that exist in upstream
285298
private Set<String> getUpstreamResources() {
286299
if (upstreamResources.get() == null) {
287300
synchronized (upstreamResources) {
288-
String output = gitCommand("ls-tree", "--name-only", "-r", getUpstreamRefName(), ".");
301+
String output = gitCommand("ls-tree", "--name-only", "-r", getBaseRefName(), ".");
289302

290303
HashSet<String> resources = new HashSet<>();
291304
Collections.addAll(resources, output.split("\n")); // git always outputs LF
@@ -301,7 +314,7 @@ private Set<String> getChangedResources() {
301314
synchronized (changedResources) {
302315
HashSet<String> resources = new HashSet<>();
303316

304-
String diffOutput = gitCommand("diff", "--name-only", "--relative", getUpstreamRefName(), ".");
317+
String diffOutput = gitCommand("diff", "--name-only", "--relative", getBaseRefName(), ".");
305318
if (diffOutput.strip().isEmpty() == false) {
306319
Collections.addAll(resources, diffOutput.split("\n")); // git always outputs LF
307320
}
@@ -324,7 +337,7 @@ private <T> T getUpstreamFile(Path resourcePath, BiFunction<Path, String, T> par
324337
return null;
325338
}
326339

327-
String content = gitCommand("show", getUpstreamRefName() + ":./" + pathString).strip();
340+
String content = gitCommand("show", getBaseRefName() + ":./" + pathString).strip();
328341
return parser.apply(resourcePath, content);
329342
}
330343

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)