Java tutorial
package org.codehaus.mojo.versions; import java.io.IOException; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import org.apache.commons.lang.StringUtils; import org.apache.maven.Maven; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProjectBuilder; import org.eclipse.jgit.api.CheckoutCommand; import org.eclipse.jgit.api.FetchCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.MergeCommand; import org.eclipse.jgit.api.MergeCommand.FastForwardMode; import org.eclipse.jgit.api.MergeResult; import org.eclipse.jgit.api.PushCommand; import org.eclipse.jgit.api.RebaseCommand; import org.eclipse.jgit.api.RebaseResult; import org.eclipse.jgit.api.Status; import org.eclipse.jgit.api.StatusCommand; import org.eclipse.jgit.api.errors.CheckoutConflictException; import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.InvalidMergeHeadsException; import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.api.errors.NoMessageException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.transport.FetchResult; import org.eclipse.jgit.transport.NetRCCredentialsProvider; import org.eclipse.jgit.transport.PushResult; import org.eclipse.jgit.transport.RefSpec; import edu.emory.mathcs.backport.java.util.Collections; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ /** * Sets the current projects version, updating the details of any child modules as necessary. * * @author Stephen Connolly * @goal bump * @aggregator * @requiresProject true * @requiresDirectInvocation true * @since 1.0-beta-1 */ public class BumpMojo extends AbstractMojo { /** * The new bump number to set. * * @parameter expression="${bump}" * @since 1.0-beta-1 */ private String bump; /** * The dev branch. * * @parameter expression="${dev}" default-value="dev" * @since 1.0-beta-1 */ private String dev; /** * The push changed back to repo? * * @parameter expression="${push}" default-value="true" * @since 1.0-beta-1 */ private Boolean push; /** * The dev branch. * * @parameter expression="${master}" default-value="master" * @since 1.0-beta-1 */ private String master; /** * @component allo * @since 1.0-alpha-1 */ protected MavenProjectBuilder projectBuilder; /** * @parameter expression="${localRepository}" * @readonly * @since 1.0-alpha-1 */ protected ArtifactRepository localRepository; /** * The Maven Project. * * @parameter expression="${project}" * @required * @readonly * @since 1.0-alpha-1 */ private MavenProject project; /** * The Maven Session. * * @component * @required * @readonly * @since 1.0-alpha-1 */ Maven maven; Git git; static class VersionSort implements Comparator<String> { public int compare(String o1, String o2) { String[] k1 = o1.split("-"); o1 = k1[k1.length - 1]; String[] k2 = o2.split("-"); o2 = k2[k2.length - 1]; String[] oo1 = o1.split("\\."); String[] oo2 = o2.split("\\."); int len = Math.min(oo1.length, oo2.length); for (int i = 0; i < len; i++) { int r = new Integer(Integer.parseInt(oo1[i])).compareTo(Integer.parseInt(oo2[i])); if (r != 0) return r; } return 0; } } public void init() throws MojoExecutionException { try { NetRCCredentialsProvider.install(); FileRepositoryBuilder builder = new FileRepositoryBuilder(); Repository repository = builder.findGitDir().readEnvironment().findGitDir().build(); git = new Git(repository); } catch (IOException e) { throw new MojoExecutionException(e.getMessage(), e); } } void out(String str) { System.out.println(str); } public void gitLastTags() throws MojoExecutionException { try { List<Ref> list = git.tagList().call(); Map<String, List<String>> u = new TreeMap<String, List<String>>(); for (Ref r : list) { String tag = StringUtils.removeStart(r.getName(), "refs/tags/"); tag = SwitchReleaseMojo.release(tag); String tt = tag.split("-")[0]; List<String> list2 = u.get(tt); if (list2 == null) { list2 = new ArrayList<String>(); } list2.add(tag); u.put(tt, list2); } for (String tt : u.keySet()) { List<String> list2 = u.get(tt); Collections.sort(list2, new VersionSort()); for (int i = Math.max(0, list2.size() - 3); i < list2.size(); i++) { out(list2.get(i)); } } } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } } public boolean gitTagExists(String tag) throws MojoExecutionException { try { List<Ref> list = git.tagList().call(); for (Ref r : list) { String tag2 = StringUtils.removeStart(r.getName(), "refs/tags/"); if (tag2.equals(tag)) return true; } return false; } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } } boolean notEmpty(Set<String> ss) { return !ss.isEmpty(); } boolean gitModified() throws MojoExecutionException { StatusCommand statusCommand = git.status(); try { Status status = statusCommand.call(); if (notEmpty(status.getModified())) return true; if (notEmpty(status.getAdded())) return true; if (notEmpty(status.getChanged())) return true; if (notEmpty(status.getConflicting())) return true; if (notEmpty(status.getRemoved())) return true; if (notEmpty(status.getUncommittedChanges())) return true; if (notEmpty(status.getUntracked())) return true; return false; } catch (NoWorkTreeException e) { throw new MojoExecutionException(e.getMessage(), e); } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } } void out(Set<String> ss) { for (String s : ss) { out("?? " + s); } } void gitFetch() throws MojoExecutionException { try { FetchCommand ff = git.fetch(); FetchResult f = ff.call(); } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } } void gitCheckout(String m) throws MojoExecutionException { try { CheckoutCommand ff = git.checkout(); ff.setName(m); Ref f = ff.call(); } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } } void gitBranchD(String m) throws MojoExecutionException { try { List<String> f = git.branchDelete().setBranchNames("refs/heads/" + m).call(); } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } } void gitPush(String d) throws MojoExecutionException { String origin = git.getRepository().getConfig().getString("branch", d, "remote"); String merge = git.getRepository().getConfig().getString("branch", d, "merge"); merge = Repository.shortenRefName(merge); gitPush(origin, merge); } void gitPush(String o, String d) throws MojoExecutionException { try { RefSpec spec = new RefSpec(d + ":" + d); PushCommand ff = git.push(); ff.setRemote(o); ff.setRefSpecs(spec); ff.setPushTags(); Iterable<PushResult> f = ff.call(); } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } } void gitCheckoutB(String tag) throws MojoExecutionException { try { CheckoutCommand ff = git.checkout(); ff.setName(tag); ff.setCreateBranch(true); Ref f = ff.call(); } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } } void gitTag(String tag) throws MojoExecutionException { try { git.tag().setName(tag).call(); } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } } void gitRebase() throws MojoExecutionException { try { RebaseCommand ff = git.rebase(); String masterOrigin = git.getRepository().getConfig().getString("branch", master, "remote"); String masterMerge = git.getRepository().getConfig().getString("branch", master, "merge"); masterMerge = Repository.shortenRefName(masterMerge); RevWalk walk = new RevWalk(git.getRepository()); RevCommit commit = walk .parseCommit(git.getRepository().getRef(masterOrigin + "/" + masterMerge).getObjectId()); ff.setUpstream(commit); RebaseResult f = ff.call(); if (!f.getStatus().isSuccessful()) { throw new MojoExecutionException(f.getStatus().toString()); } } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } catch (MissingObjectException e) { throw new MojoExecutionException(e.getMessage(), e); } catch (IncorrectObjectTypeException e) { throw new MojoExecutionException(e.getMessage(), e); } catch (IOException e) { throw new MojoExecutionException(e.getMessage(), e); } } void gitMerge(String c, String m) throws NoHeadException, ConcurrentRefUpdateException, CheckoutConflictException, InvalidMergeHeadsException, WrongRepositoryStateException, NoMessageException, GitAPIException, IOException { git.merge().setCommit(false).include(git.getRepository().getRef(m)).call(); git.commit().setAll(true).setMessage(c).call(); } void gitMergeNFF(String c, String m) throws MojoExecutionException { try { MergeCommand ff = git.merge(); ff.setCommit(false); ff.setFastForward(FastForwardMode.NO_FF); ff.include(git.getRepository().getRef(m)); MergeResult f = ff.call(); if (!f.getMergeStatus().isSuccessful()) { throw new MojoExecutionException(f.getMergeStatus().toString()); } git.commit().setAll(true).setMessage(c).call(); } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } catch (IOException e) { throw new MojoExecutionException(e.getMessage(), e); } } /** * Called when this mojo is executed. * * @throws org.apache.maven.plugin.MojoExecutionException * when things go wrong. * @throws org.apache.maven.plugin.MojoFailureException * when things go wrong. */ public void execute() throws MojoExecutionException, MojoFailureException { try { init(); if (StringUtils.isEmpty(bump)) { out("Current tags:"); gitLastTags(); out(""); out("type version like 'mvn -q com.github.axet:versions-maven-plugin:bump -Dbump=server-1.0.0'"); System.exit(1); } if (gitTagExists(bump)) { out("Current tags:"); gitLastTags(); out(""); out("tag '" + bump + "' already exist"); System.exit(1); } String tag = bump; String branch; String version; String[] bb = tag.split("-"); branch = bb[0]; version = bb[bb.length - 1]; if (gitModified()) { StatusCommand statusCommand = git.status(); try { out("Can't bump version on modified tree:"); Status status = statusCommand.call(); out(status.getModified()); out((status.getAdded())); out((status.getChanged())); out((status.getConflicting())); out((status.getRemoved())); out((status.getUncommittedChanges())); out((status.getUntracked())); } catch (NoWorkTreeException e) { throw new MojoExecutionException(e.getMessage(), e); } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } System.exit(1); } // merge master. we allowd to change master if it is a readme file // git fetch gitFetch(); // git checkout master gitCheckout(master); // git rebase gitRebase(); // git checkout dev gitCheckout(dev); // git merge -m "Merge master" master gitMerge("Merge master", master); // bump version in dev tree, otherwise it will produce conflict merge on master on second // tag for pom.xml // git checkout dev gitCheckout(dev); final List<String> tags = new ArrayList<String>(); SwitchReleaseMojo release = new SwitchReleaseMojo() { @Override synchronized String incrementModuleVersion(String groupId, String artifactId, String version) { String newVersion = super.incrementVersion(SwitchReleaseMojo.release(version)); tags.add(artifactId + "-" + newVersion); return newVersion; } }; release.projectBuilder = projectBuilder; release.localRepository = localRepository; release.setProject(project); release.setGenerateBackupPoms(false); release.setNewVersion(version); release.setLog(getLog()); release.execute(); // git commit -m "Bump version $BRANCH $VERSION" -a git.commit().setAll(true).setMessage("Bump version " + branch + " " + version).call(); // create proper branch (server-1.0.0), helps produce nice git history // git checkout -b $TAG dev gitCheckoutB(tag); // prepare to merge // git checkout master gitCheckout(master); // do merge with a propertly named branch // git merge --no-ff -m "Merge branch '$TAG'" $TAG gitMergeNFF("Merge branch '" + tag + "'", tag); // do tag last master commit // git tag $TAG gitTag(tag); // tag all other changed (depended) modules for (String t : tags) gitTag(t); tags.clear(); // drop perpared branch // git branch -d $TAG gitBranchD(tag); // switch back to the dev // git checkout dev gitCheckout(dev); // update version with -SNAPSHOT postfix // git commit -m "Bump version $BRANCH $VERSION" -a SwitchSnapshotMojo snapshot = new SwitchSnapshotMojo(); snapshot.projectBuilder = projectBuilder; snapshot.localRepository = localRepository; snapshot.setProject(project); snapshot.setGenerateBackupPoms(false); snapshot.setLog(getLog()); snapshot.execute(); git.commit().setAll(true).setMessage("Bump version " + branch + " " + version).call(); if (push) { out(""); out("All done, push repo"); out(""); // git push origin master || exit 1 // git push --tags || exit 1 // git push origin dev || exit 1 gitPush(master); gitPush(dev); } } catch (GitAPIException e) { throw new MojoExecutionException(e.getMessage(), e); } catch (IOException e) { throw new MojoExecutionException(e.getMessage(), e); } } }