Friday, October 31, 2008

Slideshare

Have you heard of Slideshare? "SlideShare is the world's largest community for sharing presentations."

Interesting idea. Upload and share your powerpoint presentations. Get your very own Slidespace. Mine's at http://www.slideshare.net/nathenharvey.

Here's a one-slide presentation I put together to test out the service. Are you using the service? What's your Slidespace?

Get Real Get A Visualcv
View SlideShare presentation or Upload your own. (tags: myspace facebook)


Thursday, October 9, 2008

Fun with Gmail addresses

You may already know this (I just found out myself) but Gmail supports plus-addressing.

In other words, you can send an email to yourusername+anystring@gmail.com and it'll be delivered to yourusername@gmail.com.

As it turns out, gmail also ignores any periods in the username so your.username@gmail.com will go to yourusername@gmail.com as will y.ou.ruserna.me@gmail.com.

This is a pretty handy!


Thursday, July 31, 2008

Restore the history of a file in subversion

I have a file (some_controller.rb) currently at revision 7744 that was deleted and added in revision 7614.

Deleting and adding a file in the same revision doesn't make a whole lot of sense. I'm pretty sure this was done inadvertently by the developer. In any case, doing so effectively erased the history of the file. Now svn log only shows the changes that have been made since 7614 and svn blame shows the committer of 7614 as the primary editor of the file.

Of course, we always want to accurately place blame...so we'd like to restore the history of the file.

This can be achieved by restoring a previous version of the file and then re-applying any updates to it. One side-effect is that any changes made between the delete/add revision (7614 in this case) and the new revision will be put in as one revision. Though, if you wanted to, I suppose you could work around that by re-applying the changes one by one.

Here are the svn steps I took to restore the history of the file:

svn mv some_controller.rb some_controller.rb.tmp

svn ci -m "temporary move, restoring the history of the file"

svn cp https://mysvnrepo.url/trunk/app/controllers/some_controller.rb --revision 7613 https://mysvnrepo.url/trunk/app/controllers/ -m "revive old version of some_controller"

svn up

svn cat some_controller.rb.tmp >some_controller.rb


svn ci -m "put new revisions back into some_controller.rb" some_controller.rb

svn del some_controller.rb.tmp

svn ci -m "remove temporary file"

Sunday, July 20, 2008

Amazon S3 - Outage

Many sites are currently feeling the pain of an Amazon S3 outage. According to http://status.aws.amazon.com/, S3 has been down since about 9AM PDT today.

Unfortunately, my company's site is one that 's impacted.

The AWS Service Health Dashboard is helpful but I'd prefer something that provides a more proactive notification when there's a service interruption. Something along the lines of an SMS once a service disruption is announced.

Perhaps there's something out there already that I haven't found?

UPDATE: As of 5PM PDT, Amazon is reporting that the system is back to normal.

UPDATE: Here's the latest summary of the chain of events from Amazon. Nice of them to not make every customer email for SLA credit.


Tuesday, July 15, 2008

reset_column_information in cruisecontrol.rb

As I described in a previous post, cruisecontrol.rb was failing with every other build because of the way our migrations were written (more on why they were written that way in a later post).

Today I was able to resolve the issue by adding a new task to our list of tasks that get run when cruise completes a build.


desc 'resets the column info for all models'
namespace :columns do
task :reset => :environment do
ActiveRecord::Base.reset_column_information
ActiveRecord::Base.send(:subclasses).each{|klass| klass.reset_column_information rescue nil}
end
end


Now, our cruise task looks like this:


task :cruise do
['test_env_init', 'db:rollback', 'columns:reset', 'db:migrate','test', 'spec:cruise:rcov'].each do |task|
Rake::Task[task].invoke
end
...


And cruisecontrol.rb is much happier...as is our development team!

Wednesday, July 2, 2008

cruisecontrol.rb fails every other build

Why does cruisecontrol.rb report that every other build fails?

Looking at the log, you see things such as:


NoMethodError: undefined method `referring_friend' for #<user:0x2aaab3936628>
So...where does referring_friend get introduced?

251_add_promo_to_user.rb

class AddPromoToUser < ActiveRecord::Migration
def self.up
if User.table_exists? && !User.column_names.include?('referring_friend')
add_column :users, :referring_friend, :string
end
end

def self.down
if User.table_exists? && User.column_names.include?('referring_friend')
remove_column :users, :referring_friend
end

end
end


OK, clearly this works and we have some additional checks in place. Specifically, don't add the column if it already exists and don't drop it if it's not there. Doing either of these could cause some database errors.

Nice, but we still don't know why it's failing. Let's have a look at what cruise does

custom_cc.rake

...
task :cruise do
['test_env_init', 'db:rollback', 'db:migrate','test', 'spec:cruise:rcov'].each do |task|
...
See the problem yet?

Let's see what's happening in that cruise task.
  • test_env_init - pretty simple, just sets the RAILS_ENV to test
  • db:rollback - runs the down for the latest migration. So in this case we

remove_column :users, :referring_friend
  • db:migrate - runs the latest migrations. So in this case we

add_column :users, :referring_friend, :string
However...we only drop the column if it exists and we only add it if it's not already there

OK, so let's try this in our good friend, script/console:

$ script/console
Loading test environment (Rails 2.0.2)
>> puts User.column_names.include?('referring_friend')
true
=> nil
>> exit
$ rake db:rollback
(in /usr/local/cruise/cruisecontrolrb-1.2.1/projects/release_1_7/work)
== 251 AddPromoToUser: reverting ==============================================
-- remove_column(:users, :referring_friend)
-> 0.1270s
== 251 AddPromoToUser: reverted (0.3239s) =====================================

$ script/console
Loading test environment (Rails 2.0.2)
>> puts User.column_names.include?('referring_friend')
false
=> nil
>> exit
$ rake db:migrate
(in /usr/local/cruise/cruisecontrolrb-1.2.1/projects/release_1_7/work)
== 251 AddPromoToUser: migrating ==============================================
-- add_column(:users, :referring_friend, :string)
-> 0.0739s
== 251 AddPromoToUser: migrated (0.2668s) =====================================

$ script/console
Loading test environment (Rails 2.0.2)
>> puts User.column_names.include?('referring_friend')
true
=> nil
>>

Hmm...that all looks correct. But that wasn't actually a good test of what's happening because we're "Loading test environment" every time we run script/console.

Let's try that again using 2 different sell sessions.

Session 1

$ script/console
>> puts User.column_names.include?('referring_friend')
true

Session 2

$ rake db:rollback
(in /usr/local/cruise/cruisecontrolrb-1.2.1/projects/release_1_7/work)
== 251 AddPromoToUser: reverting ==============================================
-- remove_column(:users, :referring_friend)
-> 0.1799s
== 251 AddPromoToUser: reverted (0.3748s) =====================================

Session 1

>> puts User.column_names.include?('referring_friend')
true

Session 2

$ psql -U cruise_test -d cruise_test_1_7
$ \d users;

*As we expected, there's no referring_friend column on the Uses table

Session 1

>> User.reset_column_information
=> nil
>> puts User.column_names.include?('referring_friend')
false


Ah ha!!

So, if we update our User model after each change, the build should Colt 45 (it works every time)

updated 251_add_promo_to_user.rb


class AddPromoToUser < ActiveRecord::Migration
def self.up
if User.table_exists? && !User.column_names.include?('referring_friend')
add_column :users, :referring_friend, :string
User.reset_column_information
end
end

def self.down
if User.table_exists? && User.column_names.include?('referring_friend')
remove_column :users, :referring_friend
User.reset_column_information
end

end
end