*

2008 / June 9th/ Quick & Dirty: Add changesets since last deploy for your Rails apps with Lighthouse

One of the most common problems for me is knowing when I last deployed my apps, and what I’ve done since then. I often will leave an app on the side for a month or two at a time, and there’s a good chance I implemented some new fix, waited until a low-traffic time to deploy and subsequently forgot. I end up in a state of not really knowing what’s up with the deploy.

So I finally sat down and hacked together a quick ‘System’ screen in my apps. Here’s an example:

Example from Clipgarden's Admin System screen for Clipgarden (rendered in Fluid.app)

It tells me:

  • How long it’s been since the last deploy
  • The currently deployed revision
  • Changes committed to the repository that are not yet deployed

This has been pretty awesome for me so far as it’s a really easy way to figure out if a certain fix or feature has been deployed yet (ever given the answer “well it’s committed, but not deployed”?).

Setup

In order for this code to work, you’ll need a Lighthouse account, and set it up to pull in changesets from your repository. I personally do this through Github since it’s just so damn easy. I won’t go into how to do this since there’s plenty of tutorials out there.

The Code

You’ll need to add the lighthouse api to your lib/ folder and then the following code should get you going. This code also assumes you’re using Capistrano or Vlad for your deployment so that a REVISION file is created in your root folder. If it doesn’t exist, there’s no harm done — but you won’t be getting any results.

Note that this also makes this fix a little hard to test in development since the whole idea is that it’s deploy-centric. I’d recommend copying down an old REVISION and throwing it in your rails root (but don’t commit!) for testing.

New model: system.rb

class System

  @@lighthouse_account = "ACCOUNT_NAME[CHANGE]"
  @@lighthouse_token = "BEACON_TOKEN[CHANGE]"
  @@lighthouse_project_id = PROJECT_ID[CHANGE]

  @@revision = nil
  def self.revision
    return @@revision unless @@revision.nil?
    if File.exists?(RAILS_ROOT + "/REVISION")
      @@revision = IO.read(RAILS_ROOT + "/REVISION").to_s.strip
    else
      @@revision = "unknown (in development mode)"
    end
    @@revision
  end

  @@deployed_at = nil
  def self.deployed_at
    return @@deployed_at unless @@deployed_at.nil?
    if File.exists?(RAILS_ROOT + "/REVISION")
      @@deployed_at = File.mtime(RAILS_ROOT + "/REVISION")
    else
      @@deployed_at = Time.now
    end
    @@deployed_at
  end

  @@lighthouse_project = nil
  def self.lighthouse_project
    return @@lighthouse_project unless @@lighthouse_project.nil?
    Lighthouse.account = @@lighthouse_account
    Lighthouse.token = @@lighthouse_token
    @@lighthouse_project = Lighthouse::Project.find(@@lighthouse_project_id)
    @@lighthouse_project
  end

  def self.changesets_since_deploy
    return [] if self.revision == "unknown (in development mode)"
    all_changesets = lighthouse_project.changesets
    changesets_since = []
    all_changesets.each do |changeset|
      break if changeset.revision == self.revision
      changesets_since << changeset
    end
    changesets_since
  end

end

Get the changesets in your controller

def index
  @changesets = System.changesets_since_deploy
end

Build a simple view

<h1>System Status</h1>
<p>The system was last updated <%= distance_of_time_in_words(System.deployed_at, Time.now) %> ago with revision <%= System.revision %></p>

<% unless @changesets.empty? %>
<h2>Changes made but not deployed</h2>

<div class="metabar">
  <p class="secondary"><%= @changesets.size %> changeset<%='s' unless @changesets.size == 1%></p>
</div><!-- /.metabar -->
<table>
  <tr>
    <th>Change</th>
    <th>Commited At</th>
  </tr>
  <% for changeset in @changesets %>
    <tr>
      <td class="small">
        <%= changeset.body_html %>
      </td>
      <td>
        <%= changeset.changed_at.to_formatted_s(:admin) %>
      </td>
    </tr>
  <% end %>
</table>
<div class="metabar">
  <p class="secondary"><%= @changesets.size %> changeset<%='s' unless @changesets.size == 1%></p>
</div><!-- /.metabar -->

<% else %>
<p>No changes!</p>
<% end %>

Downfalls

There are a few downfalls to this quick & dirty approach. The most noticeable is that each and every one of your requests to this system page make an API call to Lighthouse. However, so long as you put this page in the admin section of your site, you should be fine. In a perfect world, we’d cache the results locally.

Have fun and let me know if you have any improvements, or any way to add this into some kind of useful distributed form (plugin?).

6 Comments

comments feed

  1. Gravatar
    Kyle

    June 9th | #

    Nicely done. I have to say though, I’m much more impressed with your admin page for Clipgarden–usually admin pages for homegrown software are ugly and unusable, but it looks like you actually took the time to make yours look nice!

  2. Gravatar
    Kyle

    June 9th | #

    Yeah, I do have a thing for designing administrative interfaces (I really love them), plus I find the more effort I put into the admin system, the more I end up caring about the site. Hopefully one of these days I’ll finish off some of my thoughts about building admin interfaces into an article.

  3. Gravatar
    Chris Lloyd

    June 30th | #

    <%= pluralize(@changesets.size, ‘changeset’) %>

  4. Gravatar
    Erickson Juricks2Web

    July 7th | #

    yeah… thanks for the post dude it helps a lot…

  5. Gravatar
    web pixy

    July 17th | #

    Very good post, your idea is great! I also have problem with remembering what I had done since I last deployed an application but you found a good way of solving that:)

  6. Gravatar
    eedcfa

    July 20 | #

    ???????? ????. ????? ???? ??????? ?????? ? ??? ?? ??????? ??????? ???? ??? ??????? ????? ??? ????? ? ????????, ??????? ???? ?? ????? ????. ?? ????? ????????? ??????? ??? – veselajaferma.ru ??? ?????? ?? ???????? ???????! ???, ??? ??? ????? – ??? ???????? ??????? ? ?????????? ????: ??????? ????? ? ??????? ????? 2 ????????? ?? ???? ????????? ? ???????? ? ???. ? ????? ????????? ??? ????????? ?????????? ?????? ???????? ?????? ? ??????? ????? ????????????! http://veselajaferma.ru/

Make a Comment

don’t be afraid, it’s just text

Comments are parsed with Markdown. Basic HTML is also allowed.