Loosely Coupled Git Hooks
Jun 18, 2013
Git hooks may need to execute deployment actions they have no permissions for. Messaging provides a simple way to bridge that gap.

I’m a big fan of AMQP, it’s the current hammer solution to all my nails problems.

I’m developing a personal convention in my projects of having a push hook to automatically deploy the published branch. Instead of dealing with user privileges to let the hook process touch the application directory, I run a small daemon that subscribes to a message queue, and the hook does nothing except sending a message.

My current setup involves simply using the default direct exchange.

The hook then becomes:

1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  11
EM.run do
    connection = AMQP.connect(host: 'my.broker.host',
                              vhost: '/my-vhost',
                              user: 'my-user',
                              password: 'my-password')
    channel = AMQP::Channel.new connection
    ex = channel.direct ""
    ex.publish '{"action":"generate"}', routing_key: "my-project" do
      connection.disconnect { EM.stop }
    end
  end
  

And the daemon

1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  11
  12
  13
  14
  15
  16
  17
$0 = "My project generator"
  Dir.chdir "/var/www/my-project"
  
  Dante.run "my-project", pid_path: '/var/www/my-project-generator.pid', user: 'www-data', group: 'www-data' do
    EM.run do
      connection = AMQP.connect host: "my.broker.host", vhost: "/my-vhost", user: "my-user", password: "my-password"
      channel = AMQP::Channel.new connection
      queue = channel.queue "my-project", auto_delete: true
      queue.subscribe do |payload|
        message = Oj.load payload
        case message["action"]
        when "generate"
          `my-deploy-script`
        end
      end
    end
  end
  

Dante daemons are started like so:

1
sudo /var/www/my-project-generator.rb -d
  

See gist for full code.