Showing posts with label maven. Show all posts

Configuring Gradle publishing with AWS S3

Using S3 as a remote maven repository can provide a cost effective alternative to some of the hosted solutions available - admittedly you won’t get tooling like Artifactory sitting on top of the repository, but if you are used to using your own privately hosted remote maven repositories, then the S3 solution is a good option if you want to move it off premises.

Thankfully, the more modern versions of Gradle come with good support for AWS built in - if you are using Gradle pre-version 3 or so, then some of these may not be available, but given we are approaching Gradle 7, then it’s probably a good time to upgrade your tooling.

Out of the box, publishing to an S3 bucket is incredibly easy, but of course, you will want to secure your bucket so its not open for the world to push their artifacts to - and Gradle combined with the AWS SDK make this pretty simple.

If you want Gradle to push to S3 using the normal profile credential chain (checking env vars before using default credentials etc) then its really easy:
The above approach, running gradle publish will attempt to publish the artifact to a maven repo in the named S3 bucket, and will look locally on the host machine for AWS credentials - this will require that you have default credentials set.

Now this might not always be ideal, if for example you are running on a machine whereby you have default credentials set to some other account (not the dev tooling account where you are hosting the maven repo) and you don’t want to have to change the default credentials just to push stuff to maven. As you will have seen in the AWS docs around the profile credential chain, you can override the default profile using an environment variable AWS_PROFILE - which is a possible solution but not ideal for a couple reasons:

  1. Users have to remember to set it if they want to avoid using default credentials

  2. It isn’t very granular - setting the env var at gradle runtime (by exporting/set the variable on the command line before running the gradle command) sets the variable for the entire gradle task(s) being run - there maybe situations where you want finer control and need to use different credentials for AWS for different jobs (I have seen this requirement in real world code)

  3. Dealing with environment variables in Gradle doesn't have great support - some tasks can set them easily, others not so much (publish, for example, doesn’t support it)

Thankfully, there is still a trivial mechanism to override this - although it took me a while to stumble upon this solution - most stackoverflow questions and gradle issue discussions mostly have examples using the environment variables.

The following will use the named credentials “buildtool” on the host machine to publish. Of course, this is a simple string hardcoded, but this could be passed in using other custom arguments, sidestepping the need for env vars if you wanted to override it (create a custom -D JVM argument, for example, to override - which is much more granular and specific to your usage and much better support on Gradle).

Note you also need to import the AWS SDK to use this one:

Eclipse & LESS - Better Development time with Incremental Builds

All source code for this app is on GitHub at the moment - feel free to fork/download/etc

So one of my recent experiments I decided to start playing with LESS (CSS pre-processing, letting you use variables etc in CSS code, which has been long needed) - It's all actually relatively simple (although you can do some nice, powerful stuff with it) to code with if you are coming from an development background, so I found myself quickly getting to grips with basics like defining variables for colour schemes (very basic stuff, but sooooo much better than having to maintain masses of CSS and every time you want to tweak the colour scheme having to search for hex codes..).

However, I found myself wanting to start using LESS on new/existing web app projects which were largely Spring MVC/Java based apps, which was more problematic. LESS requires pre-processing/compilation to generate CSS, which is kind of a pain in the ass when trying to prototype web app projects - being used to just altering some CSS and then hitting refresh in the browser (at most, having to re-load the tomcat server inside  eclipse), having to try and generate the full LESS/CSS files everytime anything changes was not something I was going to be doing.

Thankfully, having done some digging, I managed to get it all setup and working like a charm - Every change I made to the LESS, Eclipse performed an incremental build (like it does for other compiled code like Java etc) and voila! I could just change the LESS and press F5 in the browser.  Here's what I did:

Software

  • Eclipse
  • Maven
  • LESS
  • WRO4J Maven plugin

Directory Structure

As I am using maven, I am of course following the standard /src/main/webapp convention - so that is assumed here.
In the webapp root, I created a new "less" folder, alongside the "css" - This holds all my *.less files - I won't go into detail about LESS here, but assume you will only include valid, compiling LESS files here (non-compiling LESS files will cause you a headache here)



As you can see, in my normal "css" folder I have only included vendor CSS files - I will not be placing any custom CSS here (All valid CSS is also valid LESS, so even if I wanted to just write CSS, I can do in my "less" directory).

Maven Configuration

The incremental build will be performed by the use of a Maven plugin. This will also mean that any formal full build/packaging that you do will also include the LESS compile step.

The below configuration simply defines a "group" that will attempt to compile and the target folders we will generate the artefacts to (more on that later).



We also define a little more confuration regarding what we want WRO (Web Resource Optimizer) to do:

/WEB-INF/wro.properties defines exactly what optimization we want to perform - in this case I have selected some pre & post processing steps:


/WEB-INF/wro.xml defines the location of the source files:


The above config will make Eclipse perform the incremental builds on your LESS files as well as generating a CSS file if you perform a regular maven build.  As can be seen below, Eclipse incremental build has generated a web-all CSS file in the target "css" directory.


Including Generated CSS

The simple part of this is of course to include it in the webpage header as an import - Despite it not being in your /src/main/webapp/css folder, you can still reference it the same as the static vendor stuff we have included as we know it will be generated there for us (either as part of full app build/deploy or incrementally in Eclipse).


There is also another gotcha at this point - You have to check that your Eclipse will be deploying the contents of your m2e-wtp directory to your webapp. This should be happening by default, but you can check (and fix if necessary) by right-clicking on your project in Eclipse and going to "properties".  In the left hand menu, select "Deployment Assembly" - this will show the directories/libraries that will be deployed as part of your application (obviously this only takes effect if you are deploying the app to a server inside of Eclipse).

As you can see below, my Eclipse defaults to deploy /target/m2e-wto/web-resources to the root of the webapp. If yours doesn't just add an entry for this and everything should work!






Footnote:

If you are struggling to generate the LESS files in the m2e directory, then there is a chance you have an compilation problem with your LESS files.  With the incremental build, if LESS compilation fails then it will fail silently - for full details you should run the full maven build to see errors logged.