Setting up Subversion Integration
Lighthouse allows for basic integration with your source control tool. Although a more specialized SCM tool may be desirable, it can be useful to send changeset notices to your Lighthouse dashboard. Lighthouse’s source control support is general enough that other tools should work, but this example will focus on subversion.
Authentication
This example beacon will use a token for authentication. Go to the My Profile link in the top right of the page. There you can create a new API token for your account. You can specify the project if you want, but make sure full access is selected.

Keywords in your changeset revision logs.
Once your subversion beacon is setup, you can now add keywords to your log messages that will update tickets. To simply refer to a ticket:
Prototype new feature [#15]
The #15 will add this log message as a comment to ticket #15. You can also change various properties:
New feature is implemented and tested [#15 tagged:committed responsible:rick milestone:"Launch" state:resolved]
- tagged – Adds the tag(s) to the ticket, but does not replace them.
- responsible – Sets the user responsible for the ticket. Use
responsible:noneto clear it. - milestone – Sets the milestone for the ticket. Use
milestone:noneto clear the milestone. - state – Sets the ticket state. Valid values are: new, open, hold, resolved, and invalid.
Setting up the script
As far as beacons go, this 73-line script is about as simple as they get. This script should work as a post-commit hook. It assumes your svn server has ruby with the standard library installed, and access to the svnlook and curl commands.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
#!/usr/bin/ruby require 'yaml' require 'cgi' require 'net/http' require 'uri' # configure multiple project settings below SVNLOOK = `which svnlook`.strip LOG_FILE = '/tmp/svn-hooks.log' OPTIONS = { # default token :token => 'CHANGEME', # tokens for other members of the team # name is matched against svn user name :users => { 'bob' => "bob's token", 'fred' => "fred's token" }, # full url, please :account => 'http://activereload.lighthouseapp.com', :project => 2, # REPLACE :prefix => /^trunk/ # OPTIONAL } def gather_and_post(repo_path, revision, options) if options[:prefix] commit_dirs_changed = `#{SVNLOOK} dirs-changed #{repo_path} -r #{revision}` return unless commit_dirs_changed.split(/\n/)[0] =~ options[:prefix] end commit_author = `#{SVNLOOK} author #{repo_path} -r #{revision}`.chop commit_log = `#{SVNLOOK} log #{repo_path} -r #{revision}` commit_date = `#{SVNLOOK} date #{repo_path} -r #{revision}` commit_changed = `#{SVNLOOK} changed #{repo_path} -r #{revision}` commit_changes = commit_changed.split("\n").inject([]) do |memo, line| if line.strip =~ /(\w)\s+(.*)/ memo << [$1, $2] end end.to_yaml changeset_xml = <<-END_XML <changeset> <title>#{CGI.escapeHTML("%s committed changeset [%d]" % [commit_author, revision])}</title> <body>#{CGI.escapeHTML(commit_log)}</body> <changes>#{CGI.escapeHTML(commit_changes)}</changes> <revision>#{CGI.escapeHTML(revision.to_s)}</revision> <changed-at type="datetime">#{CGI.escapeHTML(commit_date.split('(').first.strip)}</changed-at> </changeset> END_XML token = options[:users][commit_author] || options[:token] url = URI.parse('%s/projects/%d/changesets.xml' % [options[:account], options[:project]]) req = Net::HTTP::Post.new(url.path) req.basic_auth token, 'x' # to ensure authentication req.body = changeset_xml.strip req.set_content_type('application/xml') res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) } case res when Net::HTTPSuccess, Net::HTTPRedirection ## all good, we submitted... else res.error! end end begin # feel free to add multiple calls below gather_and_post ARGV[0], ARGV[1], OPTIONS rescue %x{echo "repo:#{ARGV[0]} rev: #{ARGV[1]}" > #{LOG_FILE}} %x{echo "Error: #{$!.to_s.gsub('`',"'")} trace:#{caller}" >> #{LOG_FILE}} end |
First, make sure the basic paths at the top to your commands are correct. Then, make sure the #gather_and_post call has the correct arguments. The :token, :account, and :project options are self-explanatory. The :prefix option should be a regex that is matched against the paths in the commit. If it’s provided and matches the commit, the script proceeds with the ping.
You can also run this script manually to test. Assuming this is in /svn/my-repo/hooks/post-commit, you’d run it with: ruby /svn/my-repo/hooks/post-commit /svn/my-repo 1000 (fill in your own repository path and revision number).
The important SVN bits of this approach were yanked from: webtypes > Subversion post commit hook using basecamp API. Also, thanks goes to James Cox for taking the initiative in writing a better version with the Net/HTTP library.

