Monday, June 23, 2014

Git: Keeping a clean master branch

Since moving to Git, I'm loving the power. I feel safe. Once changes are committed, no matter what I do, I won't lose anything. And within reason I can later edit history to tell the story I want it to tell.

In our team, we use the commit messages from our master branch to automatically generate release notes. To achieve this the master commit history need to stay pretty clean. Ideally one commit per feature.

We therefore have been working on feature branches and squash merging them to master once they pass code review.

We use Atlassian Stash for code reviews. When a code review is accepted it does a merge to your destination branch. Stash doesn't do a squash merge, or use our commit comment, so we can't have it automatically commit to master. If we don't accept the review though, all we can do is leaves the code review open or marks it as abandoned.

To avoid this we make a review branch from master and review the feature onto that. Stash can then merge it once the review passes... so it's happy... then the developer manually squash merges the review branch to master, so we are happy.

This was working fine, until we needed a feature to branch from another feature mid development.

The downside of squash merges, is that the master doesn't know the changes came from a branch. This means :-

  • If you branch from feature A, 
  • then feature A makes more changes to the already changed files 
  • and feature A commits to master first 
  • when you merge to master, it looks like the changes you inherited are conflicting with the committed files. 

This is a real pain.

To get around this... we have started to use a common "integration" branch. (instead of the review branches)

  • A developer branches from integration, 
  • does changes... 
  • then reviews back to integration. 
  • Once accepted and merged, the developer then squash merges integration to master, 
  • and then merges master back into integration. 

This final merge is easy as the code is the same, and tells Git that these branches align at this point. This means that later "squash merges" onto master keep working without merge conflicts. Also any branches committed to "integration" retain all history, so they merge nicely too.

This looks like this:

Happy Coding.

Wednesday, April 30, 2014

Making Moq Better...

I love Moq.

If I need to code in C# it's my favorite mocking framework. My favorite feature is that you can set up your mock behaviour, then after your test has performed an action you can _then_ make assertions on what should have happened.

This ability lets you follow the Arrange, Act, Assert pattern for test construction.

To my mind the only thing that breaks this is the "strict" mocking type. A Strict mock will throw exceptions when a non "setup" method is called. If you want to assert that no interactions occurred with an object, this this is a way of doing it.  However... you construct your mocks in your setup method, and forcing this to be a decision you make up front means it has to be true for all your tests... even the ones where you don't care.

Even worse, say you "setup" some behaviour, but then don't want it called as a result of a specific test, then you have to explicitly "verify" all the methods you don't want called. This seems really odd.

Anyway... To help with this I have written an extension method to verify no methods are called on an object.

This useful, but is only a step in the right direction. Ideally you would be able to specify all the interactions you do want to occur, and finish by saying "and nothing else".

Thursday, January 23, 2014

Vagrant, Docker, and Proxy Servers

I was trying to get a Docker VM running on windows at work using the tutorial, but kept getting "Unable to connect to"... In my case it was the proxy server.. and I found a simple fix.

* Open  the Vagrantfile
* Add a like after "$vbox_script = MMVBOX_SCRIPT + $script
* Type "export http_proxy="

Ok this got me a bunch further... but not all the way.  Now the Guest Additions module is failing to install.

Wish me luck.

Wrong Vagrant

I was getting messages to say the virtualBox guest additions didn't match the version of virtualbox. So I upgraded VirtualBox. Then I got messages saying Vagrant didn't support that version of Virtualbox.

OK .. Another rookie mistake. I was running vagrant from the gem (v1.0.4). I've uninstalled the gem 'gem uninstall vagrant' and downloaded the msi. The MSI version is v1.4.3.

So far so good....

Wednesday, July 31, 2013

Help! How can I ensure I get the encoding right?

I've been struggling with character encoding.
Some tests in our suite use strings like this "100µl" or "N°". The problem was, these tests were getting corrupted as they get pushed into Quality Centre. I found a work around through trial and error, but someone must know why this works.
Here's some experiments. I saved the following "µ°" in 3 files. One is ANSI, one UTF8 and one is "ANSI as UTF-8" (so Notepad++ tells me). Then run the following code:

# encoding: utf-8

utf8 ="files/utf8.txt", external_encoding:"UTF-8")
aautf8 ="files/ascii_as_utf8.txt")
ascii ="files/ascii.txt")

puts "UTF8   >> " + utf8
puts utf8.encoding.names.inspect

puts "AAUTF8 >> " + aautf8
puts aautf8.encoding.names.inspect

puts "ASCII  >> " + ascii
puts "ASCII  >> " + ascii.bytes.pack("U*")
puts ascii.encoding.names.inspect

This produces the following (assuming you are in windows with ruby 2.0 and Lucida font and you whispered the magic incantation "chcp 65001"
UTF8   >> µ°
["UTF-8", "CP65001", "locale", "external"]
AAUTF8 >> µ°
["UTF-8", "CP65001", "locale", "external"]
ASCII  >> ��
ASCII  >> µ°
["UTF-8", "CP65001", "locale", "external"]
So I guess my question is:- How are you supposed to load a file and get it to appear correctly? And secondly... that last line... was that a fluke? Also.. How do you tell if the file is loaded correctly or not?

Make Your Function Work Like a Collection

tl;dr; Kernel#enum_for  lets you treat your method like a collection.

I was iterating over the files in a folder, looking for those with a specific file extension. I had something like this...

  def for_all_files(f, e, &block)
    Dir[f+"/*"].each { |file| 
        for_all_files(file, e, &block)
      else if file.end_with?(e)

Now I'm sure Ruby provides a better way to achieve this, but it worked for me... until I found I was filtering this list again in the block I was passing in.

  for_all_files(source_folder, ".ts") do |file|
    if(path_filter =~ file)

What I wanted was something like this:
  files(source_folder, ".ts").
    select{|file| path_filter =~ file}.each do |file|

Well as per usual Ruby 2.0 has already thought of that.
  def files(folder, ending)
    def for_all_files(f, e, &block)
      Dir[f+"/*"].each { |file| 
          for_all_files(file, e, &block)
 if file.end_with?(e)
    enum_for(:for_all_files, folder, ending)

Note the enum_for. It takes a symbol for a method name and a set of arguments. It returns an Enumerable that encapsulates your method.  I really like the result of this but I don't like the code. If you know a better way, let me know. Post a comment telling me how I should have written it.

Also.. I think this means I can also make it lazy like this...
  files(source_folder, ".ts").
    select{|file| path_filter =~ file}.
    each do |file|


On a similar theme I was wrapping up a COM API that has iterators using Count and Child(x) methods. With you can easily wrap these to expose a clean ruby API.
  def child_folders(folder) do |y|
      (1..folder.Count).each {|i| y << folder.Child(i)}

GitHub Projects