ReleasePlan.java
package network.ike.plugin.ws;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.SequencedMap;
/**
* Immutable plan for a workspace release-and-align cascade.
*
* <p>Computed once at the start of any release or align operation by
* {@link ReleasePlanCompute#compute}.
* Every substitution thereafter is a blind lookup — no heuristics,
* no mid-flight reinterpretation, no re-reading of mutated POM state.
* Written to {@code plan.yaml} at the workspace root as an audit
* artifact before any mutation.
*
* <p>Design topic:
* <a href="https://github.com/IKE-Network/ike-issues/issues/212">#212</a>;
* <a href="../../../../../../../../ike-lab-documents/topics/src/docs/asciidoc/topics/dev/release-plan.adoc">dev-release-plan</a>.
*
* @param artifacts released subprojects, keyed by their Maven GA;
* insertion order is the release order
* @param properties version properties referenced by POMs in the
* cascade; iteration order is parent-declarations
* first then child overrides. A property declared in
* multiple POMs (parent + override) produces multiple
* entries — reactor inheritance is represented
* explicitly, not implicitly
*/
record ReleasePlan(
SequencedMap<GA, ArtifactReleasePlan> artifacts,
List<PropertyReleasePlan> properties) {
ReleasePlan {
artifacts = Collections.unmodifiableSequencedMap(artifacts);
properties = List.copyOf(properties);
}
/**
* A Maven artifact coordinate. {@code groupId:artifactId} is the
* unique key for an artifact release plan.
*/
record GA(String groupId, String artifactId) {
@Override
public String toString() {
return groupId + ":" + artifactId;
}
}
/**
* Kind of version-bearing site in a POM.
*
* <p>{@code PLUGIN_LITERAL} is intentionally absent — the
* 2026-04-22 empirical test showed that extensions plugins resolve
* user properties, so every in-cascade site can be a
* {@code ${property}} reference. See
* {@code ike-lab-documents/.../release-plan.adoc} for the
* evidence.
*/
enum ReferenceKind {
/** {@code <parent><version>...</version>} */
PARENT,
/** {@code <build><plugins|pluginManagement>/plugin/<version>} */
PLUGIN,
/** {@code <dependencies|dependencyManagement>/dependency/<version>} */
DEPENDENCY
}
/**
* One site in a POM that references an artifact version.
*
* <p>Captured during plan compute; used for audit output in
* {@code plan.yaml}.
* Does not drive substitution writes — those target property
* declarations and artifact self-version elements directly.
*
* @param pomPath absolute path to the POM containing the site
* @param kind whether the site is a parent, plugin, or
* dependency reference
* @param targetGa the groupId:artifactId the site references
* @param textAtSite the literal text at the site's
* {@code <version>} — a property reference like
* {@code ${ike-tooling.version}}, a literal like
* {@code 124}, or {@code null} when the version
* is inherited from parent pluginManagement
* and absent at this site
*/
record ReferenceSite(
Path pomPath,
ReferenceKind kind,
GA targetGa,
String textAtSite) {}
/**
* Plan for one subproject being released this cascade.
*
* <p>Values follow the pre/release/post naming because they are
* not always snapshots.
* IKE uses single-segment versions; values may be
* {@code 125-SNAPSHOT},
* {@code 125},
* {@code 126-SNAPSHOT},
* or any other form the subproject's version convention produces.
*
* @param ga the artifact's Maven coordinates
* @param producingSubproject the workspace subproject name that
* produces this artifact
* @param rootPomPath the subproject's root POM, where the
* artifact's own {@code <version>}
* element lives
* @param preReleaseValue the version before this cascade ran
* (typically a {@code -SNAPSHOT})
* @param releaseValue the version being released this
* cascade; what appears on the tag and
* in the deployed consumer POM; never
* ends in {@code -SNAPSHOT}
* @param postReleaseValue the version to restore the source POM
* to after the release (typically the
* next {@code -SNAPSHOT})
* @param referenceSites every site in the workspace that
* targets this artifact by GA (audit)
*/
record ArtifactReleasePlan(
GA ga,
String producingSubproject,
Path rootPomPath,
String preReleaseValue,
String releaseValue,
String postReleaseValue,
List<ReferenceSite> referenceSites) {
ArtifactReleasePlan {
referenceSites = List.copyOf(referenceSites);
}
}
/**
* Plan for one version-tracking property used by the cascade.
*
* <p>A property typically tracks an upstream subproject's release
* version.
* When the upstream subproject is released,
* this property's value in its declaring POM is updated to match
* the upstream's {@code releaseValue}.
* Child modules that redeclare the same property produce a second
* {@code PropertyReleasePlan} entry (reactor inheritance is
* represented explicitly, not implicitly).
*
* @param propertyName the property name
* (e.g., {@code ike-tooling.version})
* @param declaringPomPath the POM where the property is
* declared; where the write targets
* @param declaringSubproject the workspace subproject name
* containing the declaring POM
* @param preReleaseValue the property value before this
* cascade ran
* @param releaseValue the property value after the upstream
* is released this cascade
* @param postReleaseValue the property value to settle on after
* the full cascade; usually equals
* {@code releaseValue}
* @param referenceSites every site in the workspace that uses
* {@code ${propertyName}} (audit)
*/
record PropertyReleasePlan(
String propertyName,
Path declaringPomPath,
String declaringSubproject,
String preReleaseValue,
String releaseValue,
String postReleaseValue,
List<ReferenceSite> referenceSites) {
PropertyReleasePlan {
referenceSites = List.copyOf(referenceSites);
}
}
}