StarterSetCreatePublishMojo.java
/*
* Copyright © 2026 IKE Network (support@ike.network)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package network.ike.plugin;
import org.apache.maven.api.Session;
import org.apache.maven.api.di.Inject;
import org.apache.maven.api.plugin.MojoException;
import org.apache.maven.api.plugin.annotations.Mojo;
import org.apache.maven.api.plugin.annotations.Parameter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* Genesis of a new starter-set project — the executing half of the
* {@code ike:starter-set-create-*} pair (IKE-Network/ike-issues#866): mints the set's
* permanent identity (unless supplied), materializes the five-module family from the
* standards templates, bootstrap-commits, and proves itself by building the generated
* project green before reporting success.
*
* <p>Run {@code ike:starter-set-create-draft} first — publish executes exactly what
* the draft showed. Genesis runs once: the target directory must not already exist.
*
* @since 235
*/
@Mojo(name = IkeGoal.NAME_STARTER_SET_CREATE_PUBLISH, projectRequired = false)
public class StarterSetCreatePublishMojo extends StarterSetCreateParameters
implements org.apache.maven.api.plugin.Mojo {
/** Creates this goal instance. */
public StarterSetCreatePublishMojo() {}
@Inject
private org.apache.maven.api.plugin.Log log;
@Inject
private Session session;
/**
* Skip the post-generation verification build (offline use); the generated
* project must then be built manually before first use.
*/
@Parameter(property = "skipVerify", defaultValue = "false")
boolean skipVerify;
/**
* Mints, materializes, commits, and verifies the new starter-set project.
*
* @throws MojoException if the target exists, templates cannot be loaded, files
* cannot be written, or the verification build fails
*/
@Override
public void execute() {
StarterSetPlan plan = plan(UUID.randomUUID().toString(), log, session);
Map<String, String> templates = StarterSetCreateSupport.loadTemplates(session);
Path target = targetDirectory(plan);
if (Files.exists(target)) {
throw new MojoException("Genesis runs once — the target already exists: " + target
+ ". Conformance of existing projects is the scaffold system's job.");
}
List<String> written = new ArrayList<>();
try {
for (Map.Entry<String, String> template : templates.entrySet()) {
String relative = plan.targetPath(template.getKey());
Path file = target.resolve(relative);
Files.createDirectories(file.getParent());
Files.writeString(file, plan.expand(template.getValue()), StandardCharsets.UTF_8);
written.add(relative);
}
} catch (IOException e) {
throw new MojoException("Cannot materialize the starter-set project at " + target, e);
}
run(target, "git", "init", "-q", "-b", "main");
List<String> add = new ArrayList<>(List.of("git", "add"));
add.addAll(written);
run(target, add.toArray(new String[0]));
run(target, "git", "commit", "-q", "-m",
"Genesis of " + plan.token("artifactRoot") + " (" + plan.token("setName") + ")\n\n"
+ "Generated by ike:starter-set-create-publish. Set identity (permanent):\n"
+ plan.token("setUuid")
+ "\n\nRefs: IKE-Network/ike-issues#866");
if (skipVerify) {
log.warn("Verification build skipped (-DskipVerify) — build the project before first use.");
} else {
log.info("Verifying the generated project (mvn test) ...");
run(target, Path.of(System.getProperty("maven.home"), "bin", "mvn").toString(),
"test", "-q");
log.info("Verification build green.");
}
for (String line : StarterSetCreateSupport
.report(plan, templates, target, false).split("\n")) {
log.info(line);
}
log.info("");
log.info("SET IDENTITY MINTED (permanent, recorded in " + plan.token("className")
+ ".java): " + plan.token("setUuid"));
}
private void run(Path directory, String... command) {
try {
Process process = new ProcessBuilder(command)
.directory(directory.toFile())
.redirectErrorStream(true)
.start();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
String line = reader.readLine();
while (line != null) {
log.info("[create] " + line);
line = reader.readLine();
}
}
int exit = process.waitFor();
if (exit != 0) {
throw new MojoException("Genesis step failed (exit " + exit + "): "
+ String.join(" ", command));
}
} catch (IOException e) {
throw new MojoException("Cannot run genesis step: " + String.join(" ", command), e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new MojoException("Interrupted during genesis step", e);
}
}
}