
org.infinispan.plugins.proto.compatibility.ProtoCompatibilityMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of proto-schema-compatibility-maven-plugin Show documentation
Show all versions of proto-schema-compatibility-maven-plugin Show documentation
Compares .proto files against the previous version using the Protocol Buffers best practices
to determine whether they maintain backwards-compatibility
package org.infinispan.plugins.proto.compatibility;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.infinispan.protostream.FileDescriptorSource;
import org.infinispan.protostream.config.Configuration;
import org.infinispan.protostream.descriptors.FileDescriptor;
import org.infinispan.protostream.descriptors.ProtoLock;
import org.infinispan.protostream.impl.parser.ProtostreamProtoParser;
/**
* Protocol Buffers compatibility checks using ProtoStream
*
* @author Ryan Emerson
* @since 10.0
*/
@Mojo(
name = "proto-schema-compatibility-check",
defaultPhase = LifecyclePhase.VERIFY,
requiresDependencyResolution = ResolutionScope.COMPILE,
threadSafe = true)
public class ProtoCompatibilityMojo extends AbstractMojo {
@Parameter(defaultValue = "false")
private boolean commitProtoLock;
@Parameter(defaultValue = "${basedir}")
private String protoLockRoot;
@Parameter(defaultValue = "${project.build.directory}/classes/proto", readonly = true)
private String protoSourceRoot;
@Parameter
private String remoteLockFiles;
@Parameter(defaultValue = "${session}")
private MavenSession session;
@Parameter(defaultValue = "false")
private boolean skip;
/**
* Execute the plugin.
*
* @throws MojoExecutionException thrown when execution of protolock fails.
*/
public void execute() throws MojoExecutionException {
try {
if (skip) {
getLog().info("Skipping proto compatibility check");
return;
}
Path lockFile = Paths.get(protoLockRoot, "proto.lock");
boolean lockFileExists = Files.exists(lockFile);
if (!commitProtoLock && !lockFileExists && !remoteCheck()) {
getLog().info("Ignoring protolock check as there isn't an existing proto.lock file, commitProtoLock=false and no remoteLockFiles are specified.");
return;
}
ProtoLock protoNew = protoLockFromDir(Paths.get(protoSourceRoot));
if (lockFileExists) {
ProtoLock protoOld;
try (InputStream is = Files.newInputStream(lockFile)) {
protoOld = ProtoLock.readLockFile(is);
}
protoOld.checkCompatibility(protoNew, true);
getLog().info(String.format("Backwards compatibility check against local file '%s' passed.", lockFile));
}
if (remoteCheck())
checkRemoteCompatibility(protoNew);
if (commitProtoLock) {
try (OutputStream os = Files.newOutputStream(lockFile)) {
protoNew.writeLockFile(os);
}
getLog().info(
lockFileExists ?
"Schema changes committed to proto.lock." :
"Initialized protolock."
);
}
} catch (IOException e) {
throw new MojoExecutionException("An error occurred while running protolock", e);
}
}
private ProtoLock protoLockFromDir(Path protoRoot) throws IOException {
List protoFiles;
try (Stream stream = Files.walk(protoRoot)) {
protoFiles = stream.filter(p -> p.getFileName().toString().endsWith(".proto")).toList();
}
FileDescriptorSource fds = new FileDescriptorSource();
for (Path p : protoFiles) {
fds.addProtoFile(protoRoot.relativize(p).toString(), p.toFile());
}
ProtostreamProtoParser parser = new ProtostreamProtoParser(Configuration.builder().build());
Map descriptors = parser.parse(fds);
return new ProtoLock(descriptors.values());
}
private void checkRemoteCompatibility(ProtoLock currentState) throws IOException {
if (session.isOffline()) {
getLog().info("Skipping backwards compatibility check against remote files as maven is in Offline mode");
return;
}
for (String file : remoteLockFiles.split(",")) {
getLog().info(String.format("Checking backwards compatibility check against remote file '%s'", file));
try (InputStream is = new URL(file).openStream()) {
ProtoLock remoteLockFile = ProtoLock.readLockFile(is);
remoteLockFile.checkCompatibility(currentState, true);
}
getLog().info(String.format("Backwards compatibility check against remote file '%s' passed", file));
}
}
private boolean remoteCheck() {
return remoteLockFiles != null && !remoteLockFiles.isEmpty();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy