CascadeReporter.java
package network.ike.workspace.cascade;
import java.util.ArrayList;
import java.util.List;
/**
* Formats the cascade-awareness messages that {@code ike:release-draft}
* and {@code ike:release-publish} print (IKE-Network/ike-issues#402,
* #420).
*
* <p>In the decentralized cascade model every project version-controls
* its own {@code src/main/cascade/release-cascade.yaml}, so the
* releasing repo's own {@link ProjectCascade} is all the reporter
* needs — no graph assembly, no sibling checkouts. The {@code downstream}
* edges of that file are exactly the foundation repos a release makes
* stale.
*
* <p>This reporter does not inspect git history: after a foundation
* repo is released, every downstream repo is definitionally stale.
* The point is visibility — the operator cannot finish a single-repo
* release without seeing what the cascade says comes next.
*/
public final class CascadeReporter {
private static final String RULE =
"────────────────────────────────────────────────────────";
private CascadeReporter() {}
/**
* Builds the post-release cascade footer for
* {@code ike:release-publish}.
*
* @param local the releasing project's own parsed manifest
* @param repo the releasing project's repo/directory name
* @return log lines naming the now-stale downstream repos and the
* exact commands to continue the cascade
*/
public static List<String> publishFooter(ProjectCascade local,
String repo) {
List<String> lines = new ArrayList<>();
lines.add(RULE);
lines.add(" Foundation release cascade (release-cascade.yaml)");
lines.add(RULE);
lines.add(" ✓ " + repo + " released.");
if (local.terminal()) {
lines.add(" End of the foundation cascade — no"
+ " downstream foundation repos.");
lines.add(RULE);
return lines;
}
lines.add(" Downstream repos now carry an unreleased upstream"
+ " bump:");
for (CascadeEdge edge : local.downstream()) {
lines.add(" " + edge.repo());
}
CascadeEdge next = local.downstream().get(0);
lines.add(" Continue the cascade with the next repo:");
lines.add(" cd ../" + next.repo()
+ " && mvn ike:release-publish");
lines.add(" Or release the whole foundation in order:");
lines.add(" mvn ike:release-cascade");
lines.add(RULE);
return lines;
}
/**
* Builds the cascade preview section for {@code ike:release-draft}.
*
* @param local the project's own parsed manifest
* @param repo the project's repo/directory name
* @return log lines naming the downstream repos this release will
* make stale; an end-of-cascade advisory when nothing is
* downstream
*/
public static List<String> draftPreview(ProjectCascade local,
String repo) {
List<String> lines = new ArrayList<>();
lines.add(RULE);
lines.add(" Foundation release cascade (release-cascade.yaml)");
lines.add(RULE);
if (local.terminal()) {
lines.add(" " + repo + " is last in the foundation"
+ " cascade — nothing downstream to release.");
lines.add(RULE);
return lines;
}
lines.add(" Publishing " + repo + " will make these"
+ " downstream repos stale:");
for (CascadeEdge edge : local.downstream()) {
lines.add(" " + edge.repo());
}
lines.add(" After publishing, continue with"
+ " ike:release-cascade.");
lines.add(RULE);
return lines;
}
}