I’ve been rewriting my dashboard project recently and I wanted to find a way to programatically shift through traffic light colors to inicate the status of code coverage coming out of sonar.
CSS3 introduced HSL(Hue-Saturation-Lightness). When you shift hue from 0-120 it goes from red to orange to yellow to green. Perfect for an indicator.
I’m multipling by 1.2 to make 100% result in a hue of 120 which is green, 0% will still be 0 which is red.
I really want 50% and below to be solid red and then start shifting to green as coverage goes up. I can get that by subtracting 50 from the percentage. I also need to multiple by 2.4 and take the max of that value and 0.
I’ve been playing around with some JavaScript to make a build dashboard that can pull data from Jenkins or Bamboo. I’ve been using testem w/ jasmine to TDD my way through this experiment. I stumbled across this refactoring twice. I don’t remember where I picked this technique up from, but I thought it was worth writing up in anyway. The premise is simple. The type of build (bamboo or jenkins) will continue to creep up and cause me to write if statements that look like this.
12345
if(type==jenkins){// do jenkins stuff}elseif(type==bamboo){// do bamboo stuff}
The first time this came up it was to because the json urls for the two build systems are different. I wanted my users to be able to just go to a normal build URL and copy and paste that into the config instead of figuring out what the RESTful url would be. The second time I came across it was so that I could create a single object from either response that would have the same attributes. This would let me do something like data.total_tests regardless of if the build data came from jenkins (totalCount) or bamboo (successfulTestCount + failedTestCount). So let’s get into the refactoring.
First we start with the initial test for bamboo:
12345678910111213
it("should parse the bamboo data into a build data object",function(){// use a spy so we don't use a live ajax requestspyOn($,"ajax").andCallFake(function(options){options.success(bamboo_response);});varbamboo_build=dashboard.groups[0].builds[1];bamboo_build.refresh();expect(bamboo_build.data.failed_tests).toEqual(6);expect(bamboo_build.data.total_tests).toEqual(1053);});
This causes us to write a simple solution that parses just the bamboo data and returns a new build agnostic data object:
it("should parse the jenkins data into a build data object",function(){// use a spy so we don't use a live ajax requestspyOn($,"ajax").andCallFake(function(options){options.success(jenkins_response);});varjenkins_build=dashboard.groups[0].builds[0];jenkins_build.refresh();expect(jenkins_build.data.failed_tests).toEqual(3);expect(jenkins_build.data.total_tests).toEqual(199);});
This causes us to write the simplest solution, which is an if block on the build type:
Now that our test are green we can refactor to get rid of the if block. I like to take it one step at a time, starting with bamboo. We extract the parsing logic into a method on the type object for bamboo.
After that baby step, the tests should still pass and we can move on. We can completely blow away the if block in handle_response_data and just call the parse_raw_response on the type object.