Nicholas Blair Software Engineer

Follow up to 'Combining Spring Boot with Bower dependencies'

In this post I’ll revisit a previous post titled Combining Spring Boot with Bower dependencies. After working for a few months with the bifurcated project structure described in that post, we ran into more trouble than we expected.

Tl;DR: Don’t split the repositories if you don’t have to. Use one repository, and have gradle invoke bower install. Also support running npm start/bower install in src/main/resources.

What we thought we’d get

We thought that by splitting the repositories, two different teams with different skill sets could work in isolation on the same target deliverable. Each team could run their relevant sections of code with their preferred stacks, and we’d lean on some Maven tricks with our Continuous Integration environment to stitch it all together nicely.

What we ended up getting

With two different repositories on different stacks, we spent a lot of time diagnosing local development issues. With the back end project, we had Spring Boot’s embedded Tomcat. On the front end, we had Node. Both parts needed things like URL rewriting, redirects, and 404/500 error pages. The configuration for those types of things are container specific, and the configuration we had to develop for the front-end was only applicable to development, and not deployed environments.

Additionally, when we started, all features in the site were available to the anonymous user - no authentication was required. A REST API was then developed that required authentication. The back end had uw-spring-security for this, the front-end repository had no equivalent.

We then wanted a log in user experience, and features that toggled on/off if you were logged in. Without authentication in the front-end repository, developing those features was a guessing game. Open a pull request with what you thought would work, get it merged, and wait until it was deployed to the beta environment to see if it worked. No good at all for productivity to have to wait to ship code to see if it works.

Lastly, in the deployed environment, we had to marry the URL rewriting and redirecting needs of the front-end project in to the embedded Tomcat for Spring Boot. UrlRewriteFilter is actually amazing for this, but it was a piece of code that didn’t exist in dev, only in beta and production. Troubleshooting it was tricky, because you could only troubleshoot on some remote server.

What we did instead

The writing was on the wall: we had to consolidate the front-end and back-end repositories. The separation was good in theory, but it created too much friction in development. Having to wait to deploy your code to a remote server to see if it gets the job done is no way to work; we need to go back to being able to run the whole application locally for some tasks.

Mechanically, consolidation was a matter of copying the site content from the front-end repository into src/main/resources/static in the back-end repository.

We then needed gradle’s build to invoke bower install. The best Google search result for ‘gradle bower install’ turned out to be craigburke’s bower installer gradle plugin, here’s the relevant section of our build.gradle:

We’re back to having something buildable, but what about the front-end team? They don’t want to run gradle bootRun if they don’t have to.

We have slightly different startup instructions for front-end developers. After cloning the repository:

  1. cd src/main/resources
  2. npm start

In src/main/resources, we have the same package.json, superstatic.json and bower.json that we had in the separate repository. We had to add .bowerrc to src/main/resources with the following contents:

{ "directory": "static/bower_components" }

Now when one invokes gradle bowerInstall at the root, or if they run bower install within src/main/resources, the contents of src/main/resources/static/bower_components are equally valid. They don’t match exactly, because the gradle plugin doesn’t fetch the entire repository like true bower does, but the bits we depend on are in the exact same directory hierarchy.

This is working much better. Now a front-end developer has the choice:

  • Run lean with npm start and not have to worry about the full gradle build. The default proxy configuration points to the beta environment, so they always have a REST API available with live data. Make changes to markup, styles, and not have to restart the container.
  • If working on something that does require tigher integration with the back end, then the full gradle bootRun is an option to run everything, together, locally.

The one drawback is having to maintain bower dependencies in two places. The project doesn’t experience a lot of volatility in front-end dependencies right now, so we’re living with it.

Addendum: alternative to bower-installer-gradle plugin

One alternative to using the bower-installer-gradle plugin is to include something like this in your build.gradle:

task bowerInstallManual(type:Exec) {
    workingDir 'src/main/resources/'
    commandLine 'bower', 'install'
}

build.dependsOn bowerInstallManual
build.mustRunAfter bowerInstallManual

This works well, but it does have the side effect of requiring that the back-end developer have bower installed.

Release Management - Maintenance Branches

In this post I’ll elaborate on a specific scenario in release management: what to do when fresh new features have been merged to master and the minor (or major) version has gone up, but you need a bug fix for the prior releases.

Scenario

We have projectX, which is a mature, Maven-managed project that is using the Maven Release Plugin to distribute artifacts. The project produces a jar that is used as a dependency in a number of downstream projects in production.

Those downstream projects are depending on 3.0.4 releases of projectX. Meanwhile, in projectX, just yesterday some features landed on the master branch that necessitated a version bump to 3.1.0-SNAPSHOT (and subsequent 3.1.0 release).

Today, an issue is identified in projectX that is disrupting one of the downstream projects.

The fix

We’ve captured the issue affecting projectX, a developer was assigned, and produced a fix with a unit test. A pull request is opened targeting the master branch of the project which has been reviewed and merged.

So to get this contribution into a release, if we do nothing else the next available release version from the master branch will be 3.1.1.

The problem

For a downstream project that was depending on 3.0.4 of projectX, having to upgrade to 3.1.1 to get the necessary fix introduces risk.

What if that new feature is unstable? What if that new feature requires refactoring, or configuration changes? We don’t want the potential to fix one bug and introduce another.

Enter maintenance branches.

Path to a 3.0.5 release: Start with a maintenance branch

  1. Start with a clone of the projectX repository, with a remote to the primary repository (referenced as upstream from here on out). Start on the master branch.
  2. Make sure your master branch has the fix: git pull upstream master
  3. Grab all refs that exist in the primary repository: git fetch upstream.
  4. Checkout the very last tag in the 3.0.x series: git checkout -b maintenance projectX-3.0.4
    • Note that this command creates a new branch named maintenance that originates from the tag projectX-3.0.4. If we just checkout the tag, the subsequent maven command will fail because our working copy is in ‘detached HEAD’.
  5. Use the following maven command to create the maintenance branch: mvn release:branch -DbranchName=rel-3-0-patches -DupdateBranchVersions=true -DupdateWorkingCopyVersions=false[1]

When this command completes, you’ll see a couple things have happened.

  • You will have 2 local and remote (the repository listed in your pom’s scm block) branches: maintenance and rel-3-0-patches.
  • A commit will have been added to both of those branches that changes the version element of the pom to the version you were prompted for (3.0.5-SNAPSHOT here) and a change to the tag element the scm block in the pom that references the rel-3-0-patches branch.
  • An additional commit will exist on the maintenance branch to revert that commit; feel free to either delete the maintenance branch, or re-use it for later maintenance branch creation.

Release from the maintenance branch

Now we have a good branch to apply our original code change and make a maven release:

  1. Find the SHA-1 id of the commit containing the fix. If the fix is spread across multiple commits, you’ll need the ids of each commit, and you’ll have to repeat these commands for each one in the order they were applied. Pro tip: squash bug fix pull requests to one commit to save yourself some time.
  2. git checkout rel-3-0-patches. Double check you are up to date with a git pull upstream rel-3-0-patches.
  3. Cherry-pick the commit: git cherry-pick ab423786...
  4. Create a pull request for the commit targeting the upstream’s rel-3-0-patches branch.
    • Alternatively, if permissions and team workflow allow, you could just git push upstream rel-3-0-patches. I prefer the pull request, because it allows our Continuous Integration server to confirm the merge is successful and the tests all still pass.
  5. Run the standard maven release: mvn release:prepare && mvn release:perform.

During the prepare phase, you’ll be prompted to release 3.0.5-SNAPSHOT and increment the version of the pom to 3.0.6-SNAPSHOT. It’s important to know that the change to the tag element in the scm block will result in that version bump commit landing on the rel-3-0-patches branch upstream, rather than master (that would be bad).

Without the mvn release:branch

This process can be replicated without the mvn release:branch command, however you MUST make the changes to the pom (changing version to [patch+1]-SNAPSHOT, changing the scm.block) that that command does, or else your maven release will be performed on master and pushed upstream.

That is bad, because now master, which was 3.1.X, now goes back to 3.0.X, and you’ll need to do some major surgery or manual changes to the pom to get back to 3.1.X series. No one likes to see a messy git history like that!

Automating Release Management with Gradle and Jenkins

In this post I’ll describe a practical approach to automatically publishing releases of your Gradle managed project using some custom tasks and a Jenkins plugin.

This post was updated on July 15, 2016, edits are inline.

Background

I have a long history and extensive experience with Maven. I feel really strongly that release management is incredibly important and powerful for a project, and a lot of our related processes depend on the Maven Release Plugin.

We are working Gradle more and more into our projects. There are still a few Maven plugins and constructs I pine for, but making headway in finding equivalents, sometimes superior.

Here are a couple of user stories describing what we desired:

As a contributor to a software project
I want the continuous integration job testing my contribution to remind me to increment the version
so that I don't forget 
and artifact release processes work correctly.
As a custodian for a software project managed with Gradle
I want contributors to the project to be required to increment the project version
so that I can remove the overhead of tracking 'fix versions' down after the fact 
and I can see immediately the impact of the change, be it patch, minor feature, or major refactor.

Basically, we want to implement Semantic Versioning, but we don’t want to add a whole ton of human labor to make it happen. We have Jenkins for Continuous Integration, let’s figure out a way to take the repetitive tasks of incrementing the version, tagging, uploading artifacts to Nexus, and a bit of rule enforcement.

Google searches for “gradle equivalent of the maven release plugin” don’t really turn up a clear winner. As I use Gradle more, I think that’s the point - they leave a lot of things to your own creativity.

Idea

Since we don’t have a clear plugin to just start using, our idea started like this:

  • 2 CI Jobs in Jenkins
    • Job 1: pull request builder. Our institution uses gitlab, so we are using Gitlab Merge Request Builder Plugin.
      • The Jenkins ‘Merge before build’ step MUST come first. We won’t get a chance to peek at the version property in build.gradle before merging the contribution.
      • In order to get the ‘last released version’, let’s use a tracked text file (Java Properties file format) in the repository. we can execute git describe.
      • The gradle command we want the builder to invoke will be gradle clean confirmProjectVersionIncremented test. confirmProjectVersionIncremented doesn’t exist, we’ll write a task for that.
    • Job 2: poll the master branch of the primary repo, uploadArchives when commits land.
      • This will fire essentially after a pull request is merged, which means we’ll have a new version in build.gradle.
      • First, run gradle clean bootRepackage uploadArchives to ship our jar to Nexus.
      • Then use the Git Publisher post-build step to push the commit, tag and push the tag to the primary repository.

Implementation

The tricks are these fragments, in your build.gradle:

Summary

So far so good.

One drawback we’ve observed so far: you will regularly need to rebase your branches if there is a lot of activity happening in the project. If development is coming in at a trickle, one at a time, nothing iss going to land on master in between you branching and submitting your pull request, no conflicts. But if others are merging at the same time, it’s likely the commit from the job on the master branch that advances the version in build.gradle is going to conflict with your branch.

Update July 15, 2016

A recent edit to the gist shows a simpler way to calculate the previous version using git describe. This is a big improvement, we don’t have to have that dance around the project.last file.

The gradle-git plugin lets us embed git instead of having to shell out, and a Java implementation of the Semantic Versioning spec gives us an easier way to do the math comparing version numbers.

Combining Spring Boot with Bower dependencies

In this post I’ll describe a technique we recently employed to split a site in half, then re-assemble for deployment.

We’ll start with the Spring Boot runnable jar providing a REST API. With a few Maven tricks, we can combine that jar with a static site retrievable via bower, and end up with a new shippable Spring Boot runnable jar with both.

This post was updated on July 14, 2016, see the follow up at the bottom.

Background

We have this site we are working on that has 2 discrete areas of focus:

  • Integration with one of our institution’s data sources
  • A single page application user interface for viewing and managing that data

Pretty run of the mill business application. This is a green field project, with each one we get a chance to find a more efficient way to work.

My team is composed of 2 sub-teams (front-end for presentation, back-end for integration), each specializing in the areas of focus described above. We wanted the back-end team to be able to work in the way they are familiar, and likewise for the front-end team.

We decided to use Spring Boot for the integration project, with Gradle and Java. We wanted to use AngularJS for the front end, but use npm and bower instead.

We also wanted to experiment with a way for the front end team to be able to work without having the overhead of the Spring Boot project. The larger question we wanted to answer:

Is there a way for the front-end team to work in the site using their familiar tool chain and not have to adopt the tool chain that the back-end team uses?

Project Structure

We have two git repositories, one for the back-end using Gradle and Spring Boot, and one for the front-end using Node for a local web server and Bower for dependency management.

The analogues we’ll use are spring-boot-sample-tomcat for the back-end and angular-seed for the front-end.

Workflow

Back end team works dutifully in the back-end project. These folks have JDK, Gradle, and an IDE. They write unit and integration tests. The only “front-end” for this application is a Swagger UI if they need to do any end-to-end testing.

Front end team works dutifully in the front end of the site. They don’t need to have the same IDE installed, nor do they need a JDK or Gradle. They work in text editors like Sublime or Atom. Changes they make to the site are picked up immediately, no waiting for a gradle bootRun to re-compile classes and run unit tests.

Node is running superstatic-with-proxy for two reasons:

  1. Angular’s html5mode requires that the server be capable of rewriting/forwarding requests to Angular routes back to /index.html.
  2. We need the REST API provided by the back-end to be served from the same domain, the -proxy fork of superstatic gives us the ability to do that.

The front end developers can proxy the deployed REST API environment of their choice. The back-end team also publishes a docker image for local development if they need something that’s not deployed.

Assembly for deployment

The teams have working releases of their repositories, now we need to stitch them together for deployment.

I’ve shared a git repository demonstrating how this works:

https://github.com/nblair/spring-boot-plus-front-end

What happens when you run mvn package on this thing?

  1. maven-dependency-plugin fires first, downloading the Spring Boot jar from our Artifact Repository. It then unpacks the jar to the specified <outputDirectory> (best to nest this under ${project.build.directory}).
  2. frontend-maven-plugin fires next. If it hasn’t downloaded node for your system, it will (under ${basedir}/node/). Then it will run npm install (really just to get bower), then it will run bower install. bower.json declares a dependency on our front end project, and now we have a copy sitting in ${project.build.directory} next to the back-end project.
  3. Then, during the prepare-package phase, the maven-resources-plugin has 3 executions:
    1. Copy the bower_components (which was generated by the bower install in step 2) folder from the front-end site into META-INF/resources/bower_components in the outputDirectory of step 1.
    2. Copy the rest of the assets of the front end project site (excluding bower_components) into into META-INF/resources in the outputDirectory of step 1.
    3. Copy any beta specific configuration into the project (root of the classpath).
  4. Now sitting on the filesystem is an exploded Spring Boot jar with our assets from the front end site piled into it. The last plugin to fire is the maven-jar-plugin, with a few bits of custom configuration:
    • classesDirectory is set to be the root of our exploded Spring Boot jar.
    • A manifestFile - the original from the Spring Boot jar - is explicitly declared. If we don’t do this, the maven-jar-plugin will create one on it’s own that’s missing the properties Spring Boot expects.
    • The compress flag MUST be false. Spring Boot jars contain jars (inside the lib directory), Spring Boot won’t start properly if these jars get compressed.

Now you have a new Spring Boot jar, composed of both projects and environment specific configuration. Ship this jar to your deployment environment. If you use docker for deployment, use the following Dockerfile:

FROM java:8
COPY target/spring-boot-plus-front-end-*.jar /usr/src/spring-boot-plus-front-end.jar
EXPOSE 8080
CMD ["java", "-jar", "/usr/src/spring-boot-plus-front-end.jar"]

URL Rewriting

You may not have to do this, but if your front-end site uses Angular’s $locationProvider.html5Mode(true) you’ll need Spring Boot to handle forwarding requests to your Angular routes to /index.html (or whatever the root of your site is).

There is a great project called UrlRewriteFilter that will give you what you need.

You’ll need to add a Spring @Configuration class to your back-end project, here is a gist. You’ll also need to provide a configuration file, I’ve provided a commented example in the spring-boot-plus-front-end project.

Questions

The natural question (I myself even asked):

Why didn’t you just put the front-end assets in src/main/resources/META-INF/resources for the back end project?

We’ve done this before, and it’s got a negative impact on the front-end team. The projects they work on use a completely different tool chain.

The front-end team doesn’t have to wait for the back end unit tests to complete, or a full build. They can just run npm start and their front-end app is up and running. No restarts even after a git pull upstream to catch latest merged changes. Using superstatic-with-proxy allows them to encapsulate the back end.

Another question:

Instead of stitching the 2 projects together, couldn’t you just deploy both?

The answer to this is yes. Running the 2 services could give you some resiliency - you’d still be able to deliver content even though the back end of the application is down. Deploying this way would require some magic to get the 2 services running on 2 different ports to be presented by 1 port. You’d need some sort of intermediate layer, like a load balancer or apache with mod_proxy.

superstatic-with-proxy isn’t a good choice for deployment, because in the latest version at time of writing, an HTTP request to a proxied path will cause node to shutdown with an error if the proxied server is offline. That behavior defeats the purpose of trying to mimic the developer’s proxy setup in production.

Summary

So, with this approach, can the front end work in the tool chain of their choice and not have to adopt the tool chain of the back end team? It has been a bit tricky to get to this point, but we believe so. We will continue to experiment, and try to apply this same approach to other projects.

Having one deployable out of the multiple separate sites is nice, simple to deploy. We think it is worth experimenting with deploying the two constituent projects, but there is some complexity there we aren’t quite sure how to resolve.

Experience

I’ve written about our experience with this project structure, make sure to read Follow up to ‘Combining Spring Boot with Bower dependencies.

Internal Applications Activity, October 2015 - March 2016

This is a report I produce every 6 months to take a look at the activity of my team. For additional background, see my previous article on Visualizing Collaborative Development .

Here is the output from Gource on the combined activity across 119(!) projects between October 2015 and March 2016:

Areas of Interest

  • You will notice there are 2 distinct areas of activity; at start, and quickly moved to the right, is the existing Internal Applications team. At about the 5 second mark, you can see a hub of activity drift to the left. That activity is that of our sibling group, the Java section of the WaMS (Web and Mobile Solutions) team. Our teams are joining forces.
  • Much of the work done by the WaMS-Java team focuses on projects related to Curricular and Academic Operational Data Store (CAOS). Gource only shows the files that are touched in the time period. The longer lines present in projects there indicate deeper nesting of filesystem projects, which is a sign these projects are quite large in size.
  • In the middle of October, wisclist-custom-interim was added, but has had no activity since that date.
  • Knowledgebase continues to be isolated (lower right, 15 second mark onward). I have not yet succeeded in getting the priority and resources to help in that large project. Continues to have lots of volatility.
  • At the end of November (20 second mark), the assets for a legacy project named Itemmaster were imported (shown in purple).
  • In the middle of December (30 second mark), the assets from the site financial.doit.wisc.edu were imported (also in purple).
  • In early February, 2016 (1:00 mark in the video) we bootstrapped the new techstore project by importing a customized fork of magescotch, a development environment using Scotchbox for Magento 1.9 and 2.0 development.
  • In early March (1:10 mark in the video), we upgraded the Magento 2.0 tree in the techstore project from a pre-release version to the (at the time) latest 2.0.2 release. There have been 2 patch releases since we have yet to apply.

My Takeaways

  • There is a noticeable higher velocity in this video over the last period. Compare the first 15 seconds of this to the original video. This is really encouraging to me for a number of reasons:
    • Our developers are becoming savvier not just with git but the overall workflow; pull requests, branching, merging, rebasing. Not that they weren’t already, but less learning of the tool and more just using of the tool is apparent.
    • Units of work are generally smaller in size and more frequent. We are breaking up work better and avoiding the huge contributions of code that are hard to understand.
  • I intentionally segregated the projects of the WaMS team this time, since our merger is in progress. I can’t wait to see what working together over the next six months will be.
  • While these visualizations are really good at showing the human collaboration connections, I think they are lacking in showing how these projects actually relate to one another. The connections between projects - how they radiate out from the center - is superficial and a side effect of how gource works and my approach to getting gource to run on the history of multiple projects. I’m craving something that actually shows compile/runtime/deployment dependencies across the portfolio.

I originally intended to produce this annually, but 6 months appears to be a better mid-point to reflect. The source material used to create this video can be found at https://github.com/nblair/internal-apps-visualization.