Theory In Practice

Gerrit Reviews and Automatic Topics

The more I use the combination of git-flow and gerrit as our code review process the more I feel I’d never want to use anything different.

As we continue to break up our projects into smaller repositories I find my change sets often cross repository boundaries.

When ever I find myself with a large, epic, cross-repository refactoring I find myself wanting a way to group the disparate reviews under a common “tag” to signify their interdependence - and it turns out Gerrit supports this via “topics”.

Traditionally we setup our repositories to push into gerrit with a for-review remote for the develop branch along the lines of:

[remote "for-review"]
  url = gerrit:dev/$GIT_REPO_NAME
  fetch = +refs/heads/*:refs/remotes/for-review/*
  push = HEAD:refs/for/develop

Which means submitting reviews is a simple matter of running git push for-review. But if I want to submit a review with a topic defined, I need to modify my .git/config’s push reference, or write a long winded command line.

Being the lazy developer that I am, I followed wrote up a simple git-submit-review script to handle it all for me:

#!/bin/sh
url=$(git config --get remote.for-review.url)
push=$(git config --get remote.for-review.push)
branch_name=$(git symbolic-ref -q HEAD)
branch_name=${branch_name##refs/heads/feature/}
branch_name=${branch_name:-HEAD}

git push $url $push/$branch_name

echo "Open browser to: \
  http://gerrit/#/q/status:open+topic:$branch_name,n,z \
  to view topic reviews"

Sticking this on the path lets me run git submit-review and any commits will be pushed to gerrit, along with the current feature branch name as the topic.

Now, for each repository I’m working on, if I use the same feature name, such as TEST-102-some-epic-fix then all of those reviews will be grouped nicely together so I can just send that filtered search to a coworker.

Note: This works for Gerrit 2.5, by looking at documentation changes for the upcoming 2.6 release, the topic is set by appending %topic=TOPICNAME_ to the push reference.

cucumber-testng-factory 1.0.1 released

So I finally merged in some recent pull requests and released to Maven Central my simple TestNG/Cucumber-JVM integration project.

<dependency>
  <groupId>com.theoryinpractise</groupId>
  <artifactId>cucumber-testng-factory</artifactId>
  <version>1.0.1</version>
</dependency>

The integration works by providing a builder for a TestNG Factory class, and is used like so:

@Factory
public Object[] create() {
    return new CucumberFactoryBuilder()
            .addOption("--format", "html:target/cucumber")
            .create(new File("src"));
}

on a class that also contains Cucumber based @Given/@When/@Then annotated methods. The CucumberFactoryBuilder returns an object array of TestNG tests that wrap cucumber for every .scenario file found under the path specified.

It’s not the most elegant solution, but it does appear to work quite well.

clojure-maven-plugin 1.3.15

Another minor release of the clojure-maven-plugin released to Maven Central fixing a small typo in the new nrepl goal, and also pulling in a long overlooked pull request for Marginalia multidoc generation which can be enabled by adding:

<configuration>
  <marginalia>
    <multi>true</multi>
  </marginalia>
</configuration>

to your pom.xml.

Maven coordinates are:

<dependency>
  <groupId>com.theoryinpractise</groupId>
  <artifactId>clojure-maven-plugin</artifactId>
  <version>1.3.15</version>
</dependency>

Happy clojuring.

coffee-maven-plugin 1.4.7

It seems I’m full of activity this week with yet another coffee-maven-plugin release bringing support for Coffee Script 1.6.1 and sourcemaps.

Sourcemaps can be generated by including:

<map>true</map>

in your Maven plugin configuration. This release also enabled the --header configuration setting to generated source files by default, which can be disabled by adding:

<header>false</header>

to your configuration.

Maven coordinates are:

<dependency>
  <groupId>com.theoryinpractise</groupId>
  <artifactId>coffee-maven-plugin</artifactId>
  <version>1.4.7</version>
</dependency>

Enjoy a good brew on me.

clojure-maven-plugin 1.3.14

A minor release of the clojure-maven-plugin to coincide with the release of Clojure 1.5.

This release also brings along a new clojure:nrepl goal which takes 3 parameters:

  • replScript - The clojure script to run before starting the repl
  • port - The nREPL server port, defaulting to 4005 and settable via -Dclojure.nrepl.port
  • nreplHost - The host to bind the nREPL server to, defaulting to localhost and settable via -Dclojure.nrepl.host

Maven coordinates are:

<dependency>
  <groupId>com.theoryinpractise</groupId>
  <artifactId>clojure-maven-plugin</artifactId>
  <version>1.3.14</version>
</dependency>

Happy clojuring.

coffee-maven-plugin 1.4.6 released

As a minor update to the year 1.4.4 release of the Coffee Script maven plugin, 1.4.6 was just released bringing support for literate coffee.

If you’ve not defined any joinsets in your pom.xml or have enabled the compileIndividualFiles option then any file ending in .litcoffee is automatically processed literately.

Otherwise you will need to include <literate>true</literate> in your joinset definition which will treat all files in that joinset as being literate.

<dependency>
  <groupId>com.theoryinpractise</groupId>
  <artifactId>coffee-maven-plugin</artifactId>
  <version>1.4.6</version>
</dependency>

coffee-maven-plugin 1.4.4 released

Earlier today I rolled out a long overdue maintenance release of the coffee-maven-plugin which adds support for Coffee Script 1.4.0, and the recently released 1.5.0.

1.5.0 is also now the default version used.

<dependency>
  <groupId>com.theoryinpractise</groupId>
  <artifactId>coffee-maven-plugin</artifactId>
  <version>1.4.4</version>
</dependency> 

Update your poms and grab it from Maven Central!

Simple Maven SNAPSHOT Repository Proxy Server

Have you ever had to deal with a project that purports to support Apache Maven repositories, but when it comes to timestamped SNAPSHOTs they fall apart? Well I have.

So to counter this I decided to write up a very basic, very simple proxy server use with anaemic applications that don’t know how to do things properly.

When the proxy gets a request for:

/foo/foobar/2.3-SNAPSHOT/foobar-2.3-SNAPSHOT.jar 

Then the upstream repositories metadata XML file is inspected, and the latest file is downloaded, and then returned to the caller as thou it were the non-timestamped SNAPSHOT they requested.

So far it all seems to work fine from curl based testing - but I guess the proof will be in the pudding when I try it against a real application that I’m having issues with.

This first implementation is done with Scala, and the Socko embedded webserver library, I’m also planning to write a Clojure version using HTTP Kit for comparison.

application/vnd.siren+json support for HalBuilder

Earlier today Kevin Swiber posted to the Siren list about the existence of any Java siren implementations, this is something I’ve been thinking of adding as an extension module for the HalBuilder library for awhile and thought - why not now? It’s a long weekend anyway…

Since internally HalBuilder already had a means to plug in new rendering/parsing instances adding basic Siren support was fairly simple, at least the rendering side of things.

After adding the new (unreleased) maven artefact to your project, you start off by creating a RepresentationFactory as normal, then configure it with the new renderer:

DefaultRepresentationFactory rf = new DefaultRepresentationFactory();
rf.withFlag(RepresentationFactory.PRETTY_PRINT);
rf.withRenderer("application/vnd.siren+json", SirenRepresentationWriter.class);

Now we can start building up our representaion instances:

Representation rep = rf.newRepresentation("/api/user/mark").withProperty("name", "Mark");
rep.withLink("licence", "http://www.apache.org/licenses/LICENSE-2.0.html");
Representation address = rf.newRepresentation()
  .withProperty("city", "Auckland")
  .withProperty("country", "New Zealand");
rep.withRepresentation("address", address);

Finally convert it to a String, requesting the siren media type:

System.out.println(rep.toString("application/vnd.siren+json"));

This returns us with:

{
  "links" : [ {
    "rel" : [ "self" ],
    "href" : "/api/user/mark"
  }, {
    "rel" : [ "licence" ],
    "href" : "http://www.apache.org/licenses/LICENSE-2.0.html"
  } ],
  "properties" : {
    "name" : "Mark"
  },
  "entities" : [ {
    "rel" : [ "address" ],
    "properties" : {
      "city" : "Auckland",
      "country" : "New Zealand"
    }
  } ]
}

There are several things to note with this current basic Siren renderer:

  • No support for Siren Actions
  • No support for Siren class attributes
  • No support for multiple rel’s 

Support for actions/class will likely come via special property keys ( urn:halbuilder:siren:class for example ), however multiple rel support will require changes to the core/api HalBuilder modules.

Still, for a initial start this provides a good chunk of Siren support.