2

I have just installed Trac 1.0.1 on a server that also holds a Git repository. I’d like to be able to close Trac tickets by including things like “fixes #3” in the Git commit messages. This should pretty easy—by including a post-receive hook in my repository, I can execute some piece of code (e.g. a Python script) after each git push to the server. But what piece of code to use?

bdesham
  • 15,430
  • 13
  • 79
  • 123

1 Answers1

5

After running around for a while and following a couple of dead ends (including the Trac Git page, which is vague on this topic, and the Git plugin, which won’t actually work (?!) until bug #7301 is fixed), I found the solution.

  1. Connect your Git repository to Trac through the steps at “setting up a Trac environment”.

  2. Enable the Commit Ticket Updater plugin, either through the “Admin” section of Trac or by editing trac.ini.

  3. Create a file called post-receive in the hooks directory of your Git repository, with the following content:

    #!/usr/bin/ruby
    
    ARGF.lines do |line|
      fields = line.split
      oldrev = fields[0]
      newrev = fields[1]
      refname = fields[2].chomp
    
      if oldrev =~ /^0+$/
        revspec = newrev
      else
        revspec = oldrev + '..' + newrev
      end
    
      other_branches = `git for-each-ref --format='%(refname)' refs/heads/ | grep -F -v "#{refname}"`
      other_branches = other_branches.chomp.gsub /[\r\n]+/, ' '
    
      commits = `git rev-parse --not #{other_branches} | git rev-list --stdin #{revspec}`
    
      commits.each_line do |commit|
        system "trac-admin .../trac changeset added '(default)' #{commit.chomp}"
      end
    end
    

    Of course, replace “.../trac” with the absolute path to your Trac installation.

    I’m actually using Trac through Virtualenv. If you are too, add this to the top of the file:

    require 'tempfile'
    
    def virtualenv_system(cmd)
      script = Tempfile.new('post_receive')
      script.write 'source .../virtualenvs/trac/bin/activate'
      script.write "\n"
      script.write cmd
      script.close
      system "bash #{script.path}"
      script.unlink
    end
    

    and replace the system call with virtualenv_system.

  4. Make this post-receive file executable.

This is inspired by the approach given on the Repository Administration page, combined with this SO answer about getting all of the new commits in a post-receive script. I believe that this script, while long, behaves correctly when you are pushing multiple commits and/or pushing commits to branches other than the currently-checked-out one. (The script given on the Repository Administration page does not behave correctly in these situations—it only looks at the most recent commit message from HEAD.)

After this setup process, any Git commits that contain strings like “fixes #7” will close the corresponding tickets in Trac. You can configure this a little with the options listed on the Commit Ticket Updater page. Specifically, you might want to change the value of commit_ticket_update_envelope; it’s not completely clear, but I think the default is set so that you have to include your commands in square brackets, like “Refactored MyAwesomeClass [fixes #42]”.

Community
  • 1
  • 1
bdesham
  • 15,430
  • 13
  • 79
  • 123
  • This sounds like the sort of thing you might consider using `git notes` for. http://git-scm.com/2010/08/25/notes.html – Klas Mellbourn Apr 07 '13 at 16:48
  • @KlasMellbourn That looks promising, although it would require even deeper integration into Trac ;-) – bdesham Apr 07 '13 at 17:03
  • The final assertion is wrong. Actually the default behavior is, that just 'fixes #42' triggers, but all other details seem good. Especially dealing with virtual environment is, what makes this answer valuable, very good. – hasienda Apr 09 '13 at 18:53