AbstractSmartReactorReleaseStep.java
/*
* Copyright (C) 2016 Ronald Jack Jenkins Jr.
*
* 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 info.ronjenkins.maven.rtr.steps.release;
import info.ronjenkins.maven.rtr.RTR;
import info.ronjenkins.maven.rtr.RTRComponents;
import info.ronjenkins.maven.rtr.exceptions.SmartReactorReleaseException;
import info.ronjenkins.maven.rtr.steps.AbstractSmartReactorStep;
import java.util.List;
import java.util.Map;
import org.apache.maven.AbstractMavenLifecycleParticipant;
import org.apache.maven.MavenExecutionException;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.release.ReleaseExecutionException;
import org.apache.maven.shared.release.ReleaseFailureException;
import org.apache.maven.shared.release.ReleaseResult;
import org.apache.maven.shared.release.config.ReleaseDescriptor;
import org.apache.maven.shared.release.env.ReleaseEnvironment;
import org.apache.maven.shared.release.phase.ReleasePhase;
import org.codehaus.plexus.component.annotations.Requirement;
/**
* Base implementation of a Smart Reactor release step. No-op unless the Smart
* Reactor's release property is true at runtime.
*
* @author Ronald Jack Jenkins Jr.
*/
public abstract class AbstractSmartReactorReleaseStep extends
AbstractSmartReactorStep {
@Requirement(role = AbstractMavenLifecycleParticipant.class, hint = "rtr")
protected RTR rtr;
@Requirement(role = ReleasePhase.class)
protected Map<String, ReleasePhase> availablePhases;
@Requirement(hint = "rtr-rd")
protected ReleaseDescriptor releaseDescriptor;
@Requirement(hint = "rtr-re")
protected ReleaseEnvironment releaseEnvironment;
/**
* Subclasses can override this method to configure the release descriptor
* injected by Plexus. The default implementation does nothing.
*
* @param session
* the session to which this step applies. Not null.
* @param components
* that this step may need. May be null.
*/
protected void configureReleaseDescriptor(final MavenSession session,
final RTRComponents components) {}
@Override
public final void execute(final MavenSession session,
final RTRComponents components) throws MavenExecutionException {
if (this.rtr.isRelease()) {
this.logger.info(this.getAnnouncement());
this.configureReleaseDescriptor(session, components);
this.releaseExecute(session, components);
}
}
/**
* Returns the announcement that is logged when this release step begins
* execution.
*
* @return null or empty will prevent the corresponding log entry from
* occurring.
*/
protected abstract String getAnnouncement();
/**
* Returns the list of phases that should be executed by this release step.
*
* @return never null or empty.
* @throws UnsupportedOperationException
* if this step does not execute any release phases.
*/
protected abstract List<String> getReleasePhases();
/**
* Returns the list of phases that should be executed by this release step
* when rollback is required.
*
* @return never null or empty.
* @throws UnsupportedOperationException
* if this step does not execute any release phases.
*/
protected abstract List<String> getRollbackPhases();
/**
* Step logic that is executed if a release was requested.
*
* @param session
* the session to which this step applies. Not null.
* @param components
* that this step may need. May be null.
* @throws MavenExecutionException
* if any unrecoverable error occurs.
*/
protected void releaseExecute(final MavenSession session,
final RTRComponents components) throws MavenExecutionException {
this.releaseEnvironment.setSettings(session.getSettings());
final List<MavenProject> reactor = session.getProjects();
// Execute the release steps.
try {
this.runPhases(reactor, this.getReleasePhases());
}
catch (final MavenExecutionException | RuntimeException e) {
// Rollback if ANY exception occurred, then rethrow.
this.logger.error("Rolling back release due to error...");
try {
this.runPhases(reactor, this.getRollbackPhases());
}
catch (final MavenExecutionException | RuntimeException e2) {
// Suppress this exception.
e.addSuppressed(e2);
this.logger
.error("Rollback unsuccessful. Check project filesystem for POM backups and other resources that must be rolled back manually.");
}
throw e;
}
}
// Derived from DefaultReleaseManager.java in maven-release-manager, see
// THIRDPARTY file for further legal information.
private final void runPhases(final List<MavenProject> reactor,
final List<String> phases) throws MavenExecutionException {
ReleasePhase phase;
ReleaseResult result;
for (final String name : phases) {
phase = this.availablePhases.get(name);
if (phase == null) {
throw new SmartReactorReleaseException("Unable to find phase '" + name
+ "' to execute");
}
try {
result = phase.execute(this.releaseDescriptor, this.releaseEnvironment,
reactor);
}
catch (final ReleaseExecutionException | ReleaseFailureException e) {
throw new SmartReactorReleaseException(e);
}
if (result.getResultCode() == ReleaseResult.ERROR) {
throw new SmartReactorReleaseException(result.getOutput());
}
}
}
}