Jake Ginnivan's blog

GitVersion v3.0.0!

Today GitVersion v3.0.0 has been released. For me it has been a long time coming, with 4 beta releases and incorporating a lot of feedback between each release. It all started with this pull request which replaced the existing approach of each git workflow being hard coded with a class responsible for calculating each branch type.

This meant that GitFlow and GitHubFlow had completely separate code paths with very little shared, it also meant that things like commit counting varied on different branches. v3 changed all that and now is entirely driven by configuration. This initial pull request weighed in at 78 commits, 196 files, changed 2,500 lines of code and deleted another 700. 106 pull requests later we are shipping.

This configuration based approach has been really important for a number of reasons:

  1. Understanding/documenting what GitVersion is doing.
  2. When we had bug reports of a version being incorrectly calculated there was never a generic fix.
  3. The logic for every branch was different and inconsistent. Then GitFlow and GitHubFlow worked quite differently in some respects
  4. It was hard to get GitVersion to work with nightlies and publishing CI builds to NuGet
  5. This meant that getting GitVersion working with Octopus deploy was not great

A number of long standing bugs were fixed with the changes made in v3, some of the highlights of the new features

  • GitVersion init is a configuration tool which allows you to make GitVersion work the way you want it to
  • Decent documentation!
  • Configurable version incrementing
  • Better error reporting - when things go wrong (which should be a lot less often now) we try to give you decent information including:
    • Dumping out a cleaned git history graph which you can paste into an issue so we can reproduce the issue
    • Logging out all decisions and sources for versions

Whats next

There are a few features which will be released in 3.1 which will make GitVersion nicer to get started. v4 hopefully will be not too far down the road when we rethink the command line usage and fix a few other things which have got a bit complex over time.

Give it a go

All the links you need are on our GitHub page at https://github.com/GitTools/GitVersion#gitversion

ReactJS Popout Window

Recently I had a requirement to have a chat history panel which could be popped out into it’s own window and that window needed to have live updates. I figured I had two ways of doing it, I could open a new window which initialised itself and had it’s own connection to the server to get updates or I could keep with the React way and have the components which pop out simply flow updates to the window via props.

The component which needs to support popping out is the ChatHistory component which takes a set of items which get rendered.

1
<ChatHistory messages={this.props.chat.messages} />

A simplified implementation looks like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class ChatHistory extends React.Component {
  constructor(props) {
    super(props)
    this.popout = this.popout.bind(this)
    this.state = {
      poppedOut: false
    }
  }

  popout() {
    this.setState({ poppedOut: true });
  }

  render() {
    return (
      <div>
        <Graphicon style= icon='popout' onClick={this.popout} />
        {this.props.messages.map(msg =>
          <div>
            {msg.date}
            <pre>{msg.text}</pre>
          </div>
        )}
      </div>
    )
  }
}

Next is how do I pop this content out. First I create a PoppedOutChatHistory component:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class PoppedOutChatHistory extends React.Component {
  constructor(props) { super(props) }

  render() {
    return (
      <div>
        {this.props.messages.map(msg =>
          <div>
            {item.date}
            <pre>{msg.text}</pre>
          </div>
        )}
      </div>
    )
  }
}

Then I introduced a Popout react component into the ChatHistory render function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
render() {
  if (this.state.isPoppedOut) {
    return (
      <Popout title='Window title' onClosing={this.popupClosed}>
        <PoppedOutChatHistory messages={this.props.messages} />
      </Popout>
    );
  } else {
    return (
      <div>
      <span style= onClick={this.popout} className="buttonGlyphicon glyphicon glyphicon-export"></span>
        {this.props.messages.map(msg =>
          <div>
            {msg.date}
            <pre>{msg.text}</pre>
          </div>
        )}
      </div>
    );
  }
}

popupClosed() {
  this.setState({ poppedOut: false });
}

The Popout component is quite simple, when show is set to true then it will render the content in a new popout window. The nice thing about having this as a React component is that the Popout window’s lifecycle is tied to the lifecycle of the owning component. So when the History component is unmounted the Popout will close the popup it might have had opened.

Summary

I am pretty happy with the result of this Component, I can continue to flow props and handle events. For instance if I wanted to pop up a input form:

1
2
3
4
5
6
7
8
render() {
  return (
    <Popout title='Window title' onClosing={this.popupClosed}>
      <input type='text' onChange={this.textChanged} />
      <input type='button' onClick={this.submit} />
    </Popout>
  );
}

Source and install

npm install react-popup –save

Source on GitHub

Improving the Carnac Codebase and Rx Usage (Part 3)

Parts one and two have covered the InterceptKeys class which exposes a feed of raw keyboard events and the MessageProvider which turns key presses into messages to display on the screen. There is a class between those two, the KeyProvider which I am not going to actually blog about as it doesn’t introduce any new concepts which I have not covered in parts 1 and 2 of this blog series.

Part 1 - Refactoring the InterceptKeys class
Part 2 - Refactoring the MessageProvider class
Part 3 - Introducing the MessageController class
Part 4 - Removing state mutation from the stream

Instead we will dive into the MessageController class which brings the streams from the KeyProvider and MessageProvider together then maintains the list of Messages displayed on the screen. The requirements are:

  • Add any new messages into the messages collection
  • After 5 seconds set a flag on the message which triggers an animation
  • 1 second after that the message is removed from the messages collection
  • If a message is updated the 5 second countdown should start again.

Old implementation

The previous implementation was quite simple but it was hard to test. Also Rx can solve this problem very nicely, so why not.

  • New messages were added to the messages list
  • A timer fired once a second, the callback did:
    • A foreach loop over every item which had a LastUpdated property more than 5 seconds go, then set the IsDeleting flag to true
    • A foreach loop over every item which had a LastUpdated property more than 6 seconds go, then removed it from the list

Lets rewrite this into Rx

Improving the Carnac Codebase and Rx Usage (Part 2)

This post is the second part in a series covering a series of improvements in the carnac codebase, specifically to improve the usage of Rx. The next class I will be rewriting is the MessageProvider.

Part 1 - Refactoring the InterceptKeys class
Part 2 - Refactoring the MessageProvider class
Part 3 - Introducing the MessageController class
Part 4 - Removing state mutation from the stream

As a bit of background, in carnac a KeyPress is not directional and it also contains information about if modifiers were pressed at the same time. For Instance ctrl + r would be a KeyPress. A Message is what is shown on the screen.

The message provider as it is does the following:

  • Is IObserver<KeyPress>
  • It aggregates multiple KeyPresses into logical messages with the following rules:
    • Shortcuts are always shown in their own message
    • If there has been more than a second between the last keypress a new message is created
    • If the key presses were entered into different applications a new messsage is created
  • Apply ‘Only show shortcuts’ filter

Here is what the code looked like before the refactor.

Improving the Carnac Codebase and Rx Usage (Part 1)

Carnac is an open source project created as part of Code52. It is a simple utility which overlays key presses on your screen as you type which is pretty handy for presentations. Carnac also ships with some keymaps for different applications so it understands when you are pressing shortcuts.

Recently Scott Hanselman blogged about a Quake Mode console and mentioned carnac, this triggered Brendan Forster and myself to think about carnac again. When we started writing carnac there was not any Rx experience amongst the team and we did a pretty bad job. I think carnac is a great Rx problem and the code can be improved to take advantage of Rx and be a really good non-trivial Rx sample. This blog series is all about the things we did wrong and the process I went through to refactor carnac into a much simpler code base and really leverage the power of Rx.

Part 1 - Refactoring the InterceptKeys class
Part 2 - Refactoring the MessageProvider class
Part 3 - Introducing the MessageController class
Part 4 - Removing state mutation from the stream

My Typical TeamCity Build Setup

I posted Simple Versioning and Release Notes a few weeks ago talking about how to simplify release notes and versioning. This post is a bit of a cheat sheet for how I set up my builds.

Structure

I normally have two but sometimes three builds for each project. The structure is something like this:

  • TeamCity Project
    1. CI
    2. Acceptance/UI Tests (optional)
    3. Release

1. CI builds the solution with correctly versioned assemblies (update assembly info files with version before build), runs all unit tests then creates any packages which are required. This includes NuGet packages, Chocolatey packages, zipped binaries, clickonce installers etc. This build monitors pull requests and is triggered automatically when there are new commits/branches.

2. Acceptance/UI Tests is an extra I use when I have long running or UI tests, for example TestStack.White on TeamCity (sign in as guest) has this build setup and it runs Whites UI tests. The reason I separate it is for speed reasons, I want my CI build to fail fast and only if it is successful do I run this slow build. This build triggers whenever 1. CI succeeds

3. Release (or 2. Release if there is no acceptance/ui test build) is run manually and it releases the artifacts build by 1. CI, if that is a NuGet package it is pushed to NuGet.org, chocolatey packages get pushed to chocolatey.org, zip files get pushed as a GitHub release etc. Once this build succeeds it should tag the VCS root and push that tag.

Updating Chocolateys Release Notes With GitReleaseNotes

Today I saw a tweet from Rob Reynolds today that Chocolatey 0.9.8.24 RC1 was released so I clicked the link which was straight to the closed issues list on GitHub.

I also noticed that many of the RCs and betas were not tagged in Git so you can’t see what was fixed each beta.

I have been working on a little utility to solve exactly this problem called GitReleaseNotes, the idea is that you install it via Chocolatey, then run GitReleaseNotes /outputFile ReleaseNotes.md /allTags and it will connect to your issue tracker (if the issue tracker is a REMOTE in your Git repository) fetch all the closed issues since it was last run and append them into your release notes. For public GitHub repos using GitHub issues these are the same so it just works, for Jira and YouTrack you will need to specify additional command line parameters

You then can manually edit, group and do whatever you want. All your modifications will not be changed when you run GitReleaseNotes again.

Using Approval Text in Tests

Using Approval Text in tests

I am currently using TestStack.BDDfy as my BDD testing framework. v4 has some great changes which make BDDfy really really awesome.

One of the things I am testing is generated confirmation text based on a number of selected form inputs. I want the approved generated text to be put into the BDDfy output. First steps are to read the approved file, here is a quick snipped which does this:

protected string GetApproved()
{
    var namer = new UnitTestFrameworkNamer();
    var basename = string.Format("{0}\\{1}", namer.SourcePath, namer.Name);
    var approvalFilename = new ApprovalTextWriter(string.Empty).GetApprovalFilename(basename);
    var approved = !File.Exists(approvalFilename) ? string.Empty : File.ReadAllText(approvalFilename);
    return approved;
}

Then I can just add my step in BDDfy .Then(_ => ApprovedGeneratedConfirmationShouldMatch(sut.DealSummary.ToString()), string.Format("Approved generated confirmation should be:\r\n{0}", GetApproved()))

Low Friction Octopress/GitHub Pages Setup

My blog uses Octopress which is basically Jekyll plus a whole bunch of plug-ins preconfigured and it is hosted on GitHub Pages. But sometimes I really miss being able to simply create or edit posts online. I started looking around and found Prose.io.

Prose is an awesome open source online Jekyll site editor for GitHub. Then if we setup TeamCity to automatically regenerate and deploy our blog when we make any commits we have a really simple way of making quick blog posts online.