net.sf.buildbox.changes.ChangesControllerImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of releasator Show documentation
Show all versions of releasator Show documentation
Commandline utility for creating reproducible releases. Minimal parametrization, isolated sandbox for releases. Currently built on top of maven-release-plugin.
The newest version!
package net.sf.buildbox.changes;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import java.io.*;
import net.sf.buildbox.changes.bean.*;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.XmlException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
public class ChangesControllerImpl implements ChangesController {
public static final XmlOptions xmlOptions = new XmlOptions()
.setUseDefaultNamespace()
.setCharacterEncoding("UTF-8")
.setSavePrettyPrint();
private final ChangesDocumentBean doc;
final ChangesDocumentBean.Changes changes;
private static final String SNAPSHOT_SUFFIX = "-SNAPSHOT";
private static final String COMMENTED_EXAMPLE = " delete this wrapping comment and write your change items here - at least one is required for release.\n" +
" - some meaningful description
\n ::";
public ChangesControllerImpl(File xmlFile) throws IOException {
try {
this.doc = ChangesDocumentBean.Factory.parse(xmlFile, xmlOptions);
this.changes = doc.getChanges();
} catch (XmlException e) {
e.printStackTrace();
throw new IOException(e.getClass().getName() + ": " + e.getMessage());
}
}
public ChangesControllerImpl(ChangesDocumentBean doc) {
this.doc = doc;
this.changes = doc.getChanges();
}
private static ChangesDocumentBean newDoc() {
final ChangesDocumentBean result = ChangesDocumentBean.Factory.newInstance(xmlOptions);
result.addNewChanges();
return result;
}
public ChangesControllerImpl(String groupId, String artifactId, String version, String initialItemText) {
this(newDoc());
final ChangesDocumentBean.Changes.Unreleased unreleased = changes.addNewUnreleased();
unreleased.setGroupId(groupId);
unreleased.setArtifactId(artifactId);
unreleased.setVersion(version);
if (initialItemText != null) {
final ItemBean item = unreleased.insertNewItem(0);
item.setAction(ItemBean.Action.ADD);
item.setStringValue(initialItemText);
}
}
private VersionNotesBean latest() {
if (changes.getUnreleased() != null) return changes.getUnreleased();
if (changes.getLocalbuild() != null) return changes.getLocalbuild();
return changes.getReleaseArray(0);
}
public String getGroupId() {
return latest().getGroupId();
}
public String getArtifactId() {
return latest().getArtifactId();
}
public String getVersion() {
return latest().getVersion();
}
public void snapshotToLocalBuild(long timestamp, String author) throws IOException {
final BuiltVersionNotesBean localBuild = changes.addNewLocalbuild();
final ChangesDocumentBean.Changes.Unreleased unreleased = changes.getUnreleased();
if (unreleased == null) {
throw new IllegalStateException("no unreleased part found");
}
// remove comments:
final Node parentNode = unreleased.getDomNode();
Node node = parentNode.getFirstChild();
while (node != null) {
final Node n1 = node;
node = node.getNextSibling();
if (n1.getNodeType() == Node.COMMENT_NODE) {
parentNode.removeChild(n1);
}
}
//
try {
localBuild.set(unreleased);
localBuild.setVersion(unreleased.getVersion());
final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.setTimeInMillis(timestamp);
localBuild.setTimestamp(cal);
localBuild.setAuthor(author);
// vcs, toolstack, os, cpu
final BuiltVersionNotesBean.Os os = localBuild.addNewOs();
os.addNewArch().setStringValue(System.getProperty("os.arch"));
os.addNewName().setStringValue(System.getProperty("os.name"));
os.addNewVersion().setStringValue(System.getProperty("os.version"));
} finally {
changes.unsetUnreleased();
}
}
public boolean localBuildToRelease(String releaseVersion, String releaseTag) throws IOException {
final BuiltVersionNotesBean localBuild = changes.getLocalbuild();
if (localBuild == null) {
throw new IllegalStateException("no localbuild part prepared");
}
// TODO: check that all neccessary info is ready and correct
// check that there is no release with such version yet
final String releaseGroupId = localBuild.getGroupId();
final String releaseArtifactId = localBuild.getArtifactId();
for (ChangesDocumentBean.Changes.Release release : changes.getReleaseArray()) {
if (!release.getGroupId().equals(releaseGroupId)) continue;
if (!release.getArtifactId().equals(releaseArtifactId)) continue;
if (!release.getVersion().equals(releaseVersion)) continue;
throw new IllegalStateException("File changes.xml already contains version " + releaseVersion);
}
// check that major version specified in changes.xml prefixes the releaseVersion
boolean shouldIncrementSnapshot = false;
final String unreleasedVersion = localBuild.getVersion();
final String releaseVersionPrefix = getReleaseConfigProperty(RLSCFG_RELEASE_VERSION_PREFIX);
if (releaseVersionPrefix == null) {
final String majorVersion;
if (unreleasedVersion.endsWith(SNAPSHOT_SUFFIX)) {
majorVersion = unreleasedVersion.substring(0, unreleasedVersion.length() - SNAPSHOT_SUFFIX.length());
} else {
majorVersion = unreleasedVersion;
}
if (releaseVersion.equals(majorVersion)) {
// ok, we release exactly the same version as major
shouldIncrementSnapshot = true;
} else if (releaseVersion.startsWith(majorVersion + ".")) {
// ok, we release minor of current version
} else if (releaseVersion.startsWith(majorVersion + "-")) {
// ok, we release alpha/beta/rc or patch of current version
} else {
throw new IllegalArgumentException(String.format("version mismatch - changes.xml/unreleased/@version(='%s') is not prefix for releaseVersion(='%s')",
unreleasedVersion, releaseVersion));
}
} else {
if (! releaseVersion.startsWith(releaseVersionPrefix)) {
throw new IllegalArgumentException(String.format("version mismatch - changes.xml/configuration/property[@name='%s'] " +
"requires the version to be prefixed with '%s' - not satisfied by your version: %s ",
RLSCFG_RELEASE_VERSION_PREFIX, releaseVersionPrefix, releaseVersion));
}
}
final ItemBean[] items = localBuild.getItemArray();
if (items.length == 0) {
throw new IllegalStateException("There are no change items to release");
}
final String firstItemStr = items[0].getStringValue();
if (firstItemStr.length() < 10) {
throw new IllegalStateException("Item text does not look like a valuable description: " + firstItemStr);
}
/*TODO:
if (localBuild.getModuleArray().length == 0) {
throw new IllegalStateException("Missing list of released artifacts");
}
*/
if (localBuild.getVcs() == null) {
throw new IllegalStateException("Missing VCS information");
}
try {
final BuiltVersionNotesBean release = changes.insertNewRelease(0);
release.set(localBuild);
release.setVersion(releaseVersion);
release.getVcs().setTag(releaseTag);
return shouldIncrementSnapshot;
} finally {
changes.unsetLocalbuild();
}
}
public void releaseToSnapshot(String snapshotVersion) {
if (changes.getLocalbuild() != null) {
throw new IllegalStateException("cannot advance to snapshot from local distribution");
}
if (changes.getUnreleased() != null) {
throw new IllegalStateException("not in released state - unreleased section found");
}
final ChangesDocumentBean.Changes.Release r = changes.getReleaseArray(0);
final ChangesDocumentBean.Changes.Unreleased u = changes.addNewUnreleased();
u.setGroupId(r.getGroupId());
u.setArtifactId(r.getArtifactId());
u.setVersion(snapshotVersion);
u.getDomNode().appendChild(((Document) doc.getDomNode()).createComment(COMMENTED_EXAMPLE));
}
public void validate() {
doc.validate();
//TODO: add some more validations
}
public void addBuildTool(BuildToolRole role, String groupId, String artifactId, String version) {
final BuiltVersionNotesBean localBuild = changes.getLocalbuild();
final BuiltVersionNotesBean.Buildtool tool = localBuild.addNewBuildtool();
tool.setRole(role.toString());
tool.setGroupId(groupId);
tool.setArtifactId(artifactId);
tool.setVersion(version);
}
public void addFile(String moduleGroupId, String moduleArtifactId, String moduleVersion, String classifier, String type) {
final BuiltVersionNotesBean latest = (BuiltVersionNotesBean) latest(); //TODO: DIRTY - should be done on localbuild!
final BuiltVersionNotesBean.Module module = findOrCreate(latest, moduleGroupId, moduleArtifactId, moduleVersion);
final BuiltVersionNotesBean.Module.Artifact artifact = module.addNewArtifact();
if (classifier != null) {
artifact.addNewClassifier().setStringValue(classifier);
}
artifact.addNewType().setStringValue(type);
}
public void addUnreleasedItem(ItemBean.Action.Enum action, String issueRef, String component, String text) {
final ChangesDocumentBean.Changes.Unreleased unreleased = changes.getUnreleased();
if (unreleased == null) {
throw new IllegalStateException("No 'unreleased' element found in changes.xml");
}
final ItemBean item = unreleased.insertNewItem(0);
if (action != null) {
item.setAction(action);
}
if (issueRef != null) {
item.setIssue(issueRef);
}
if (component != null) {
item.setComponent(component);
}
item.setStringValue(text);
}
public void save(File file) throws IOException {
((Element) doc.getChanges().getDomNode()).setAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi:schemaLocation", "http://buildbox.sf.net/changes/2.0 http://buildbox.sourceforge.net/releasator/changes.xsd");
doc.save(file, xmlOptions);
}
public void setCodename(String newCodename) {
if (changes.getUnreleased() != null) {
changes.getUnreleased().setCodename(newCodename);
} else if (changes.getLocalbuild() != null) {
changes.getLocalbuild().setCodename(newCodename);
} else {
throw new IllegalArgumentException("no unreleased or localbuild section found, cannot change codename");
}
}
public void setVcsInfo(String vcsType, String vcsId, String develCodePath, String revision) {
final BuiltVersionNotesBean localBuild = changes.getLocalbuild();
final VcsInfoBean vcs = localBuild.addNewVcs();
vcs.setType(vcsType);
vcs.setId(vcsId);
vcs.setLocation(develCodePath);
if (revision != null) {
vcs.setRevision(revision);
}
}
public String getReleaseConfigProperty(String propertyName) {
return getReleaseConfigProperties().get(propertyName);
}
public Map getReleaseConfigProperties() {
final Map config = new HashMap();
final ChangesDocumentBean.Changes.Configuration configuration = changes.getConfiguration();
if (configuration == null) {
return Collections.emptyMap();
}
for (ConfigurationPropertyBean propertyBean : configuration.getPropertyArray()) {
final String propertyName = propertyBean.getName();
final String propertyValue = propertyBean.getStringValue();
config.put(propertyName, propertyValue);
}
return config;
}
private BuiltVersionNotesBean.Module findOrCreate(BuiltVersionNotesBean builtVersion, String groupId, String artifactId, String version) {
final BuiltVersionNotesBean.Module[] modules = builtVersion.getModuleArray();
for (BuiltVersionNotesBean.Module module : modules) {
if (!groupId.equals(module.getGroupId().getStringValue())) continue;
if (!artifactId.equals(module.getArtifactId().getStringValue())) continue;
if (!version.equals(module.getVersion().getStringValue())) continue;
return module;
}
final BuiltVersionNotesBean.Module module = builtVersion.addNewModule();
module.addNewGroupId().setStringValue(groupId);
module.addNewArtifactId().setStringValue(artifactId);
module.addNewVersion().setStringValue(version);
return module;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy