CentralStageMojo.java
package network.ike.plugin;
import network.ike.plugin.release.central.CentralStaging;
import org.apache.maven.api.di.Inject;
import org.apache.maven.api.plugin.Log;
import org.apache.maven.api.plugin.Mojo;
import org.apache.maven.api.plugin.MojoException;
import org.apache.maven.api.plugin.annotations.Parameter;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Finalize a Maven Central staging directory: prune the Maven 4
* {@code -build.pom} artifacts, swap generated BOMs over their staged
* stub POMs, re-sign, and verify (IKE-Network/ike-issues#853,
* IKE-Network/ike-issues#966).
*
* <p>Invoked by the async Central deploy sentinel script
* (IKE-Network/ike-issues#484) between its signed staging deploy and
* the JReleaser upload — always as a fully pinned
* {@code groupId:artifactId:version:central-stage} matching the plugin
* that rendered the script, never through the build's own plugin pin,
* which may lag one release behind (#966). The sync deploy path runs
* the same {@link CentralStaging} logic in-process without this goal.
*
* <p>Usage (as rendered into the sentinel script):
* <pre>
* mvn -N -B network.ike.tooling:ike-maven-plugin:242:central-stage \
* -Dike.central.buildRoot=/path/to/worktree \
* -Dike.central.stagingDir=/path/to/worktree/target/staging-deploy
* </pre>
*
* <p>Fails (non-zero) when a swapped POM does not verify, so the
* sentinel script treats it as a retry-eligible cycle failure — a
* stub can no longer reach Central silently.
*/
@org.apache.maven.api.plugin.annotations.Mojo(
name = IkeGoal.NAME_CENTRAL_STAGE, projectRequired = false)
public class CentralStageMojo implements Mojo {
/** Maven logger, injected by the plugin runtime. */
@Inject
Log log;
/** @return the injected Maven logger */
Log getLog() { return log; }
/**
* The build root that produced the staged artifacts — the release
* worktree. Walked for {@code target/generated-bom.xml} outputs
* and must contain the {@code mvnw} wrapper used for the re-sign
* deploy.
*/
@Parameter(property = "ike.central.buildRoot", required = true)
String buildRoot;
/**
* The {@code staging-deploy} directory produced by the signed
* staging deploy — the bundle JReleaser uploads.
*/
@Parameter(property = "ike.central.stagingDir", required = true)
String stagingDir;
/** Creates this goal instance. */
public CentralStageMojo() {}
@Override
public void execute() {
Path root = requireDirectory(buildRoot, "ike.central.buildRoot");
Path staging = requireDirectory(stagingDir, "ike.central.stagingDir");
File mvnw = root.resolve("mvnw").toFile();
if (!mvnw.isFile()) {
throw new MojoException("No mvnw wrapper at " + mvnw
+ " — central-stage re-signs swapped BOMs through "
+ "the build root's own Maven wrapper");
}
CentralStaging.pruneBuildPoms(getLog(), staging);
CentralStaging.swapGeneratedBoms(getLog(), root.toFile(), mvnw,
staging);
}
/**
* Resolves a required directory parameter, failing with the
* property name when it is absent or not a directory.
*
* @param value the configured parameter value
* @param property the property name for the failure message
* @return the resolved directory path
* @throws MojoException when the value is not an existing directory
*/
static Path requireDirectory(String value, String property) {
Path p = Paths.get(value);
if (!Files.isDirectory(p)) {
throw new MojoException(property + "=" + value
+ " is not an existing directory");
}
return p;
}
}