Sample Code for the Mingle API Using Ruby on Rails ActiveResource

by Matthias Marschall on June 12, 2008 · 0 comments

We use Mingle for managing our agile software development process and found some repetitive tasks which we wanted to automate.

As part of our deployment to the test environment, we had to manually move all “ready to deploy” stories to status “deployed on test env”. With every release to production, we had to move them all again from tested to done. Then, we carefully copied all story numbers and titles to a Release Notes email, which was sent out to all interested parties within our company. Not exactly a lot of hassle but we did it often enough (and found it boring enough) to think about automation.

Mingle 2.0 provides a complete RESTful API, so I started to play around with it using Ruby on Rails ActiveResource (Mingle supports version 2.0.2 only). As the Mingle API documentation states, you must first enable HTTP Basic Auth for Mingle. Afterwards, it’s very easy to get started.

Just require 'activeresource' in your ruby file (or, as I did, in the Capistrano task) and define the ActiveResource for a Card:

class Card << ActiveResource::Base
    self.site = "http://#{user}:#{password}@mingle.yourdomain.com/projects/#{project_shortcut}/
end

Now you can use the Card resource e.g. to create a new card:

card = Card.new
card.name = "Hello World"
card.cp_status = "open"
card.save

Pretty simple, huh? Note the cp_, which prepends the status. cp_ stands for "custom property" and you have to use it whenever you want to access one of the custom properties you created. Name, in contrast, is a built-in property and can be addressed directly.
After this pretty simple warmup we can try to come closer to our goal - getting rid of the tedious manual status changes and writing standard emails. Let's start with changing the status. We need to automate the following steps:

  • Get all Cards, which are currently in status "tested"
  • Change the status property of every card to "done"
  • Save the Card

    We've already seen how to set the status and save the Card. So the only interesting part here is setting the Cards' status set to "tested". The straight forward approach, which is independent of your setup, uses a filter for getting the desired Cards like so:

    cards = Card.find(:all, :params => { :filters => ["[status][is][#{status}]"]})
    

    Since this call is a little tricky, let's dissect it:

    ActiveResource provides you with finder methods very similar to what you are used to from ActiveRecord. But instead of conditions we need to pass a params hash to tell Mingle what we are looking for.
    In our example, we pass a filter. You know filters from the right pane of your Mingle screens where you can select the property, the comparator and the value you are looking for.
    The filters parameter is an array of Strings, each one describing one filter criteria. This String looks like a set of arrays but it's actually a simple String (this really confused me in the beginning until I took a closer look). Within that filter String you separate the property, the comparator and the value with brackets: "[property][comparator][value]".
    Such a String is the basic building block for the filters array. Of course, you can use variables inside the String, like I did in the example above, with #{status}. Combining multiple filter criteria is as easy as adding multiple Strings to the filters array. Every String follows the exact same pattern. You can just look at the Mingle UI to find out what to put there once you got the pattern.

    Another way of getting the Cards you need is to use a saved view through the API. We have a "Current Iteration" view with the following filters set

    [status][is not][discarded]
    [Type][is][(any)]
    [iteration][is][#{current_week}]

    To get all Cards shown in this view you can use the following call to your ActiveResource:

    cards = Card.find(:all, :params => { :view => "Current Iteration"})
    

    It's as simple as that!

    Now that we have all the cards we need, we can simply loop through them and change the status:

    cards.each do |card|
        card.cp_status = "done"
        card.save
    end
    

    As we want to send a mail containing all card numbers as well as their names (titles) I came up with this:

    release_notes = ""
    cards.each do |card|
      release_notes << "#" << card.number.to_s << ": " << card.name << "n"
      card.cp_status = target_status
      card.save
    end
    

    Now, I simply take the release_notes string, stuff it in an email and send it:

          subject = "Release live!"
    
          unless cards.empty?
            Net::SMTP.start('#{mail_host}','25','#{XXXXXXX}','#{mail_user}','#{mail_password}', :login) do |smtp|
              smtp.open_message_stream("#{sender_email}", array_of_receipient_emails) do |f|
                f.puts "From: #{sender_email}"
                f.puts "To: #{release_note_recipients.join(", ")}"
                f.puts "Subject: #{subject}"
                f.puts
                f.puts "The following Cards are done:"
                f.puts
                f.puts release_notes
              end
            end
          end
    

    I embedded all that code into a capistrano task and call that task from within after_deploy and after_migrations hooks:

      after 'deploy', :roles => :app do
        mingle.track_deployment
      end
    
      after 'deploy:migrations', :roles => :app do
        mingle.track_deployment
      end
    

    These few lines of code, together with the great powers of Capistrano, give me a complete "one command" release!

    Did you enjoy this article? Please subscribe to the RSS Feed to receive updates on Agile Methodologies & DevOps.

  • Related Posts

    Leave a Comment