Skip to content

Commit 558b454

Browse files
tvernumjasontedor
andauthored
Fix version logic when bumping major version (#38595)
When we are preparing to release a major version the rules around "unreleased" versions and branches get a bit more complex. This change implements the following rules: - If the tip version on the previous major is a .0 (e.g. 6.7.0) then the tip of the minor before that (e.g. 6.6.1) must be unreleased. (This is because 6.7.0 would be "staged" in preparation for release, but 6.6.1 would be open for bug fixes on the release 6.6.x line) (in VersionCollection & VersionUtils) - The "major.x" branch (if it exists) will always point to the latest minor in that series. Anything that is not the latest minor, must therefore be on a the "major.minor" branch For example, if v7.1.0 exists then the "7.x" branch must be 7.1.0, and 7.0.0 must be on the "7.0" branch (in VersionCollection) - Special logic so that the 7.0.0 build knows that we do not plan to have any 6.x releases after the 6.7 series Backport of: #38593 Partial Backport of: #38513 Co-authored-by: Jason Tedor <[email protected]>
1 parent 5e798c1 commit 558b454

File tree

3 files changed

+110
-21
lines changed

3 files changed

+110
-21
lines changed

buildSrc/src/main/java/org/elasticsearch/gradle/VersionCollection.java

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -171,30 +171,38 @@ public UnreleasedVersionInfo unreleasedInfo(Version version) {
171171
}
172172

173173
public void forPreviousUnreleased(Consumer<UnreleasedVersionInfo> consumer) {
174-
getUnreleased().stream()
174+
List<UnreleasedVersionInfo> collect = getUnreleased().stream()
175175
.filter(version -> version.equals(currentVersion) == false)
176-
.forEach(version -> consumer.accept(
177-
new UnreleasedVersionInfo(
176+
.map(version -> new UnreleasedVersionInfo(
178177
version,
179178
getBranchFor(version),
180179
getGradleProjectNameFor(version)
181180
)
182-
));
181+
)
182+
.collect(Collectors.toList());
183+
184+
collect.forEach(uvi -> consumer.accept(uvi));
183185
}
184186

185187
private String getGradleProjectNameFor(Version version) {
186188
if (version.equals(currentVersion)) {
187189
throw new IllegalArgumentException("The Gradle project to build " + version + " is the current build.");
188190
}
191+
189192
Map<Integer, List<Version>> releasedMajorGroupedByMinor = getReleasedMajorGroupedByMinor();
190193

191194
if (version.getRevision() == 0) {
192-
if (releasedMajorGroupedByMinor
193-
.get(releasedMajorGroupedByMinor.keySet().stream().max(Integer::compareTo).orElse(0))
194-
.contains(version)) {
195-
return "minor";
195+
List<Version> unreleasedStagedOrMinor = getUnreleased().stream()
196+
.filter(v -> v.getRevision() == 0)
197+
.collect(Collectors.toList());
198+
if (unreleasedStagedOrMinor.size() > 2) {
199+
if (unreleasedStagedOrMinor.get(unreleasedStagedOrMinor.size() - 2).equals(version)) {
200+
return "minor";
201+
} else{
202+
return "staged";
203+
}
196204
} else {
197-
return "staged";
205+
return "minor";
198206
}
199207
} else {
200208
if (releasedMajorGroupedByMinor
@@ -210,7 +218,14 @@ private String getGradleProjectNameFor(Version version) {
210218
private String getBranchFor(Version version) {
211219
switch (getGradleProjectNameFor(version)) {
212220
case "minor":
213-
return version.getMajor() + ".x";
221+
// The .x branch will always point to the latest minor (for that major), so a "minor" project will be on the .x branch
222+
// unless there is more recent (higher) minor.
223+
final Version latestInMajor = getLatestVersionByKey(groupByMajor, version.getMajor());
224+
if (latestInMajor.getMinor() == version.getMinor() && isFinalMinor(version) == false) {
225+
return version.getMajor() + ".x";
226+
} else {
227+
return version.getMajor() + "." + version.getMinor();
228+
}
214229
case "staged":
215230
case "maintenance":
216231
case "bugfix":
@@ -220,13 +235,30 @@ private String getBranchFor(Version version) {
220235
}
221236
}
222237

238+
/**
239+
* There is no way to infer that 6.7 is the final minor release in the 6.x series until we add a 7.0.1 or 7.1.0 version.
240+
* Based on the available versions (7.0.0, 6.7.0, 6.6.1, 6.6.0) the logical conclusion is that 7.0.0 is "master" and 6.7.0 is "6.x"
241+
* This method force 6.7.0 to be recognised as being on the "6.7" branch
242+
*/
243+
private boolean isFinalMinor(Version version) {
244+
return (version.getMajor() == 6 && version.getMinor() == 7);
245+
}
246+
223247
public List<Version> getUnreleased() {
224248
List<Version> unreleased = new ArrayList<>();
225249
// The current version is being worked, is always unreleased
226250
unreleased.add(currentVersion);
227251

228252
// the tip of the previous major is unreleased for sure, be it a minor or a bugfix
229-
unreleased.add(getLatestVersionByKey(this.groupByMajor, currentVersion.getMajor() - 1));
253+
final Version latestOfPreviousMajor = getLatestVersionByKey(this.groupByMajor, currentVersion.getMajor() - 1);
254+
unreleased.add(latestOfPreviousMajor);
255+
if (latestOfPreviousMajor.getRevision() == 0) {
256+
// if the previous major is a x.y.0 release, then the tip of the minor before that (y-1) is also unreleased
257+
final Version previousMinor = getLatestInMinor(latestOfPreviousMajor.getMajor(), latestOfPreviousMajor.getMinor() - 1);
258+
if (previousMinor != null) {
259+
unreleased.add(previousMinor);
260+
}
261+
}
230262

231263
final Map<Integer, List<Version>> groupByMinor = getReleasedMajorGroupedByMinor();
232264
int greatestMinor = groupByMinor.keySet().stream().max(Integer::compareTo).orElse(0);
@@ -239,8 +271,10 @@ public List<Version> getUnreleased() {
239271
unreleased.add(getLatestVersionByKey(groupByMinor, greatestMinor - 1));
240272
if (groupByMinor.getOrDefault(greatestMinor - 1, emptyList()).size() == 1) {
241273
// we found that the previous minor is staged but not yet released
242-
// in this case, the minor before that has a bugfix
243-
unreleased.add(getLatestVersionByKey(groupByMinor, greatestMinor - 2));
274+
// in this case, the minor before that has a bugfix, should there be such a minor
275+
if (greatestMinor >= 2) {
276+
unreleased.add(getLatestVersionByKey(groupByMinor, greatestMinor - 2));
277+
}
244278
}
245279
}
246280

@@ -252,6 +286,13 @@ public List<Version> getUnreleased() {
252286
);
253287
}
254288

289+
private Version getLatestInMinor(int major, int minor) {
290+
return groupByMajor.get(major).stream()
291+
.filter(v -> v.getMinor() == minor)
292+
.max(Version::compareTo)
293+
.orElse(null);
294+
}
295+
255296
private Version getLatestVersionByKey(Map<Integer, List<Version>> groupByMajor, int key) {
256297
return groupByMajor.getOrDefault(key, emptyList()).stream()
257298
.max(Version::compareTo)

buildSrc/src/test/java/org/elasticsearch/gradle/VersionCollectionTests.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ public class VersionCollectionTests extends GradleUnitTestCase {
8181
"6_0_0", "6_0_1", "6_1_0", "6_1_1", "6_1_2", "6_1_3", "6_1_4", "6_2_0", "6_2_1", "6_2_2", "6_2_3",
8282
"6_2_4", "6_3_0", "6_3_1", "6_3_2", "6_4_0", "6_4_1", "6_4_2"
8383
));
84+
sampleVersions.put("7.0.0", asList(
85+
"7_0_0", "6_7_0", "6_6_2", "6_6_1", "6_6_0"
86+
));
87+
sampleVersions.put("7.1.0", asList(
88+
"7_1_0", "7_0_0", "6_7_0", "6_6_1", "6_6_0"
89+
));
8490
}
8591

8692
@Test(expected = IllegalArgumentException.class)
@@ -145,6 +151,11 @@ public void testWireCompatible() {
145151
singletonList("7.3.0"),
146152
getVersionCollection("8.0.0").getWireCompatible()
147153
);
154+
assertVersionsEquals(
155+
asList("6.7.0", "7.0.0"),
156+
getVersionCollection("7.1.0").getWireCompatible()
157+
);
158+
148159
}
149160

150161
public void testWireCompatibleUnreleased() {
@@ -171,6 +182,10 @@ public void testWireCompatibleUnreleased() {
171182
singletonList("7.3.0"),
172183
getVersionCollection("8.0.0").getUnreleasedWireCompatible()
173184
);
185+
assertVersionsEquals(
186+
asList("6.7.0", "7.0.0"),
187+
getVersionCollection("7.1.0").getWireCompatible()
188+
);
174189
}
175190

176191
public void testIndexCompatible() {
@@ -270,6 +285,14 @@ public void testGetUnreleased() {
270285
asList("7.1.1", "7.2.0", "7.3.0", "8.0.0"),
271286
getVersionCollection("8.0.0").getUnreleased()
272287
);
288+
assertVersionsEquals(
289+
asList("6.6.1", "6.7.0", "7.0.0", "7.1.0"),
290+
getVersionCollection("7.1.0").getUnreleased()
291+
);
292+
assertVersionsEquals(
293+
asList("6.6.2", "6.7.0", "7.0.0"),
294+
getVersionCollection("7.0.0").getUnreleased()
295+
);
273296
}
274297

275298
public void testGetBranch() {
@@ -293,6 +316,14 @@ public void testGetBranch() {
293316
asList("7.1", "7.2", "7.x"),
294317
getVersionCollection("8.0.0")
295318
);
319+
assertUnreleasedBranchNames(
320+
asList("6.6", "6.7", "7.0"),
321+
getVersionCollection("7.1.0")
322+
);
323+
assertUnreleasedBranchNames(
324+
asList("6.6", "6.7"),
325+
getVersionCollection("7.0.0")
326+
);
296327
}
297328

298329
public void testGetGradleProjectName() {
@@ -309,13 +340,17 @@ public void testGetGradleProjectName() {
309340
getVersionCollection("6.4.2")
310341
);
311342
assertUnreleasedGradleProjectNames(
312-
asList("maintenance", "bugfix", "staged"),
343+
asList("maintenance", "bugfix", "minor"),
313344
getVersionCollection("6.6.0")
314345
);
315346
assertUnreleasedGradleProjectNames(
316347
asList("bugfix", "staged", "minor"),
317348
getVersionCollection("8.0.0")
318349
);
350+
assertUnreleasedGradleProjectNames(
351+
asList("maintenance", "staged", "minor"),
352+
getVersionCollection("7.1.0")
353+
);
319354
}
320355

321356
public void testCompareToAuthoritative() {

test/framework/src/main/java/org/elasticsearch/test/VersionUtils.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class VersionUtils {
4343
* rules here match up with the rules in gradle then this should
4444
* produce sensible results.
4545
* @return a tuple containing versions with backwards compatibility
46-
* guarantees in v1 and versions without the guranteees in v2
46+
* guarantees in v1 and versions without the guarantees in v2
4747
*/
4848
static Tuple<List<Version>, List<Version>> resolveReleasedVersions(Version current, Class<?> versionClass) {
4949
// group versions into major version
@@ -52,7 +52,7 @@ static Tuple<List<Version>, List<Version>> resolveReleasedVersions(Version curre
5252
// this breaks b/c 5.x is still in version list but master doesn't care about it!
5353
//assert majorVersions.size() == 2;
5454
// TODO: remove oldVersions, we should only ever have 2 majors in Version
55-
List<Version> oldVersions = majorVersions.getOrDefault((int)current.major - 2, Collections.emptyList());
55+
List<List<Version>> oldVersions = splitByMinor(majorVersions.getOrDefault((int)current.major - 2, Collections.emptyList()));
5656
List<List<Version>> previousMajor = splitByMinor(majorVersions.get((int)current.major - 1));
5757
List<List<Version>> currentMajor = splitByMinor(majorVersions.get((int)current.major));
5858

@@ -67,7 +67,11 @@ static Tuple<List<Version>, List<Version>> resolveReleasedVersions(Version curre
6767
// on a stable or release branch, ie N.x
6868
stableVersions = currentMajor;
6969
// remove the next maintenance bugfix
70-
moveLastToUnreleased(previousMajor, unreleasedVersions);
70+
final Version prevMajorLastMinor = moveLastToUnreleased(previousMajor, unreleasedVersions);
71+
if (prevMajorLastMinor.revision == 0 && previousMajor.isEmpty() == false) {
72+
// The latest minor in the previous major is a ".0" release, so there must be an unreleased bugfix for the minor before that
73+
moveLastToUnreleased(previousMajor, unreleasedVersions);
74+
}
7175
}
7276

7377
// remove next minor
@@ -78,12 +82,21 @@ static Tuple<List<Version>, List<Version>> resolveReleasedVersions(Version curre
7882
moveLastToUnreleased(stableVersions, unreleasedVersions);
7983
}
8084
// remove the next bugfix
81-
moveLastToUnreleased(stableVersions, unreleasedVersions);
85+
if (stableVersions.isEmpty() == false) {
86+
moveLastToUnreleased(stableVersions, unreleasedVersions);
87+
}
8288
}
8389

84-
List<Version> releasedVersions = Stream.concat(oldVersions.stream(),
85-
Stream.concat(previousMajor.stream(), currentMajor.stream()).flatMap(List::stream))
86-
.collect(Collectors.toList());
90+
// If none of the previous major was released, then the last minor and bugfix of the old version was not released either.
91+
if (previousMajor.isEmpty()) {
92+
assert currentMajor.isEmpty() : currentMajor;
93+
// minor of the old version is being staged
94+
moveLastToUnreleased(oldVersions, unreleasedVersions);
95+
// bugix of the old version is also being staged
96+
moveLastToUnreleased(oldVersions, unreleasedVersions);
97+
}
98+
List<Version> releasedVersions = Stream.of(oldVersions, previousMajor, currentMajor)
99+
.flatMap(List::stream).flatMap(List::stream).collect(Collectors.toList());
87100
Collections.sort(unreleasedVersions); // we add unreleased out of order, so need to sort here
88101
return new Tuple<>(Collections.unmodifiableList(releasedVersions), Collections.unmodifiableList(unreleasedVersions));
89102
}

0 commit comments

Comments
 (0)