Class FeatureStartSiblingPublishMojo
- All Implemented Interfaces:
org.apache.maven.api.plugin.Mojo
- Direct Known Subclasses:
FeatureStartSiblingPublishVerifyMojo
This is the sibling column of ws:feature-start: where
ws:feature-start-publish branches the primary in place — which
under Syncthing rewrites the working tree while the other machine's
.git/HEAD stays put, the failure mode that motivates this goal —
ws:feature-start-sibling-publish makes a second clone of the whole
workspace alongside the primary, checked out on feature/<name>
from inception. The primary never leaves its current branch; the feature
lives in its own directory and is disposable (rm -rf) after merge.
The same isolation makes concurrent same-machine work safe: each sibling
has its own working tree, so two lines of work never stage each other's
edits.
What it does (workspace mode):
- Validates
featurethroughFeatureNameand computes the sibling directory<parent>/<baseName>-<feature>/from the resolved working set'sbaseName; refuses if it already exists. - Resolves the base branch to clone from:
-Dfromwhen given, else the primary's current branch — guarded so a sibling is not silently cut from an unexpected branch (seeSiblingBaseResolution). - Clones the workspace root, then each subproject in topological
order, into the sibling with
git clone --reference <primary>/<component> --dissociate -b <base> <remote> <sibling>/<component>.--referenceborrows the object database from the primary's local clone (the order-of-magnitude win for large histories like tinkar-core's 492 MB);--dissociatethen copies the borrowed objects so the sibling is fully self-contained. - Creates
feature/<name>in each clone and applies the same version qualification and BOM/property cascade thatws:feature-start-publishproduces in-place, via the sharedFeatureStartSupport. - Rewrites the sibling's
workspace.yamlbranch fields and commits.
No push. Externally visible side effects stay opt-in
(per feedback_workspace_ops_completion). The clones, branches,
version commits, and workspace.yaml update are all recoverable
local effects and happen by default; pushing to origin is not.
mvn ws:feature-start-sibling-publish -Dfeature=jira-456
# creates ../<workspace>-jira-456/ with every component on
# feature/jira-456, then: cd ../<workspace>-jira-456 && work.
- See Also:
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprotected booleanWhether the-Dallow-uncommittedescape hatch is set — bypasses aTreePreflight.REQUIRE_UNMODIFIEDpreflight (#780).protected booleanPrompt the user with a yes/no question, accepting "y"/"yes"/"n"/"no" (case-insensitive).protected booleanWhether the-Ddefer-commitcascade hand-off is set — the goal skips its ownTreePreflight.REQUIRE_UNMODIFIEDpreflight andAuthoredCommit.IN_ISOLATIONcommit so the invoking goal owns the commit (AuthoredCommit.DEFER_TO_CALLER, #780).final voidexecute()Run the goal and write its report.protected org.apache.maven.api.plugin.LoggetLog()Access the Maven logger.protected network.ike.plugin.support.IkePrompterTheIkePrompterfor this goal — built lazily from the session's interactive flag, or the test-injected instance.protected org.apache.maven.api.SessionAccess the Maven session injected by Maven 4's plugin DI.protected StringGet the current branch of a subproject directory.protected StringgitShortSha(File subprojectDir) Get the short SHA of HEAD for a subproject directory.protected StringRungit status --porcelainon a subproject directory and return the output (empty string = clean).protected StringFormat a goal header line using the workspace name.protected booleanCheck whether a workspace.yaml exists in the directory hierarchy.protected network.ike.workspace.WorkspaceGraphLoad the manifest and build the workspace graph.protected WsGoalThe goal identity used for this run's report file.protected StringrequireParam(String currentValue, String propertyName, String promptLabel) Prompt the user interactively for a required parameter when it was not supplied on the command line.protected network.ike.workspace.CohortResolve theCohortan artifact / release-style goal acts on, honoring-Dworkspace.manifest(IKE-Network/ike-issues#612).protected PathResolve the manifest path — explicit parameter, or search upward.protected network.ike.workspace.WorkingSetResolve theWorkingSetthis goal acts on, honoring the-Dworkspace.manifestoverride and the workspace-vs-single-repo decision in one place (IKE-Network/ike-issues#611).protected WorkspaceReportSpecrunGoal()Run this goal's work and return the report it produced.protected StringselectFromList(String label, List<String> options) Prompt the user to pick from a numbered list.protected voidsetLog(org.apache.maven.api.plugin.Log log) Replace the logger.protected final booleanWhether to build the sibling reactor after creating it.protected static network.ike.workspace.FeatureNamevalidateFeatureName(String feature) Validate a feature-name string withFeatureName.of(String)and surface any rule violation as a cleanMojoException(the rawIllegalArgumentExceptionwould otherwise bubble up as a Maven internal error).protected static network.ike.workspace.MavenVersionvalidateMavenVersion(String version) Validate a Maven version string withMavenVersion.of(String)and surface any rule violation as aMojoException(ike-issues#295).protected static network.ike.workspace.SubprojectNamevalidateSubprojectName(String subproject) Validate a subproject-name string withSubprojectName.of(String)and surface any rule violation as aMojoException(ike-issues#295).protected booleanDefault for the post-create reactor build when-Dverifyis not given.protected voidverifySibling(File siblingRoot) Build the sibling's whole reactor from its root, failing loud if it does not build.protected StringRead the workspace name from the root POM's artifactId.protected FileResolve the workspace root directory (parent of workspace.yaml).
-
Constructor Details
-
FeatureStartSiblingPublishMojo
public FeatureStartSiblingPublishMojo()Creates this goal instance.
-
-
Method Details
-
shouldVerify
protected final boolean shouldVerify()Whether to build the sibling reactor after creating it. The base goal returns the-Dverifyflag; the-verifysubclass overridesverifyByDefault()so the build is on by default.- Returns:
truewhen the post-create reactor build should run
-
verifyByDefault
protected boolean verifyByDefault()Default for the post-create reactor build when-Dverifyis not given.falsehere;FeatureStartSiblingPublishVerifyMojooverrides it totrue.- Returns:
false— the base goal does not build unless asked
-
reportGoal
The goal identity used for this run's report file. The base goal reports asWsGoal.FEATURE_START_SIBLING_PUBLISH; the-verifysubclass overrides this so its report lands in its own file.- Returns:
- the
WsGoalthis invocation reports as
-
verifySibling
Build the sibling's whole reactor from its root, failing loud if it does not build. RunsverifyGoals(defaultclean install -DskipTests -T 1C) as a subprocess against the freshly created sibling, mirroringws:checkpoint-publish's pre-tag reactor gate (#689).On failure the clone is left intact — the message says so — so the user can fix the build in place rather than re-clone. Overridable so the #777 coverage can drive the pass/fail outcome without a nested build.
- Parameters:
siblingRoot- the sibling workspace root to build from- Throws:
org.apache.maven.api.plugin.MojoException- if the reactor build fails, or the subprocess setup itself fails
-
runGoal
Run this goal's work and return the report it produced.Implementations do the goal's actual work here and return a
WorkspaceReportSpec— the goal identity and the Markdown body. The base class resolves the workspace root and writes the file. A goal cannot be implemented without producing a report, which is the structural fix for the missing-report bug class (IKE-Network/ike-issues#413 / #407).On failure, throw
MojoExceptionas usual — a failed goal produces no report, and Maven surfaces the exception.- Returns:
- the report this goal produced (never
null) - Throws:
org.apache.maven.api.plugin.MojoException- if the goal fails
-
getLog
protected org.apache.maven.api.plugin.Log getLog()Access the Maven logger.- Returns:
- the logger instance
-
allowUncommitted
protected boolean allowUncommitted()Whether the-Dallow-uncommittedescape hatch is set — bypasses aTreePreflight.REQUIRE_UNMODIFIEDpreflight (#780).- Returns:
trueto proceed despite an uncommitted working tree
-
deferCommit
protected boolean deferCommit()Whether the-Ddefer-commitcascade hand-off is set — the goal skips its ownTreePreflight.REQUIRE_UNMODIFIEDpreflight andAuthoredCommit.IN_ISOLATIONcommit so the invoking goal owns the commit (AuthoredCommit.DEFER_TO_CALLER, #780).- Returns:
trueto defer the preflight + commit to the caller
-
getSession
protected org.apache.maven.api.Session getSession()Access the Maven session injected by Maven 4's plugin DI.- Returns:
- the injected session (may be
nullin unit tests)
-
setLog
protected void setLog(org.apache.maven.api.plugin.Log log) Replace the logger. Used when a mojo is constructed directly (not via Maven's DI container) and so never had a logger injected —WsSyncMojodrivesPullWorkspaceMojoandPushMojoinstances it created itself.- Parameters:
log- the replacement logger
-
getPrompter
protected network.ike.plugin.support.IkePrompter getPrompter()TheIkePrompterfor this goal — built lazily from the session's interactive flag, or the test-injected instance. Callers that pass it to a static helper (e.g.FeatureFinishSupport.promptStaleBranchCleanup(File, List, String, String, IkePrompter, Log)) use this.- Returns:
- the prompter (never
null)
-
loadGraph
protected network.ike.workspace.WorkspaceGraph loadGraph()Load the manifest and build the workspace graph.- Returns:
- the workspace dependency graph
- Throws:
org.apache.maven.api.plugin.MojoException- if the manifest cannot be read
-
resolveManifest
Resolve the manifest path — explicit parameter, or search upward.- Returns:
- path to the workspace manifest file
- Throws:
org.apache.maven.api.plugin.MojoException- if the manifest cannot be found
-
workspaceRoot
Resolve the workspace root directory (parent of workspace.yaml).- Returns:
- the workspace root directory
- Throws:
org.apache.maven.api.plugin.MojoException- if the manifest cannot be found
-
gitStatus
-
gitBranch
-
gitShortSha
-
isWorkspaceMode
protected boolean isWorkspaceMode()Check whether a workspace.yaml exists in the directory hierarchy. Does not throw — returns false if no manifest is found.- Returns:
- true if running inside a workspace, false for a bare repo
-
resolveWorkingSet
protected network.ike.workspace.WorkingSet resolveWorkingSet()Resolve theWorkingSetthis goal acts on, honoring the-Dworkspace.manifestoverride and the workspace-vs-single-repo decision in one place (IKE-Network/ike-issues#611). When aworkspace.yamlis configured or found by searching upward, the working set is that workspace's subprojects plus the root; otherwise it is the current repository — a working set of one. This is the single home for theisWorkspaceMode()+ bare-mode branch the working-tree goals otherwise each carry, delegating to the sharedWorkingSetResolver.- Returns:
- the resolved working set (never
null)
-
resolveCohort
protected network.ike.workspace.Cohort resolveCohort()Resolve theCohortan artifact / release-style goal acts on, honoring-Dworkspace.manifest(IKE-Network/ike-issues#612). When aworkspace.yamlis configured or found by searching upward, the cohort is its subprojects in topological order (the aggregator root excluded); otherwise it is the current repository — a cohort of one. The dependency-ordered counterpart toresolveWorkingSet(), delegating to the sharedCohortResolver.- Returns:
- the resolved cohort (never
null)
-
requireParam
Prompt the user interactively for a required parameter when it was not supplied on the command line.Delegates to the
IkePrompter(IKE-Network/ike-issues#385): an inline prompt on a real terminal, an own-line prompt in a piped IDE runner. In batch mode it throws a clear error directing the user to pass the property explicitly.- Parameters:
currentValue- the value from the@Parameterfield (may be null)propertyName- the-Dproperty name (for the error message)promptLabel- human-readable label shown in the prompt; callers pass it without trailing punctuation (a": "separator is appended here)- Returns:
- the resolved value — either the original or user-supplied
- Throws:
org.apache.maven.api.plugin.MojoException- if no value can be obtained
-
validateFeatureName
Validate a feature-name string withFeatureName.of(String)and surface any rule violation as a cleanMojoException(the rawIllegalArgumentExceptionwould otherwise bubble up as a Maven internal error). Use this anywhere a feature name leaves the-Dfeature=command-line boundary (ike-issues#205).- Parameters:
feature- the candidate feature name (must already be resolved — i.e. non-null afterrequireParam(String, String, String)or auto-detection)- Returns:
- the validated
FeatureNamevalue - Throws:
org.apache.maven.api.plugin.MojoException- iffeaturefails theFeatureNamesyntax rules
-
validateSubprojectName
Validate a subproject-name string withSubprojectName.of(String)and surface any rule violation as aMojoException(ike-issues#295).- Parameters:
subproject- the candidate subproject name (already resolved — non-null afterrequireParam(String, String, String)or POM derivation)- Returns:
- the validated
SubprojectNamevalue - Throws:
org.apache.maven.api.plugin.MojoException- ifsubprojectfails theSubprojectNamesyntax rules
-
validateMavenVersion
Validate a Maven version string withMavenVersion.of(String)and surface any rule violation as aMojoException(ike-issues#295). Perfeedback_no_semver_assumptionthe validator accepts single-segment monotonic, semver-like, calendar-based, and branch-qualified versions; it does not enforce semver.- Parameters:
version- the candidate version string- Returns:
- the validated
MavenVersionvalue - Throws:
org.apache.maven.api.plugin.MojoException- ifversionfails theMavenVersionsyntax rules
-
confirm
Prompt the user with a yes/no question, accepting "y"/"yes"/"n"/"no" (case-insensitive). When invoked in a non-interactive context, the default is used.- Parameters:
label- the question to display (without trailing punctuation)defaultYes- whethertrue(yes) is the default- Returns:
truefor yes,falsefor no- Throws:
org.apache.maven.api.plugin.MojoException- if no answer can be obtained
-
selectFromList
Prompt the user to pick from a numbered list. Returns the chosen option, ornullwhen the list is empty.- Parameters:
label- prompt header (printed via the Prompter as a message)options- ordered list of choices- Returns:
- the chosen option, or
nullifoptionsis empty - Throws:
org.apache.maven.api.plugin.MojoException- if no valid choice can be obtained
-
workspaceName
Read the workspace name from the root POM's artifactId. Falls back to "Workspace" if the POM cannot be read.- Returns:
- the workspace name derived from the root POM artifactId
-
header
-
execute
public final void execute() throws org.apache.maven.api.plugin.MojoExceptionRun the goal and write its report.This method is
final: everyws:*goal follows the same template — do the work, then write exactly one report. Subclasses supply the work and the report content by implementingrunGoal(); they cannot overrideexecute()to skip the report. That is what makes report-writing structural — a goal that compiles necessarily writes a report, so the #407 bug class (a goal runs fine but silently writes none) becomes compiler-impossible (IKE-Network/ike-issues#413).The report lands in its per-goal file at the workspace root (
ws꞉goal-name.md);WorkspaceReportself-heals the nearest.gitignoreso reports never land in git. A-publishrun does not delete the matching-draftreport — both are timestamped history (ike-issues#413).- Specified by:
executein interfaceorg.apache.maven.api.plugin.Mojo- Throws:
org.apache.maven.api.plugin.MojoException- if the goal fails
-