Tuesday, March 07, 2017

Writing plugins for Octopus

Following on from my previous post about writing plug-ins, here’s the next installment of what may or may not become an irregular feature.

I’ve been using Octopus Deploy at work for several years now, and it is a great tool for automating the deployment of software; in my case, it turned a 20-page manual checklist that took 40 minutes to work through into a five minute fire-and-forget exercise. However, there are still little steps here and there that can’t be automated out-of-the-box, and that’s where we pick up our story.

We track our work-in-progress using JIRA, and one of those tedious post-release tasks is to update all the tickets, setting their status to Released and so on. So, given that JIRA exposes an API, and Octopus supports custom steps or step templates written in Powershell, why not combine the two and cross another manual step off the list?!

Show me the code!

Actually, I’m not going to post any code snippets this time – rather, I’ve published the source code to GitHub (something else I’m learning, after 15 years of Subversion), so go ahead and fork it. There’s not a whole lot of error handling in there at the moment, but it seems to do the trick. There are two files:

  • the original Powershell file, which you can open up and run in the Powershell IDE;
  • the Octopus Deploy step template, which wraps up the Powershell in a bit and parameterises it to make the code more reusable

Tuesday, February 14, 2017

Writing plugins for Exceptionless

Exceptionless is one of those tools that no developer should be without; it integrates with your application (currently .NET and NodeJS platforms are supported, with the promise of more to come), captures your unhandled exceptions, and provides you all sorts of tools to manage these exceptions.

The project itself is open source, and you can set up your own on-premise server to run the service, or you can use their cloud service if you don’t want the hassle of maintaining YADS (Yet Another D**n Server).
Their support is also very good; I’ve been working on a number of different scenarios (e.g. creating custom reports using the API to query for data, at least until they implement custom dashboards). The scenario that prompted this post was simple – when we deploy a new version of our API, we run a suite of automated regression tests to make sure we haven’t broken anything for our customers, but these regression tests include a large number of expected failure tests, which result in a large number of false positives being reported. So time to break open the coding tools and fix that…

Show me the code

The Exceptionless client provides a number of extension points, and after talking to Blake Niemyjski, who seems to be the main point of contact for enquiries, I whipped up the following plugin:
[Priority(5)]
public class SquelchExpectedExceptionsPlugin : IEventPlugin
{
    public void Run(EventPluginContext context)
    {
        var exception = context.ContextData.GetException();
        var httpContext = context.ContextData.GetHttpContext();

        if (ApiExceptionClassifier.IsAnExpectedException(exception, httpContext.Request.Headers))
        {
            context.Cancel = true;
        }
    }
}

internal static class ExceptionlessExtensions
{
    internal static HttpActionContext GetHttpContext(this IDictionary<string, object> data)
    {
        if (!data.ContainsKey("HttpActionContext")) return null;
        return data["HttpActionContext"] as HttpActionContext;
    }

    internal static Exception GetException(this IDictionary<string, object> data)
    {
        if (!data.ContainsKey("@@_Exception")) return null;
        return data["@@Exception"] as Exception;
    }

I had to add the extension methods as these are currently internal to the Exceptionless.Net library, while the ApiExceptionClassifier is a bit of business logic which checks for a specific header the the request to determine what sort of HTTP status code a given exception should result in (e.g. we want all ValidationExceptions to result in a 400 Bad Request). The plugin priority needs to be set to a low value so that it gets executed as early as possible – there’s not much point in gathering all sorts of data if we’re just going to throw it all away when the Cancel method gets called.
Once that was done, all that is left is to register the plugin in the API’s startup routine:
ExceptionlessClient.Default.Configuration.AddPlugin<SquelchExpectedExceptionsPlugin>();
And now, my regression tests don’t fill the Exceptionless reports with noise, unless an actual exception occurs during the process.

Back from hiatus

It’s been quite a while since I last posted, so it’s probably about time I got back into the habit. More to follow shortly!

Monday, September 10, 2012

Surrealism

I can’t believe I’ve never heard this joke before today, but it makes me smile:

Two penguins are sitting on an ice floe, drifting helplessly north into warmer waters. The penguins are quite fond of each other, but they don’t speak English very well. Suddenly, cra-a-a-a-a-ck, the ice floe splits in two, right between the penguins. As they drift apart, one penguin sadly waves a flipper and calls out, “Chocolate milk!”.

Happy Monday!

Friday, August 17, 2012

NDoc3 - a modern-day Lazarus

Back in the early days, the nDoc utility was the go-to solution for auto-generating API documentation for .NET applications. The build engine would parse the XML comments that the developer decorated class members with, and nDoc would take those results and produce MSDN-style web pages based on it. As an open source product, it attracted quite a following.
However, with the release of .NET Framework v2, nDoc failed to make the jump and instead imploded, being at the time quite a high-profile example of the risks of running an open source project:
  • the community might love your product, but if they don’t contribute something back (whether code, time or money) then it may not be possible for you to continue to develop it;
  • the vendor whose environment you are working in (in this case, Microsoft, but it could easily be another company. Apple, anyone?) can move into your space and deliver something that is good enough to draw mindshare away from your target audience. Actually, Sandcastle has never really been as good as, nor as easy to use as, nDoc, but the damage was done;
Fast-forward to the near-present time, and while Sandcastle continues to be unwieldy, the open source community is once again picking up the nDoc baton, this time in the form of nDoc3. In its current state, nDoc3 brings to the table support for .NET 3.5, but if you’re prepared to download the source code and build it yourself, you can get .NET 4 support as well. Of course, Microsoft moved the goalposts slightly this week with the release of .NET 4.5, so the cycle continues!
If you do want to try getting .NET 4 support, these are the steps that I had to go through (and a few hoops that I needed to jump through):
  1. Download the source code from Sourceforge, and extract the tarball to the file system;
  2. Rather than opening in VS2008 as the README file directs, I fired up VS2010;
  3. Building threw up a whole host of warnings, so I decided to try the provided NAnt build scripts;
  4. Building threw up a whole host of warnings, mostly about missing NAnt targets; in the end, I had to hack the NAnt.build file to pieces, first commenting out the references to the JavaDoc, Latex and LinearHtml documenters which, though references in the build file, don’t exist in the source code; I also had to comment out all the code related to testing, as again it referred to folders and/or files that don’t exist;
  5. I also needed to remove a duplicate AssemblyVersion attribute from Core\AssemblyInfo.cs;
  6. This at least allowed me to compile and run the application; however, when I tried to get it to document one of my own pieces of code, it quickly threw an exception which I traced back to an already-reported issue; fortunately, the user who raised the issue also submitted a patch, which while it has not been applied to the source tree, at least fixes the problem.
So now I have nDoc3 happily spitting out documentation for me; perhaps if time allows, I will look into writing a Wiki-format documenter.

Thursday, August 02, 2012

That didn't take long

I've been a devotee of the Sparrow mail app for Mac since it first came out. Its clean interface and seamless integration with GMail put it head-and-shoulders above Apple's own Mail application.

Unfortunately, those days are numbered - Google's recent acquisition of Sparrow is a near-guarantee that the application will receive no further work, beyond promised bug fixes. The timing couldn't be worse - with Apple having just released OS X Mountain Lion, there are bound to be problems with third-party applications, and it seems that Sparrow is already showing some.

I've been finding the UI locks up on me when composing or sending emails; labelling emails I want to keep isn't happening, nor is the deleting of emails that I don't. I can receive emails OK, so it's not a problem with my network or account. Quitting the application tends to cause it to hang, until I kill its process with extreme prejudice. And it's not just me who's seeing this:



All in all, the sort of experience that third-party developers would be rushing to fix; but with Google now calling the shots, how quickly will this happen? I'm not holding my breath.

Meanwhile, in the interest of actually Getting Things Done, I'm making do with Mail again.

Friday, January 27, 2012

A nice little trick with FluentAssertions

I love using FluentAssertions when writing tests for my code, it just makes the code so expressive in plain language. Recently I’ve been working on tests which involve the testing of lots of properties on a test result, and was looking for a way to remove a lot of the repetition involved.

Usually when asserting the properties on a test result, you can do it in three different ways. If I have my test class defined as below:

[TestFixture]
public class MyTestFixture
{
    private MyClass _subject; 
    private MyOtherClass _result;
 
    [SetUp]
    public void ExecuteTest() 
    { 
        _subject = new MyClass(); 
        _subject.Initialise(/*.. Some parameters here ..*/); 
        _result = _subject.SomeOperation();
    }
}

Then I can test the results as follows:

A. Assert all the properties in a test method

    [Test]
    public void ThePropertiesAreSet()
    {
        _result.First.Should().Be("Paula Bean");
        _result.Second.Should().Be("Brillant!");
    }

This is probably the usual way people do this. However, if the first test fails, the second test will never run, and we'll never know if our test method set the second result correctly or not, so we are lacking information as to the overall state of the test. Secondly, as the number of properties to test increases, you end up with a lot of visual noise, although Intellisense will at least take some of the effort out of creating the noise.

B. Assert the properties in a test method per property

    [Test]
    public void TheFirstPropertyIsSet()
    {
        _result.First.Should().Be("Paula Bean");
    }
 
    [Test]
    public void TheSecondPropertyIsSet()
    {
        _result.Second.Should().Be("Brillant!");
    }

With this approach, we now know if the setting of _result.Second was successful, even if _result.First failed. This extra information does come at the expense of more visual noise (the addition of another test method). Also, it allows you to really game the system if you get rewarded for the number of tests in your project :-)

C. Implement IEquatable

As the number of properties on MyOtherClass go up, you'll find a lot of code appearing in the test method. You can remove this by implemeting IEquatable<MyOtherClass> on MyOtherClass:

public class MyOtherClass : IEquatable<MyOtherClass>
{
    public override bool Equals(MyOtherClass other)
    {
        return this.First == other.First && this.Second == other.Second;
    }
}

(please note you should also really implement Object.Equals and Object.GetHashCode if you're going to use IEquatable, and for brevity, I've missed out a lot of the basic implementation of IEquatable<T>)

The result of this is that our test method now becomes:

    [Test]
    public void TheFirstPropertyIsSet()
    {
        MyOtherClass expected = new MyOtherClass { First = "Paula Bean", Second = "Brillant!" };
        _result.Should().Be(expected);
    }

Much cleaner and very expressive, and you'll probably find your code benefits elsewhere from having implementations of IEquatable<T>; but you do have to write that implementation (and perhaps unit test it too!). Yet more code...

This finally leads me to my point:

D. Use anonymous classes and FluentAssertion's AllProperties

How's this for simplicity?

    [Test]
    public void TheFirstPropertyIsSet()
    {
        _result.ShouldHave().AllProperties().EqualTo(new { First = "Paula Bean", Second = "Brillant!" });
    }

ShouldHave().AllProperties() does all the hard work of checking the properties. You can also use SharedProperties() if you only need to test a subset of the properties, and add IncludeNestedObjects if you have a more complex object model.

P.S. I love the story of the Brillant Paula Bean. It confirms all your prejudices about contractors.

Wednesday, January 11, 2012

Adobe Lightroom 4 Beta is out!

Adobe Lightroom 4I’m looking forward to this. I’ve been a user of Lightroom since it first came out as version one, and it’s been indispensible for managing my growing photo collection (I passed the 10000 mark last year).

I’m particularly excited by the long-awaited introduction of proper geocoding support. I bought a GPS logger a year or two ago, and use Dirk Stichling’s My Tracks to add geotag my photos prior to importing them into Lightroom. When I export from Lightroom to iPhoto, the geotags are picked up and displayed nicely in the Places section of iPhoto (and on the iPhone and iPad). However, this only works when importing photos – existing photos cannot be geotagged. Jeffrey Friedl has written a plugin for Lightroom that achieves this, after a fashion, but I prefer my metadata to reside within embedded metadata, rather than in shadow files which are then written on export; and although My Tracks is a good application, I would prefer to have fewer steps in the overall process.

Of course, the ideal would be for Canon to release an accessory that geotags photos when they are taken, but for the moment, they seem to be preferring to take the third-party route.