Skip to content

Commit

Permalink
Add release tooling for adding new transport versions (elastic#122426)
Browse files Browse the repository at this point in the history
  • Loading branch information
mark-vieira authored Feb 12, 2025
1 parent 8c0ab4e commit 6c6e8d8
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
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;
Expand All @@ -33,6 +34,7 @@
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;
Expand All @@ -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) {
Expand All @@ -62,6 +66,11 @@ public void addVersion(String version) {
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;
Expand All @@ -87,15 +96,18 @@ static Optional<Version> parseVersionField(CharSequence field) {

@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));
Expand All @@ -115,6 +127,18 @@ public void executeTask() throws IOException {
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());
Expand Down Expand Up @@ -161,6 +185,51 @@ static Optional<CompilationUnit> addVersionConstant(CompilationUnit versionJava,
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()),
Expand All @@ -172,6 +241,29 @@ private static FieldDeclaration createNewVersionConstant(FieldDeclaration lastVe
);
}

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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,96 @@ public void updateVersionFile_removesCorrectly() throws Exception {
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));
}
Expand Down

0 comments on commit 6c6e8d8

Please sign in to comment.