Wednesday 10 August 2022

Pushover Plugin for IntelliJ

 One of the more annoying problems I face on a daily basis is the slow compile times of my current primary project at work.

To be fair, this is a lot less of a problem than it used to be; prior to our upgrade from Scala 2.11 to Scala 2.13, compilation would regularly take 30 minutes or more. These days, it’s typically around 5 minutes for a full rebuild - still annoying, but hardly as much of a time sink.

However, I do still occasionally have to rebuild old versions, or run the database initialisation task, which does still take a long time.

Wouldn’t it be nice if I could go off and do something else, and get notified (on my phone) once it’s complete?

Sunday 19 June 2022

Eliminating a Joda Time Dependency

 A short time ago, I started work on a new project, which would be based on the Scala Play framework.

Part of this project required some authentication logic, and I stumbled upon the Play Silhouette library. Unfrotunately, this depends on Joda Time, which in 2022 (and, particularly, post the introduction of the Java Time API in Java 8) seems old-hat.

I therefore set about creating a PR to remove Joda Time from this library.  It seemed simple... replace all the uses of Joda's DateTime with a ZonedDateTime from Java Time, remove the dependency on Joda Time, and we're done... right?

Wrong.

Sunday 22 July 2018

Deploying create-react-app on nginx with a separate backend

So... you've followed the instructions here and created your shiny new React app, with its own server-side element. Now you want to deploy it to your Production server, which runs nginx... how will you approach it?

The naïve way

Quick and simple - clone your project, start the server and client services, and point nginx at your client app, same as you did during development.  The "proxy" config in the client app then redirects requests to the backend server.

Does this seem right? I don't think so...

Wednesday 22 November 2017

Windows 10 Fall Creators Update Emoji in the UK

The Windows 10 Fall Creators update had a shiny new feature: hit [Win+]; or [Win+.] and you get a popup appear that lets you enter emoji directly into pretty much any supporting text field, Word document or even your IDE.

However, for anyone without a US keyboard, it seemed that you were stuck... the keyboard shortcut was only enabled for the en-US keyboard layout, so it wouldn't work if your keyboard layout was set to UK or anything else.

However, with a little trickery from this site, I've managed to get it working for the UK keyboard layout, and presumably any other layout you might want to use.

First, find the correct culture code here: https://msdn.microsoft.com/en-gb/library/ee825488(v=cs.20).aspx
I wanted en-GB, which is 0x0809
Then, copy the registry keys for the Emoji keyboard from [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Input\Settings\proc_1\loc_0409\im_1] to your own locale - in my case, [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Input\Settings\proc_1\loc_0809\im_1]

For a UK keyboard, a reg file like this does the job:

Sunday 22 October 2017

iOS 11 Upgrade Woes

iOS 11 is here, and with it the demise of any 32-bit apps that you might have been using. Apple helpfully provides a way to see which apps will stop working before you upgrade - and it was quite a shock to the system when I checked.

Going to Settings / General / About on my iPhone, I see that I have 462 applications installed - clicking that text shows the full list of incompatible applications... 49 in my case! On my iPad, things are even worse; 501 applications, 97 of which will stop working!

Below, I've listed all of these apps, together with my thoughts about what I'm going to do about losing this particular app, and links to my chosen replacements. As you might expect... this is going to be a work in progress, and I'll be updating this post as I go!

Application iPad iPhone Description
12 Days Gift of the day for Christmas.
Action: Defunct, so delete
12 Days (*) Another, similarly named Christmas gift app
Action: Defunct, so delete
1Path Pathfinding game
Action: Delete
300 Workout Workout app based on the film 300
Action: Delete
AA Parking Parking map
Action: Seems to have been merged into the main AA app
Alain Ducasse Recipes
Action: Delete
Amex UK-iPad
Action:
AppGratis Free app of the day
Action: Delete and abandon; these free app services mostly seem to give away apps I'm not interested in.
AppGratis HD Free app of the day
Action: As above... and the few times I have found a useful app, it seems that a week later the company produces a "Pro" version that's a separate purchase anyway!
AppOfTheDay Free app of the day
Action: As above for AppGratis
Beat On Metronome
Action: Neat feature of this app was that it allowed you to tap out a tempo.  Need to find a replacement!
Bookworm Fun letter puzzle game
Action: Delete
Brain Test
Action:
Candy Train
Action:
CloudOn
Action:
CLZ Books HD
Action:
Cockpit Devolo control software
Action: Just use the PC software, sadly
Compass
Action:
Contraptions
Action:
Crazy Raider
Action:
Curiosity
Action:
Debenhams
Action:
DH3
Action:
Eye-Fi Control software for Eye-Fi card
Action: Hardware is end-of-life already, no solution
F1 Challenge
Action:
FarmVille
Action:
Fieldrunners2 Fun tower defense game
Action: Delete
Fit Garmin exercise app
Action: Delete
Flybe Business FlyBe Magazine app
Action: Delete
Flybe Uncovered FlyBe Magazine app
Action: Delete
FrozenLexicon Word puzzle game
Action: Delete
Geared Gear puzzle game
Action: Delete
GearedHD Gear puzzle game
Action: Delete
Giftshare
Action:
Greek Greek Translation
Action: Find a replacement next time I go to Greece
Greenredeem Green loyalty points
Action: Just use the website, I guess
HE Everest
Action:
httpebble Pebble Smart Watch app
Action: This is one of a number of apps that links to my Pebble.  Since the Pebble is discontinued, I've kinda given up on apps for it, which is a shame
iSee Files For Visio
Action:
iSSH SSH, Remote Desktop and Wake-on-LAN
Action: This is my biggest loss, and will need a lot of research to choose a replacement, as most of the good alternatives appear to be paid apps
iWOL Wake-on-LAN app
Action: Will need replacing
Jungle
Action:
Kapow Free HD
Action:
Link Free
Action:
Lync 2013
Action:
Magic 2014
Action:
Mahjong Game
Action: Delete
Metro Phone Edition Newspaper
Action: Delete
MoneyWiz
Action:
MovieCharade Game
Action: Delete
MPG w/Ads Mileage and petrol tracking
Action: Already replaced with Road Trip
My Measures
Action:
MyFitnessPal
Action:
NanoBlockesLite
Action:
NHM Alive
Action:
Node Node.JS interpreter
Action: How this ever arrived on the App Store, I don't know... but it's gone, and I doubt it will ever come back
Num Addict Number Game
Action: Delete
Odeon Magazine
Action:
One Minute Changes Guitar chord training app
Action: Find a replacement, or build my own
OneTuner Multiple radio stations
Action: Delete - I don't listen to radio much anyway!
OnLive Viewer
Action:
Packing
Action:
Paper Zoo
Action:
Paris Metro Paris Metro map
Action: Switch to NaviTime Transit, which seems better anyway
Pebble Faces Pebble Smart Watch faces app
Action: This is one of a number of apps that links to my Pebble.  Since the Pebble is discontinued, I've kinda given up on apps for it, which is a shame
PetrolPrices
Action:
Photobucket
Action:
PhotoMagic Photo effects
Action: Delete
PipeLand Really good water-pipe puzzle game
Action: Sadly, delete it, since the developer seems to have stopped working
PipeLand HD
Action:
Pirates!
Action:
Planetary
Action:
pocket BLU
Action:
PopSci+
Action:
Premier Inn
Action:
PuzzlerWorld2
Action:
Quidco
Action:
RAD Soldiers
Action:
Radiation
Action:
RATP Pure
Action:
Re
Action:
RecipeMark
Action:
ReversiHD
Action:
Rimshot!
Action:
Ringer
Action:
Rokco
Action:
Room Design
Action:
Rosecliff HD
Action:
Sainsburys Loyalty App
Action: Merged into Nectar app
Score!
Action:
Scrobbler
Action:
ShanghaiHD
Action:
Shark Dash
Action:
Shazam
Action:
Six Pack Abs
Action:
Sky News
Action:
Skyrim
Action:
SmartWatch+ Pebble Watch Face app
Action: This is one of a number of apps that links to my Pebble.  Since the Pebble is discontinued, I've kinda given up on apps for it, which is a shame
Solitaire Card Game
Action: Delete
Song Speed
Action:
SpiritLevel Uses iPhone gyros as a Spirit Level
Action: Find a replacement!
Taboo Buzzer
Action:
TapDefenseHD
Action:
Tesco Finder Demo of Tesco API
Action: Delete… and build my own version!
Tesco Food
Action:
The Crib
Action:
TicketScanner
Action:
Timeli
Action:
To-Fu
Action:
toptable
Action:
toptable (*)
Action:
TouchTerm SSH Terminal
Action: Find a replacement
Touchwood Loyalty App
Action: Delete
Travelodge Hotel booking app
Action: Delete, and search again next time I stay there!
TTR Premium
Action:
UltiMaze
Action:
Vlingo
Action:
Voice Translator
Action:
Waitrose Shopping app for Waitrose
Action: Delete
Was That You
Action:
Windowshop
Action:
Word Lens
Action:
Words HD Free
Action:
YO! Calc Yo! Sushi plate counter
Action: Either find a replacement, or build my own
YO! Sushi
Action: Either find a replacement, or build my own
Zombie Dice
Action:
Total 98 49

Sunday 15 October 2017

Simple Score Pad - Released!

Ladies & gentleman, boys and girls, prepare to be astonished, perplexed and... disappointed!

Yes, it's that time - I've finally submitted my first App to Apple for review prior to distribution on the App Store.

Following the lessons of Lean development, it doesn't do much more than act as a simple score pad (yes, the clue was in the name), to save you reaching for pen and paper when you need to keep score in any kind of real-world game.

Happy downloading (when it's approved, of course!)

Update: It's been approved! Download now from iTunes

Sunday 12 March 2017

Aggregating Reports in Multi-Module Maven Projects

With a highly complex multi-module Maven build, it can be very useful to use the Site generation feature of Maven to produce HTML reports for Unit and Integration Test results, as well as code coverage.  This can save scrolling back through pages of console output to try and figure out which Unit Test has unexpectedly failed

However, by default, Maven will produce a separate report for each module, which can mean having to click through many different modules to figure out which one contains the failure - especially when the module Name (shown in the Maven log) doesn't correspond directly to the path where it can be found.

Fortunately, Maven does have some report aggregating capabilities.  Less fortunately, these seem to be poorly documented online - either that, or everyone else figured it out with no help at all!

Module Configuration

I've set up a simple demo project to explore how this can be done effectively.  My scope included the following requirements:
  • Aggregate the Unit Test reports (Surefire) in a single place
  • Aggregate the Integration Test reports (Failsafe) in a single place
  • Aggregate the Code Coverage report (Jacoco) in a single place
Additionally, to match the real-world scenario that prompted this investigation, I wanted to cover the interesting edge case of an "Integration Test Only" module - ideally, failures in this module would be aggregated in with the Failsafe reports, and the aggregated code coverage report from Jacoco would include the coverage from the integration tests.

So, my starting position looks like this:
  • module1
  • module2
  • component-test (depends on module1 & module2)
The next step is to combine these three modules into a single Maven build, and here's where it gets interesting.  It seems that there are two separate principles in play in Maven, which are often conflated into a single implementation: Inheritance vs. Aggregation

The best article I've found on the topic is a StackOverflow answer, which led me to the two possible solutions below:
  • parentAggregate
    • module1 (inherits from parentAggregate)
    • module2 (inherits from parentAggregate)
    • component-test (inherits from parentAggregate, depends on module1 & module2)
or
  • aggregate
    • parent
    • module1 (inherits from ../parent)
    • module2 (inherits from ../parent)
    • component-tests (inherits from ../parent, depends on module1 & module2)
The key difference between these two solutions is the build order.  The parent module is always built before any child modules - so parentAggregate is built before module1 or module2.  However, with the separate parent and aggregate model, the aggregate module is built last, after all modules are completed.  This is quite interesting and important when it comes to creating aggregate reports for Jacoco.

The project I've inherited uses the parentAggregate model, which at first glance seems to be the more elegant solution.  There's no need to specify the relative path for the parent, and the directory structure directly matches the inheritance model.  However, as we'll see, this isn't necessarily the optimal solution when it comes to aggregate reports.

For the rest of this post, I'm going to try and cover both models - highlighting the similarities and differences between the configuration required in each case.  At the end, I'll offer my opinion as to which solution is superior for my requirements, and why.

Executing Tests and Gathering Coverage

Let's start by configuring the Surefire, Failsafe and Jacoco plugins to actually execute the Unit Tests, Integration Tests and Code Coverage during the build.

There are a few things to note here:
  • For the Surefire plugin, there's no need to specify any executions; the defaults work as expected
  • For both Failsafe and Jacoco, if you don't specify the executions, the plugin will not run
  • In the parentAggregate model, this should be added to the parentAggregate module, so it is inherited by each sub-module.  Similarly, in the separate aggregate/parent model, it must be added to the parent model, so it is inherited by each sub-module.
This configuration results in four outcomes during the Maven build cycle:
  • During the test phase, the Unit Tests are executed by the Surefire plugin.
  • While these are running, Jacoco gathers the code coverage and creates jacoco.exec
  • During the verify phase, the Integration Tests are executed by the Failsafe plugin
  • While these are running, Jacoco gathers the code coverage and created jacoco-it.exec
At this point though, we have no reports generated at all; if we want to examine the results of the unit tests, we need to look at each separate TXT or XML file generated by Surefire and Failsafe, and we have no way to read the coverage data.

Basic Reporting per Module

The next step is to configure Surefire Reports, Failsafe Reports and Jacoco Reports for each sub-module.  For now, we're just interested in making it easy to read the reports per sub-module, rather than aggregating the reports.


Again, the points of interest:
  • These are still added to the "parent" module, whichever that is.
  • For speed, I've disabled the default reports - only the index report is generated, which provides the index.html page with the project description.
  • The Failsafe reports are generated by the Surefire report plugin
  • For all three reports, the report is only generated if the relevant raw data exists.  This means that there will be no Jacoco Integration report if there is no jacobo-it.exec file for a module.  
  • Also, since my component-test module has no production classes (it's test only), there will be no Jacoco report for this module either, as there's no way to calculate a percentage coverage without having the original classes to compare to.  Modules that do have both Unit and Integration tests would get both Jacoco reports
At this point, we can easily get separate reports for each module, but we have no visibility of what is covered by our dedicated integration test module, and it's still tricky to find a test failure in a random module.

Executing Maven

A note now on how best to execute Maven.  If you do the obvious mvn clean install site, you will discover that failed unit tests prevent the Site from being generated for that module - so there's no reports to examine!  However, mvn site on it's own will quite happily find the failed tests and add them to the report, but runs the tests a second time anyway.  I've found the best combination is this:
mvn -fn clean verify; mvn -DskipTests site

This ensures all the tests are run (-fn, Fail Never, means that the build will continue on failing Unit Tests, so you can see all the tests that fail, not just the first one), then runs the Site build as a separate task, without re-running the tests.
If your integration tests are particularly slow, you may want to run just test instead of verify.
You may want to add a third step - mvn site:stage - to put the Sites for all the modules into a single location. However, when we get to the point of generating aggregate reports, this becomes unnecessary.

Aggregated Test Reports

Finally, we get to the most interesting part of this post - generating the Aggregate reports.

For Surefire and Failsafe, this is quite easy to achieve.

This needs to be added to the aggregate module - for both the parentAggregate and the separate models, that's the top level module.  When using the separate parent and aggregate, the inherited=false setting is technically not required, but won't do any harm.
This will generate the Aggregate reports when the aggregate module site is built.  When using the separate parent and aggregate, this is the last module to be built, so it could be done as part of a single Maven execution - but as discussed above, it's useful to run a separate build for the Site to catch any Unit Test failures in the reports.
When using the combined parentAggregate model, the parent is built first, so if you try and do this all as one execution, the Aggregate report will be empty, which is one reason some people would prefer this architecture.
In this model, since both the reportSets are set not to inherit, the child modules end up using the default reportSet only, and therefore generating the non-aggregated reports, as we require.

Aggregated Coverage Report

Generating an Aggregate report from Jacoco is, unfortunately, far more involved.  Jacoco provides a target for an aggregate report (report-aggregate), but this target only aggregates the reports for dependencies of the current module.

This gives us two different solutions - one for the parentAggregate model, and one for the separate model.

When using a parentAggregate, the recommended solution from Jacoco themselves is to create a separate reports module.  This module must depend on all the other modules - and, significantly, specify the test scope for Test-Only modules.  This ensures that Jacoco knows how to count lines of code - in Test-Only modules, the execution counts toward coverage, but the code itself does not need to be covered by tests.  The Jacoco Aggregate report is added in the dedicated reports module.

When using separate parent and aggregator modules, the aggregator is built last, so one would think that adding the Jacoco Aggregate report to this module would be sufficient, but alas, Jacoco still needs the dependancies to know the scope of each module.

Therefore, to generate the Aggregate report for Jacoco we must add the following to either the aggregator or the reports module, depending on the model chosen.

In either architecture, the Dependancies of the aggregator or the reports module must be maintained separately for the Aggregated Code Coverage report to continue to be accurate.  This is a burden on maintenance that would be better avoided.
In my opinion, using separate the aggregator module has the advantage here, as the Dependencies can be updated when the Modules are updated, whereas with a reports module, these would have to be updated separately.

Final Conclusions

By executing the Build and the Site generation separately, we eliminate a lot of the confusion around aggregate reports almost accidentally - which may be why the internet as a whole is so quiet on this topic... perhaps most people do these separately by default!

mvn -fn clean verify; mvn -DskipTests site

Generating the Aggregated Test Reports is simple, whichever model you choose to implement.

Generating the Aggregated Jacoco Reports is difficult, whichever model you implement, although the combined parentAggregator does make this slightly worse.

In the end, the best solution is probably to generate the Aggregated Test Reports in Maven, and leave the Code Coverage report to a dedicated tool such as Sonar!