Wednesday, October 31, 2007

Liberate yourself from the evil transparent menubar

In Leopard, of course. Get it here!

Using Git with Lighthouse

I wanted to set up Git integration with Lighthouse. The requirements for this was a bit different from the regular SVN integration, since in SVN every commit goes to a central repository, while Git is distributed. For the projects we wanted to integrate with Lighthouse, we use a shared Git repository which acts like the "main" repos. So when our local commits and changes gets pushed to the main repos, we want it to send a new changeset to Lighthouse, which should include the commit messages of all the new revisions since the previous push. A bit more complex than the Svn use case, but luckily Git provides some nice tools that made it quite easy. Google told me that some other guy made something similar a few days ago. However, his solution uses a post-commit hook, and thus sends every single commit to Lighthouse. Which wasn't acceptable for us, since we do a lot of small atomic commits localy. And it works against one of the nicest Git features: quick and easy branches for experimenting, since all the experimental commits would have been exposed to Lighthouse and filled up the overview screen. Summed up, we wanted to be able to make multiple local commits, and then send them as a "revision bundle" to Lighthouse and the main repos.

I solved this by setting up a both post- and pre-receive hooks on the main repos. I suspect that the pre-receive hook can be avoided, but I did the simplest thing that could possibly work. The pre-receive hook saves the current (pre-push) revision to a temporary text file, so it can be used by the post-receive hook. The post-receive hook runs a Ruby script. Most of it is taken from the script in the earlier link. The coolest line goes like this:


commit_log = `#{GIT} rev-list --pretty=short "#{oldrev}..#{newrev}" | git shortlog`


It sums up each authors commits, and shows the commit messages from each of the commits. (You can see this in action on the screenshot at the top of this post) Perfect. The script isn't as complete or elegant as it should be, but it works for now. I will edit it if I come up with something better. If anyone else makes improvements to this script I would love to hear about it (please leave a comment here, or ship me an email)!

Pre-receive hook: http://pastie.caboo.se/112536
Post-receive hook: http://pastie.caboo.se/112535

Tuesday, October 30, 2007

Choosing a project management system

Last week we were starting up a couple of small projects for some clients. I saw that as a great opportunity to review our choice of project management system. We were currently using Retrospectiva, a open source rails project. It does the job okay, but it isn't exactly very pretty, and the usability kinda sucks. This is supposed to get improved. Anyway, letting clients into Retrospectiva just didn't feel right. Oh, and currently Retrospectiva only supports subversion. And since we've transitioned completely to Git, thats a problem for us.

So I went looking for a substitute. I looked a bit at a new Rails app named WhoDoes. Its pretty cool, and I really wanted to like it since its extremely cheap compared to Lighthouse. It wasn't quite "it" tho. The biggest problem: it lacks a very basic PM requirement: knowledge capture. You really need to have an external wiki or something, since it doesn't even have simple pages/messages like Lighthouse. But I bet this app will improve in the future, so it's something to look out for. So we ended up with Lighthouse, which has a really really beautiful UI. And it's dead easy to use: everything is a ticket. Client-safe, and a whole lot more fun to use than Retrospectiva! We even got Git integration working, which I will write about next.

Saturday, October 27, 2007

Leopard: First impressions

Alright, so Leopard has arrived! On Friday I wiped the harddrive of my MacBook and eagerly installed my new OS. I this post I will present some of my thoughts about it, based a couple of days usage.

The good:

  • It's very convenient that so much quality software ships with the OS. Built-in svn is nice even tho I prefer Git, since a lot of projects use it. I really wanted the Ruby support to be good. But it turned out that I pretty quickly had to change it with a custom install via MacPorts. The built in Ruby simply refused to install the ruby-postgres gem. I gave the exact same params to extconf.rb with the custom Ruby in place, and it just worked. I had to install PostgreSQL 8.2 from source by the way, since the port for it is broken at the moment. Its still very nice that the OS ships with a up to date Ruby tho.
  • Spaces are cool, even tho I don't like everything about their behavior. I really want to disable the animated gliding that occurs when you change between spaces.
  • The new finder feels much better to use.
  • Safari have gotten a bunch of updates as well, I especially like the new search function.
  • Its faster than Tiger.
The bad:
  • Transparency which you cant turn off. God, I hate transparent windows.
  • The new terminal isn't as good as expected. I switched back to iTerm pretty quickly.
  • The new dock is way too heavy on the eye candy for my taste.
The ugly:
  • A lot of port breakage, but thats to be expected I guess. And most of them get fixed really quick.

Thursday, October 25, 2007

A note on UTC support in Rails

I was doing some work on Bitswiki yesterday, and figured it would be a good idea to store time data in UTC. I thought this was as easy as uncommenting the "config.active_record.default_timezone = :utc" line in environment.rb, but this was not the case. The models' created_at fields still got populated with my local timezone, even tho Rails claimed it was in UTC. I was quite puzzled. It turned out that it was as easy as adding this to environment.rb (or into its own file in /config/initializers):


# Make Time.now return time in UTC
ENV['TZ'] = 'UTC'


Maybe this should have been set implicitly by the default_timezone setting, as you probably want the two in conjunction anyway?

Wednesday, October 17, 2007

Creating a simple news publishing system in Rails 2.0

In this tutorial we will create a simple news publishing system. We'll also take a look at some of the new Rails 2.0 features, like namespaced routes. Note that I wont do any testing in this tutorial, due to the limited scope. However, I recommend downloading the latest RSpec screencasts over at http://smartic.us/, to keep up-to-date on the latest testing techniques. Please note that this is my first attempt at writing a tutorial of this kind, so bear with me. Hopefully my writing will improve over time.

As usual, we'll start with creating a new project (I assume that you have Rails 1.2.5 installed). You might want to freeze to the latest edge version, but note that this is not required for completing this tutorial. Type this into your shell of choice:

rails newsmachine
rake rails:freeze:edge (optional)


Now we're ready to roll. Lets set up our database and create some models:


cd newsmachine
./script/generate model newsitem header:string author:string body:text
rake db:create:all
rake db:migrate


Note that in Rails 2.0 we don't have to specify the created_at/updated_at fields; they are automatically created for us by default. Nice. The new database creation raketasks are also very handy, but note that you probably have to do a little editing on your database.yml file first. I run PostgreSQL, so I had to change the adapter setting. Now we have a database ready, so lets try to create a admin interface. We will use the new namespace routing for this purpose.

./script/generate controller 'admin/newsitems' index new create
./script/generate controller newsitems index


Note that we create two different NewsItems controllers, with two different responsibilities. This helps us partition our code nicely into two clearly defined places. We avoid the "one controller to rule them all"-syndrome, since we get one controller for public consumption and one for admin-only stuff. Now lets delete the public/index.html file, and boot up our server:

rm public/index.html
./script/server



Lets add some routes into our routes.rb file:

map.root :controller => "newsitems"

map.namespace :admin do |admin|
admin.resources :newsitems
end


We are now ready to start writing some actual code. The first thing that we should be able to do, is creating new news items. Head to app/controllers/admin/newsitems_controller and enter the following:


def index
@newsitems = Newsitem.find(:all)
end

def new
@newsitem = Newsitem.new
end

def create
@newsitem = Newsitem.new(params[:newsitem])
@newsitem.save!
redirect_to :action => :index
end


This is pretty basic, but good enough for our example. Now over to index.html.erb, still within the admin scope:


<h1>Administration</h1>

<%= link_to "Create new news item", new_admin_newsitem_url %>

<hr />

<ol>
<% @newsitems.each do |n| %>
<li><%= n.header %></li>
<% end %>
</ol>


Try this out by putting your browser over to http://localhost:3000/admin/newsitems/. If it works: yay! If not, maybe you missed something. Or maybe my explanations just sucks. Let me know, leave a comment. Now lets create some news items. new.html.erb:


<h1>Create a new news item</h1>

<% form_for ([:admin, @newsitem]) do |f| %>
<%= label(:newsitem, :header, "Header:") %>
<%= f.text_field :header %>


<%= label(:newsitem, :author, "Author:") %>
<%= f.text_field :author %>


<%= label(:newsitem, :body, "Body:") %>
<%= f.text_area :body %>


<%= submit_tag "Create!" %>
<% end %>


The new form_for functionality is really nice. When we give it a ActiveRecord-object, it automatically identifies the correct paths etc. As you would expect, it also supports namespacing when we pass it an array. Another sleek 2.0 feature is builtin http-auth. Yep, plain old simple basic HTTP-authentication. Its a perfect fit for password-protecting small sites like this. First, add a before-filter to the admin controller (app/controllers/admin/newsitems_controller):


before_filter :authenticate


Then add the authenticate-method (put the code in as the last method in your controller):

private
def authenticate
authenticate_or_request_with_http_basic { |u, p| u == "admin" && p == "1234" }
end


There you go, a fully functional login-system written in one single line of code. Not bad. Go ahead and test it!

Ok, now we have a semi-functional admin interface without updating and deleting (but hey, at least we have auth!). Not bad! Lets implement a public view. Head over to index.erb.html for the regular newsitems controller (app/controllers/newsitems_controller):


<h1>Newsmachine gives you the news!</h1>
<%= render :partial => "newsitem", :collection => @newsitems %>


We need a partial, so create a new file called _newsitem.html.erb and enter this:


<div style=\"background-color: <%= cycle("#aaa", "#eee")%>">
<h2><%= newsitem.header %></h2>
<%= simple_format(newsitem.body) %>

<i>Written by <%= newsitem.author %> on <%= newsitem.created_at.to_s(:long) %></i>
</div>


Check it out, we now got a working site. There is a lot of stuff we could add from here, like Atom-feeds, image support, etc. I might write a part two of this, so any suggestions are greatly appreciated.