Add release tooling for adding new transport versions (#122426) (#122447)

This commit is contained in:
Mark Vieira 2025-02-12 17:15:00 -08:00 committed by GitHub
parent df04756a24
commit ed0ca6a966
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 184 additions and 2 deletions

View file

@ -15,6 +15,7 @@ import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;
import com.google.common.annotations.VisibleForTesting;
@ -33,6 +34,7 @@ import java.util.NavigableMap;
import java.util.Objects;
import java.util.Optional;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@ -51,6 +53,8 @@ public class UpdateVersionsTask extends AbstractVersionsTask {
private boolean setCurrent;
@Nullable
private Version removeVersion;
@Nullable
private String addTransportVersion;
@Inject
public UpdateVersionsTask(BuildLayout layout) {
@ -62,6 +66,11 @@ public class UpdateVersionsTask extends AbstractVersionsTask {
this.addVersion = Version.fromString(version);
}
@Option(option = "add-transport-version", description = "Specifies transport version to add")
public void addTransportVersion(String transportVersion) {
this.addTransportVersion = transportVersion;
}
@Option(option = "set-current", description = "Set the 'current' constant to the new version")
public void setCurrent(boolean setCurrent) {
this.setCurrent = setCurrent;
@ -87,15 +96,18 @@ public class UpdateVersionsTask extends AbstractVersionsTask {
@TaskAction
public void executeTask() throws IOException {
if (addVersion == null && removeVersion == null) {
if (addVersion == null && removeVersion == null && addTransportVersion == null) {
throw new IllegalArgumentException("No versions to add or remove specified");
}
if (setCurrent && addVersion == null) {
throw new IllegalArgumentException("No new version added to set as the current version");
}
if (Objects.equals(addVersion, removeVersion)) {
if (addVersion != null && removeVersion != null && Objects.equals(addVersion, removeVersion)) {
throw new IllegalArgumentException("Same version specified to add and remove");
}
if (addTransportVersion != null && addTransportVersion.split(":").length != 2) {
throw new IllegalArgumentException("Transport version specified must be in the format '<constant>:<version-id>'");
}
Path versionJava = rootDir.resolve(VERSION_FILE_PATH);
CompilationUnit file = LexicalPreservingPrinter.setup(StaticJavaParser.parse(versionJava));
@ -115,6 +127,18 @@ public class UpdateVersionsTask extends AbstractVersionsTask {
modifiedFile = removed;
}
}
if (addTransportVersion != null) {
var constant = addTransportVersion.split(":")[0];
var versionId = Integer.parseInt(addTransportVersion.split(":")[1]);
LOGGER.lifecycle("Adding transport version constant [{}] with id [{}]", constant, versionId);
var transportVersionsFile = rootDir.resolve(TRANSPORT_VERSIONS_FILE_PATH);
var transportVersions = LexicalPreservingPrinter.setup(StaticJavaParser.parse(transportVersionsFile));
var modified = addTransportVersionConstant(transportVersions, constant, versionId);
if (modified.isPresent()) {
writeOutNewContents(transportVersionsFile, modified.get());
}
}
if (modifiedFile.isPresent()) {
writeOutNewContents(versionJava, modifiedFile.get());
@ -161,6 +185,51 @@ public class UpdateVersionsTask extends AbstractVersionsTask {
return Optional.of(versionJava);
}
@VisibleForTesting
static Optional<CompilationUnit> addTransportVersionConstant(CompilationUnit transportVersions, String constant, int versionId) {
ClassOrInterfaceDeclaration transportVersionsClass = transportVersions.getClassByName("TransportVersions").get();
if (transportVersionsClass.getFieldByName(constant).isPresent()) {
LOGGER.lifecycle("New transport version constant [{}] already present, skipping", constant);
return Optional.empty();
}
TreeMap<Integer, FieldDeclaration> versions = transportVersionsClass.getFields()
.stream()
.filter(f -> f.getElementType().asString().equals("TransportVersion"))
.filter(
f -> f.getVariables().stream().limit(1).allMatch(v -> v.getInitializer().filter(Expression::isMethodCallExpr).isPresent())
)
.filter(f -> f.getVariable(0).getInitializer().get().asMethodCallExpr().getNameAsString().endsWith("def"))
.collect(
Collectors.toMap(
f -> f.getVariable(0)
.getInitializer()
.get()
.asMethodCallExpr()
.getArgument(0)
.asIntegerLiteralExpr()
.asNumber()
.intValue(),
Function.identity(),
(f1, f2) -> {
throw new IllegalStateException("Duplicate version constant " + f1);
},
TreeMap::new
)
);
// find the version this should be inserted after
Map.Entry<Integer, FieldDeclaration> previousVersion = versions.lowerEntry(versionId);
if (previousVersion == null) {
throw new IllegalStateException(String.format("Could not find previous version to [%s]", versionId));
}
FieldDeclaration newTransportVersion = createNewTransportVersionConstant(previousVersion.getValue(), constant, versionId);
transportVersionsClass.getMembers().addAfter(newTransportVersion, previousVersion.getValue());
return Optional.of(transportVersions);
}
private static FieldDeclaration createNewVersionConstant(FieldDeclaration lastVersion, String newName, String newExpr) {
return new FieldDeclaration(
new NodeList<>(lastVersion.getModifiers()),
@ -172,6 +241,29 @@ public class UpdateVersionsTask extends AbstractVersionsTask {
);
}
private static FieldDeclaration createNewTransportVersionConstant(FieldDeclaration lastVersion, String newName, int newId) {
return new FieldDeclaration(
new NodeList<>(lastVersion.getModifiers()),
new VariableDeclarator(
lastVersion.getCommonType(),
newName,
StaticJavaParser.parseExpression(String.format("def(%s)", formatTransportVersionId(newId)))
)
);
}
private static String formatTransportVersionId(int id) {
String idString = Integer.toString(id);
return new StringBuilder(idString.substring(idString.length() - 2, idString.length())).insert(0, "_")
.insert(0, idString.substring(idString.length() - 3, idString.length() - 2))
.insert(0, "_")
.insert(0, idString.substring(idString.length() - 6, idString.length() - 3))
.insert(0, "_")
.insert(0, idString.substring(0, idString.length() - 6))
.toString();
}
@VisibleForTesting
static Optional<CompilationUnit> removeVersionConstant(CompilationUnit versionJava, Version version) {
String removeFieldName = toVersionField(version);

View file

@ -239,6 +239,96 @@ public class UpdateVersionsTaskTests {
assertThat(field.isPresent(), is(false));
}
@Test
public void addTransportVersion() throws Exception {
var transportVersions = """
public class TransportVersions {
public static final TransportVersion V_1_0_0 = def(1_000_0_00);
public static final TransportVersion V_1_1_0 = def(1_001_0_00);
public static final TransportVersion V_1_2_0 = def(1_002_0_00);
public static final TransportVersion V_1_2_1 = def(1_002_0_01);
public static final TransportVersion V_1_2_2 = def(1_002_0_02);
public static final TransportVersion SOME_OTHER_VERSION = def(1_003_0_00);
public static final TransportVersion YET_ANOTHER_VERSION = def(1_004_0_00);
public static final TransportVersion MINIMUM_COMPATIBLE = V_1_0_0;
}
""";
var expectedTransportVersions = """
public class TransportVersions {
public static final TransportVersion V_1_0_0 = def(1_000_0_00);
public static final TransportVersion V_1_1_0 = def(1_001_0_00);
public static final TransportVersion V_1_2_0 = def(1_002_0_00);
public static final TransportVersion V_1_2_1 = def(1_002_0_01);
public static final TransportVersion V_1_2_2 = def(1_002_0_02);
public static final TransportVersion SOME_OTHER_VERSION = def(1_003_0_00);
public static final TransportVersion YET_ANOTHER_VERSION = def(1_004_0_00);
public static final TransportVersion NEXT_TRANSPORT_VERSION = def(1_005_0_00);
public static final TransportVersion MINIMUM_COMPATIBLE = V_1_0_0;
}
""";
var unit = StaticJavaParser.parse(transportVersions);
var result = UpdateVersionsTask.addTransportVersionConstant(unit, "NEXT_TRANSPORT_VERSION", 1_005_0_00);
assertThat(result.isPresent(), is(true));
assertThat(result.get(), hasToString(expectedTransportVersions));
}
@Test
public void addTransportVersionPatch() throws Exception {
var transportVersions = """
public class TransportVersions {
public static final TransportVersion V_1_0_0 = def(1_000_0_00);
public static final TransportVersion V_1_1_0 = def(1_001_0_00);
public static final TransportVersion V_1_2_0 = def(1_002_0_00);
public static final TransportVersion V_1_2_1 = def(1_002_0_01);
public static final TransportVersion V_1_2_2 = def(1_002_0_02);
public static final TransportVersion SOME_OTHER_VERSION = def(1_003_0_00);
public static final TransportVersion YET_ANOTHER_VERSION = def(1_004_0_00);
public static final TransportVersion MINIMUM_COMPATIBLE = V_1_0_0;
}
""";
var expectedTransportVersions = """
public class TransportVersions {
public static final TransportVersion V_1_0_0 = def(1_000_0_00);
public static final TransportVersion V_1_1_0 = def(1_001_0_00);
public static final TransportVersion V_1_2_0 = def(1_002_0_00);
public static final TransportVersion V_1_2_1 = def(1_002_0_01);
public static final TransportVersion V_1_2_2 = def(1_002_0_02);
public static final TransportVersion SOME_OTHER_VERSION = def(1_003_0_00);
public static final TransportVersion PATCH_TRANSPORT_VERSION = def(1_003_0_01);
public static final TransportVersion YET_ANOTHER_VERSION = def(1_004_0_00);
public static final TransportVersion MINIMUM_COMPATIBLE = V_1_0_0;
}
""";
var unit = StaticJavaParser.parse(transportVersions);
var result = UpdateVersionsTask.addTransportVersionConstant(unit, "PATCH_TRANSPORT_VERSION", 1_003_0_01);
assertThat(result.isPresent(), is(true));
assertThat(result.get(), hasToString(expectedTransportVersions));
}
private static Optional<FieldDeclaration> findFirstField(Node node, String name) {
return node.findFirst(FieldDeclaration.class, f -> f.getVariable(0).getName().getIdentifier().equals(name));
}