Permalink
Browse files

Merge pull request #5 from dreverri/refactor

Refactor
  • Loading branch information...
2 parents 64d399c + c949950 commit cd4ae5cda6e1f4e5b1cd702f2e1ee3164206d465 @dreverri committed Apr 6, 2012
View
@@ -1 +1,2 @@
-config.yml
+config/projects.yml
+.DS_Store
View
1 .rvmrc
@@ -0,0 +1 @@
+rvm use ruby-1.9.2@github_post_receive --create
View
11 Gemfile
@@ -0,0 +1,11 @@
+source :rubygems
+
+gem 'sinatra'
+gem 'grit'
+gem 'posix-spawn'
+
+group :development do
+ gem 'rake'
+ gem 'rack-test'
+ gem 'rspec'
+end
View
@@ -0,0 +1,36 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ diff-lcs (1.1.2)
+ grit (2.4.1)
+ diff-lcs (~> 1.1)
+ mime-types (~> 1.15)
+ mime-types (1.16)
+ posix-spawn (0.3.6)
+ rack (1.3.0)
+ rack-test (0.6.0)
+ rack (>= 1.0)
+ rake (0.9.2)
+ rspec (2.6.0)
+ rspec-core (~> 2.6.0)
+ rspec-expectations (~> 2.6.0)
+ rspec-mocks (~> 2.6.0)
+ rspec-core (2.6.3)
+ rspec-expectations (2.6.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.6.0)
+ sinatra (1.2.6)
+ rack (~> 1.1)
+ tilt (< 2.0, >= 1.2.2)
+ tilt (1.3.2)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ grit
+ posix-spawn
+ rack-test
+ rake
+ rspec
+ sinatra
View
@@ -0,0 +1,86 @@
+# Description
+
+Sinatra app that handles HTTP POSTs from GitHub's post-receive
+webhook.
+
+# Usage
+
+* Create the file `config/projects.yml`
+
+* Add a project to the projects file
+
+```yaml
+path/to/deploy:
+ name: repo-sync-webhook
+ branch: master
+ cmd: rake
+```
+
+* Use the `rackup` command to start the app on port `9292` bound to
+ `0.0.0.0`
+
+* Setup a [post receive
+ hook](http://help.github.com/post-receive-hooks/) in the Github
+ admin panel
+
+# Config
+
+Project definitions are specified in a `projects.yml` file.
+
+# Projects
+
+The config file should contain a hash of projects. The key of the hash
+is used as the deploy path. Each project should define the following
+parameters:
+
+* name - Name of the repository
+* branch - Name of the branch to respond to
+* token - Token to be matched to incoming requests (optional)
+* cmd - Command to run when the post commit hook is received
+
+Each defined project should be specific to a particular repository and
+branch. When the incoming request matches the defined repository,
+branch, and token the cmd will be executed.
+
+```yaml
+path/to/deploy:
+ name: repo-sync-webhook
+ branch: master
+ token: secret
+ cmd: rake
+```
+
+# Deploy Path
+
+The path defined for a project (e.g. `path/to/deploy`) stores the currently
+processed commit. Each post receive hook creates a new directory
+within the deploy path using the id of the received commit.
+
+A symlink (`current`) is maintained which always points to the most
+recently processed commit.
+
+# Token
+
+Projects may specify a token parameter. Incoming requests will be
+expected to have a token query parameter with a value that matches the
+value defined in the config file.
+
+If a token is defined for a project the post commit URL should be
+similar to `http://hostname:9292/notify?token=project_token`
+
+# Process
+
+When a post receive hook is received this app will do the following:
+
+* Read repository name, branch name, and commit id from payload
+* Look for matching projects in the config file
+* Clone the repo to a new directory and checkout the commit
+* Set the current working directory to this new directory
+* Run the project's defined cmd
+ * On success - update current symlink and remove old version
+ * On failure - log the failure and destroy the commit directory
+
+# To Do
+
+* Use mutex per project rather than Sinatra's global mutex
+* Package as a gem
View
@@ -1,74 +0,0 @@
-* Description
-
- Sinatra app that handles HTTP POSTs from GitHub's post-receive
- webhook.
-
-* Usage
-
- The following command will start a server on port 4567 bound to "0.0.0.0".
-
-#+BEGIN_SRC bash
- ruby sync.rb
-#+END_SRC
-
-* Config
-
- This app supports project definitions specified in a "config.yml"
- file. A [[./config.example.yml][sample]] is provided in this repository.
-
-* Projects
-
- The config file should contain a list of projects. Each project should
- define the following parameters:
-
- - name :: Name of the repository
- - branch :: Name of the branch to respond to
- - token :: Token to be matched to incoming requests (optional)
- - root :: The repository will be cloned to this directory
- - cmd :: Command to run when post commit hook is received
-
- The assumption is that each defined project should be specific to a
- particular repository and branch. When the incoming request matches
- the defined repository, branch, and token the cmd will be executed.
-
-* Token
-
- Projects may specify a token parameter. Incoming requests will be
- expected to have a token query parameter with a value that matches
- the value defined in the config file.
-
- If a token is defined for a project the post commit URL should be
- similar to "http://hostname:4567/notify?token=project_token"
-
-* Process
-
- When a post receive hook is received this app will do the following:
-
- - Read repository name, branch name, and commit id from payload
- - Look for matching projects
- - Mirror repository or fetch updates
- #+BEGIN_SRC bash
- # Mirror repository
- git clone --mirror #{repository} #{cache}
- #+END_SRC
- #+BEGIN_SRC bash
- # Fetch updates
- git --git-dir=#{cache} fetch
- #+END_SRC
- - Checkout the commit
- #+BEGIN_SRC
- git clone #{cache} #{commit_path}
- git --git-dir=#{commit_path}/.git --work-tree=#{commit_path} \
- checkout -f #{commit_id}
- #+END_SRC
- - Change directory to the repository directory
- - Run the cmd defined in the config
-
- The cache and commit_path are directories created in the root
- directory defined in the config file.
-
-* To Do
-
- - Use mutex per project rather than Sinatra's global mutex
- (set :lock, true)
- - Package as a gem
View
@@ -0,0 +1,15 @@
+require 'rubygems'
+require 'bundler'
+
+Bundler.setup
+
+require 'rspec/core'
+require 'rspec/core/rake_task'
+
+desc "Run Unit Specs Only"
+RSpec::Core::RakeTask.new(:spec) do |spec|
+ spec.pattern = "spec/github_post_receive/**/*_spec.rb"
+ spec.rspec_opts = ["--color", "--format", "doc"]
+end
+
+task :default => :spec
View
@@ -1,6 +0,0 @@
-:projects:
- - :name: riak_wiki
- :branch: master
- :token: project_token
- :root: .
- :cmd: gollum-site generate && (PREV=`readlink ../current`.. || PREV="") && rm -f ../current && ln -s `pwd`/_site ../current && ([ `pwd` -ef `cd $PREV && pwd` ] || rm -rf $PREV)
View
@@ -0,0 +1,12 @@
+require 'rubygems'
+require 'bundler'
+
+Bundler.setup
+
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
+require 'github_post_receive'
+GithubPostReceive::App.load_config("config/projects.yml")
+if File.exists?("config/logger.yml")
+ GithubPostReceive::App.load_logger_config("config/logger.yml")
+end
+run GithubPostReceive::App
View
@@ -0,0 +1 @@
+level: ERROR
@@ -0,0 +1,5 @@
+wiki:
+ name: riak_wiki
+ branch: master
+ token: project_token
+ cmd: gollum-site generate
@@ -0,0 +1,9 @@
+require 'json'
+require 'yaml'
+require 'grit'
+require 'posix-spawn'
+require 'sinatra/base'
+require 'github_post_receive/payload'
+require 'github_post_receive/project'
+require 'github_post_receive/deployment'
+require 'github_post_receive/app'
@@ -0,0 +1,66 @@
+module GithubPostReceive
+ class App < Sinatra::Application
+ def self.load_config(fname)
+ hsh = YAML.load(ERB.new(File.read(File.expand_path(fname))).result)
+ load_hash(hsh)
+ end
+
+ def self.load_hash(hsh)
+ set :projects, hsh.map { |path, config| Project.new(path, config) }
+ end
+
+ def self.load_logger_config(fname)
+ hsh = YAML.load(ERB.new(File.read(File.expand_path(fname))).result)
+ self.load_logger(hsh)
+ end
+
+ def self.load_logger(hsh={})
+ $logger.close if $logger
+ $logger = ::Logger.new(hsh['device'] || STDOUT)
+ $logger.level = ::Logger.const_get(hsh['level'] || ENV['LOGGER_LEVEL'] || 'ERROR')
+ $logger.datetime_format = hsh['datetime_format'] || "%Y-%m-%d %H:%M:%S"
+ Grit.logger = $logger
+ Grit.debug = $logger.debug?
+ $logger
+ end
+
+ def self.logger
+ $logger ||= load_logger
+ end
+
+ configure do
+ enable :lock
+ end
+
+ get '/' do
+ "Nothing to see here"
+ end
+
+ post '/notify' do
+ process_request(params, settings.projects)
+ "Thank you"
+ end
+
+ helpers do
+ def process_request(params, projects)
+ payload = Payload.from_params(params)
+ projects.each do |project|
+ if project.match?(payload)
+ async = (params[:async] == "true")
+ project.deploy(payload.url, payload.commit_id, async)
+ end
+ end
+ rescue GithubPostReceive::AlreadyDeployed => e
+ logger.error("Received notification for an already deployed commit: #{e.message}")
+ end
+
+ def url(payload, project)
+ project['remote'] || payload['repository']['url']
+ end
+
+ def logger
+ self.class.logger
+ end
+ end
+ end
+end
Oops, something went wrong.

0 comments on commit cd4ae5c

Please sign in to comment.