skynet-deploy 0.9.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -8,13 +8,50 @@ Skynet builds and deploys web sites on your VPS or bare metal server. It is trig
8
8
  Current Builder Types
9
9
  ---------------------
10
10
 
11
- 1. Static. Just copies entire repository to proper location
11
+ 1. Static. Copies the entire repository to the specified destination and then
12
+ removes the destination .git folder
12
13
  1. Jekyll. Run jekyll on your repository. Entirely controlled by
13
14
  site's `_config.yml`
14
15
 
15
16
  Usage
16
17
  -----
18
+
17
19
  * Install Skynet: `$ gem install skynet-deploy`
18
20
  * Install basic config file: `$ skynet config <first project name>`
19
21
  * edit config file to add your repositories
22
+ * Run builder by hand to ensure everything works: `$ skynet build`
23
+ * Add `http://YOUR_SKYNET_SERVER/PROJECT_NAME` as a WebHook URL to your repository under `Admin -> Service Hooks`
20
24
  * Start server: `$ skynet server`
25
+
26
+ Config file arguments
27
+ ---------------------
28
+
29
+ ### Required configuration variables for each project: ###
30
+ * `url` Value passed from post-receive hook to verify that the deploy
31
+ should happen
32
+ * `type` The builder type to invoke for this application
33
+ * Either `branch` and `destination` together or only `branches` must be specified
34
+
35
+ ### Optional configuration variables: ###
36
+ * `key` SSH private key file to be used to clone and pull from private
37
+ repositories. Should be given as an absolute path
38
+ * `repository` The location to clone the repository from. This is
39
+ usually inferred from `url`, but can be overridden here
40
+ * `branch` The branch to be deployed
41
+ * `destination` Absolute path to the deployed application
42
+ * `branches` For when multiple branches should be deployed to this
43
+ machine (such as a production + staging strategy). `branches` is a
44
+ hash with keys being the branch name and values being the destination
45
+
46
+ Example Post-Receive Hook
47
+ -------------------------
48
+
49
+ Add this to your `.git/hooks/post-receive` file to use Skynet with
50
+ a git server other than GitHub.
51
+
52
+ read oldrev newrev refname
53
+
54
+ curl -d "payload={\"repository\":{\"url\":\"<<same path as in config.yml>>\"},\"before\":\"$oldrev\",\"after\":\"$newrev\",\"ref\":\"$refname\"}" http://YOUR_SKYNET_SERVER/PROJECT_NAME
55
+
56
+ The URL must be visible from the Skynet server, as it will pull a new
57
+ copy of the repository from this server.
@@ -1,5 +1,6 @@
1
1
  require 'sinatra/base'
2
2
  require 'json'
3
+ require 'active_support/core_ext/object/blank'
3
4
 
4
5
  module Skynet
5
6
 
@@ -11,10 +12,10 @@ module Skynet
11
12
 
12
13
  post '/:app_name' do |app_name|
13
14
  Skynet.logger.debug "params: #{params.inspect}"
14
- payload = JSON.parse params[:payload]
15
- config = settings.config[app_name]
16
- if deployable? config, payload
17
- Builder.build app_name, config
15
+ @payload = JSON.parse params[:payload]
16
+ @config = settings.config[app_name]
17
+ if deployable?
18
+ Builder.build app_name, @config, branch
18
19
  else
19
20
  Skynet.logger.warn "#{app_name} is not deployable"
20
21
  end
@@ -23,12 +24,16 @@ module Skynet
23
24
 
24
25
  private
25
26
 
26
- def deployable?(config, payload)
27
- !config.nil? &&
28
- config[:url] == payload['repository']['url'] &&
29
- payload['ref'] == "refs/heads/#{config[:branch]}" &&
27
+ def deployable?
28
+ @config.present? &&
29
+ @config[:url] == @payload['repository']['url'] &&
30
30
  payload['after'] !~ /^0{40}$/
31
31
  end
32
+
33
+ def branch
34
+ @payload['ref'] =~ %r[^refs/heads/(.*)$]
35
+ $1
36
+ end
32
37
  end
33
38
 
34
39
  end
@@ -5,8 +5,8 @@ module Skynet
5
5
  autoload :Static, 'skynet/builder/static'
6
6
  autoload :Jekyll, 'skynet/builder/jekyll'
7
7
 
8
- def self.build(app, config)
9
- for_app(app, config).build
8
+ def self.build(app, config, branch=nil)
9
+ for_app(app, config).build branch
10
10
  end
11
11
 
12
12
  def self.for_app(app, config, type=nil)
@@ -1,4 +1,6 @@
1
1
  require 'active_model'
2
+ require 'active_support/core_ext/object/blank'
3
+ require 'uri'
2
4
 
3
5
  module Skynet
4
6
  module Builder
@@ -8,32 +10,55 @@ module Skynet
8
10
  class Base
9
11
  include ActiveModel::Validations
10
12
 
11
- attr_accessor :app, :url, :branch, :destination, :type
12
- attr_reader :source
13
+ attr_accessor :app, :url, :branch, :destination, :branches, :type, :repository
14
+ attr_reader :source, :key
13
15
 
14
- validates_presence_of :app, :url, :branch, :destination
16
+ validates_presence_of :app, :url, :branch, :destination, :branches
15
17
  validates_inclusion_of :type,
16
18
  in: ALLOWED_BUILDERS,
17
19
  message: "must be one of #{ALLOWED_BUILDERS}"
20
+ validate :branches_have_destinations
21
+ validate :key_is_readable, if: :key?
18
22
 
19
23
  def initialize(app, config)
20
- self.app = app
21
- @config = config
24
+ self.app = app
25
+ @config = config
26
+ @source = File.join Dir.pwd, app, '.'
27
+ @key = config[:key]
28
+
29
+ if config[:branches].blank?
30
+ self.branches = { config[:branch] => config[:destination] }
31
+ else
32
+ self.branches = config[:branches]
33
+ end
34
+ self.branch = branches.first[0]
35
+ self.destination = branches.first[1]
22
36
  self.url = config[:url]
23
- self.branch = config[:branch]
24
- self.destination = config[:destination]
25
37
  self.type = config[:type]
26
- @source = File.join Dir.pwd, app, '.'
38
+ self.repository = config[:repository]
27
39
  end
28
40
 
29
- def build
30
- unless valid?
31
- Skynet.logger.error "Configuration error for #{app}"
32
- Skynet.logger.error errors.full_messages.join '. '
33
- raise ArgumentError
41
+ def build(branch=nil)
42
+ unless branch.blank?
43
+ return if branches[branch].blank?
44
+ self.branches = { branch => branches[branch] }
34
45
  end
35
46
 
36
- build_repository
47
+ branches.each_pair do |branch, destination|
48
+ self.branch = branch.to_s
49
+ self.destination = destination
50
+
51
+ if valid?
52
+ Skynet.logger.info "#{type} running for #{app} (branch: #{branch})"
53
+ else
54
+ Skynet.logger.error "Configuration error for #{app} (branch: #{branch})"
55
+ Skynet.logger.error errors.full_messages.join '. '
56
+ raise ArgumentError
57
+ end
58
+
59
+ build_repository
60
+ execute
61
+ end
37
62
  end
38
63
 
39
64
  private
@@ -42,20 +67,58 @@ module Skynet
42
67
  repo_exists? ? update_repo : create_repo
43
68
  end
44
69
 
70
+ def remote_repository
71
+ repository || translate_url
72
+ end
73
+
74
+ def translate_url
75
+ uri = URI.parse url
76
+ if uri.host == 'github.com'
77
+ "git@github.com:#{uri.path.gsub %r[(^/)|(/$)|(\.git$)], ''}.git"
78
+ else
79
+ url
80
+ end
81
+ rescue URI::InvalidURIError
82
+ url
83
+ end
84
+
45
85
  def create_repo
46
86
  Skynet.logger.debug "Creating repository for #{app}"
47
87
  Skynet.logger.debug `rm -rf #{source}`
48
- Skynet.logger.info `git clone #{url} #{app}; cd #{source}; git checkout #{branch}`
88
+ if key?
89
+ Skynet.logger.info `ssh-agent bash -c 'ssh-add #{key}; git clone #{remote_repository} #{app}'; cd #{source}; git checkout #{branch}`
90
+ else
91
+ Skynet.logger.info `git clone #{remote_repository} #{app}; cd #{source}; git checkout #{branch}`
92
+ end
49
93
  end
50
94
 
51
95
  def update_repo
52
96
  Skynet.logger.debug "Updating repository for #{app}"
53
- Skynet.logger.info `cd #{source}; git checkout #{branch}; git pull`
97
+ if key?
98
+ Skynet.logger.info `cd #{source}; git checkout #{branch}; ssh-agent bash -c 'ssh-add #{key}; git pull origin #{branch}'`
99
+ else
100
+ Skynet.logger.info `cd #{source}; git checkout #{branch}; git pull origin #{branch}`
101
+ end
54
102
  end
55
103
 
56
104
  def repo_exists?
57
105
  File.exist? File.join(source, '.git')
58
106
  end
107
+
108
+ def branches_have_destinations
109
+ return if branches.blank?
110
+ branches.each_pair do |b, d|
111
+ errors.add(:branches, "#{b} must have a destination") unless d.present?
112
+ end
113
+ end
114
+
115
+ def key?
116
+ key.present?
117
+ end
118
+
119
+ def key_is_readable
120
+ errors.add(:key, 'must be present and readable') unless File.readable?(key)
121
+ end
59
122
  end
60
123
  end
61
124
  end
@@ -4,10 +4,7 @@ module Skynet
4
4
  module Builder
5
5
  class Jekyll < Base
6
6
 
7
- def build
8
- Skynet.logger.info "Jekyll running for #{app}..."
9
- super
10
-
7
+ def execute
11
8
  Skynet.logger.debug "PWD: #{Dir.pwd} Source: #{source} Destination: #{destination}"
12
9
  Skynet.logger.info `jekyll #{source} #{destination}`
13
10
 
@@ -4,10 +4,7 @@ module Skynet
4
4
  module Builder
5
5
  class Static < Base
6
6
 
7
- def build
8
- Skynet.logger.info "Static running for #{app}..."
9
- super
10
-
7
+ def execute
11
8
  Skynet.logger.debug "Removing #{destination}/*"
12
9
  FileUtils.rm_rf Dir.glob(File.join destination, '*'), secure: true
13
10
 
@@ -46,12 +46,12 @@ module Skynet
46
46
  end
47
47
  end
48
48
 
49
- desc "build [PROJECT_NAME]", "Builds all applications, or PROJECT_NAME only if given"
49
+ desc "build [PROJECT_NAME] [BRANCH_NAME]", "Builds all applications, or PROJECT_NAME only if given"
50
50
  method_option :file, type: :string, default: './config.yml', aliases: '-f', desc: 'Configuration file'
51
- def build(name=nil)
51
+ def build(project=nil, branch=nil)
52
52
  all_apps = load_configuration options[:file]
53
53
 
54
- if name.nil?
54
+ if project.nil?
55
55
  all_apps.each do |app, config|
56
56
  begin
57
57
  Builder.build app, config
@@ -60,11 +60,11 @@ module Skynet
60
60
  end
61
61
  end
62
62
  else
63
- config = all_apps[name]
63
+ config = all_apps[project]
64
64
  if config.nil?
65
- Skynet.logger.error "Could not find configuration for #{name}"
65
+ Skynet.logger.error "Could not find configuration for #{project}"
66
66
  else
67
- Builder.build name, config
67
+ Builder.build project, config, branch
68
68
  end
69
69
  end
70
70
  end
@@ -1,15 +1,30 @@
1
- # Base configuration for SkyNet
2
- #
3
- # Example project:
1
+ # Base configuration for Skynet
4
2
  #
3
+ # Example for single branch deployment:
5
4
  # project_name:
6
- # url: git@github.com:project_name.git
7
- # branch: master
5
+ # url: https://github.com/owner/project_name
8
6
  # type: jekyll
7
+ # branch: master
9
8
  # destination: /var/www/project_name
9
+ #
10
+ # Example for multiple branch deployment:
11
+ # project_name:
12
+ # url: https://github.com/owner/project_name
13
+ # type: jekyll
14
+ # branches:
15
+ # master: /var/www/project_name_production
16
+ # develop: /var/www/project_name_staging
17
+ #
18
+ # Example for private repository deployment:
19
+ # project_name:
20
+ # url: https://github.com/owner/project_name
21
+ # type: jekyll
22
+ # key: /home/username/.ssh/id_rsa
23
+ # branch: master
24
+ # destination: /var/www/project_name
10
25
 
11
26
  <%= @project_name %>:
12
- url: https://github.com/ORGANIZATION/<%= @project_name %>
27
+ url: https://github.com/ORGANIZATION_OR_USER/<%= @project_name %>
13
28
  branch: master
14
29
  type:
15
30
  destination:
@@ -1,3 +1,3 @@
1
1
  module Skynet
2
- VERSION = "0.9.2"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -5,8 +5,9 @@ require 'shoulda-matchers'
5
5
  describe Skynet::Builder::Base do
6
6
 
7
7
  let(:source) { File.join Dir.pwd, 'app', '.' }
8
- let(:repo) { 'git@github.com:app.git' }
9
- let(:options) { {url: repo, branch: 'master', destination: '/var/www', type: 'static'} }
8
+ let(:url) { 'https://github.com/org/app' }
9
+ let(:repo) { 'git@github.com:org/app.git' }
10
+ let(:options) { {url: url, branch: 'master', destination: '/var/www', type: 'static'} }
10
11
  subject { described_class.new 'app', options }
11
12
 
12
13
  describe ".validations" do
@@ -14,61 +15,143 @@ describe Skynet::Builder::Base do
14
15
  it { should validate_presence_of :url }
15
16
  it { should validate_presence_of :branch }
16
17
  it { should validate_presence_of :destination }
18
+ it { should validate_presence_of :branches }
17
19
  it { should ensure_inclusion_of(:type).in_array(%w[static jekyll]).allow_nil(false).allow_blank(false) }
18
20
  it { should_not allow_value('base').for :type }
21
+ describe "on @branches" do
22
+ before(:each) { subject.valid? }
23
+
24
+ context "when passed a single branch" do
25
+ specify { subject.errors[:branches].should be_empty }
26
+ end
27
+ context "when passed multiple valid branches" do
28
+ let(:options) { {url: url, type: 'static', branches: {master: '/var/www/production', develop: '/var/www/staging'}} }
29
+ specify { subject.errors[:branches].should be_empty }
30
+ end
31
+ context "when passed an invalid branch" do
32
+ let(:options) { {url: url, type: 'static', branches: {master: '/var/www', develop: ''}} }
33
+ it "has an error on branches" do
34
+ subject.errors[:branches].should include('develop must have a destination')
35
+ end
36
+ end
37
+ end
38
+ describe "on @key" do
39
+ context "when not passed a key" do
40
+ before(:each) { subject.valid? }
41
+ specify { subject.errors[:key].should be_empty }
42
+ end
43
+
44
+ context "when passed a valid key" do
45
+ let(:options) { {key: 'keyfile'} }
46
+ before(:each) do
47
+ File.stub(:readable?).and_return true
48
+ subject.valid?
49
+ end
50
+ specify { subject.errors[:key].should be_empty }
51
+ end
52
+
53
+ context "when passed an invalid key" do
54
+ let(:options) { {key: 'missing_keyfile'} }
55
+ before(:each) do
56
+ File.stub(:readable?).and_return false
57
+ subject.valid?
58
+ end
59
+ it "has an error on key" do
60
+ subject.errors[:key].should include('must be present and readable')
61
+ end
62
+ end
63
+ end
19
64
  end
20
65
 
21
66
  describe "#build" do
67
+ before(:each) do
68
+ subject.stub :build_repository
69
+ subject.stub :execute
70
+ end
71
+
22
72
  context "when valid" do
23
- before(:each) { subject.stub :build_repository }
24
73
  it { expect { subject.build }.to_not raise_error }
25
74
  end
26
75
  context "when invalid" do
27
76
  let(:options) { {} }
28
77
  it { expect { subject.build }.to raise_error ArgumentError }
29
78
  end
79
+ context "when passing a branch" do
80
+ it { expect { subject.build 'master' }.to_not raise_error }
81
+ it "d" do
82
+ subject.build 'develop'
83
+ end
84
+ end
30
85
  end
31
86
 
32
- describe "#build_repository" do
33
- context "repo already exists" do
34
- before(:each) { subject.stub(:repo_exists?).and_return true }
87
+ context "private methods" do
88
+ before(:each) do
89
+ subject.branch = 'master'
90
+ subject.destination = '/var/www'
91
+ end
92
+
93
+ describe "#build_repository" do
94
+ context "repo already exists" do
95
+ before(:each) { subject.stub(:repo_exists?).and_return true }
35
96
 
36
- it "updates the repository" do
37
- subject.should_receive(:update_repo).with no_args
38
- subject.send :build_repository
97
+ it "updates the repository" do
98
+ subject.should_receive(:update_repo).with no_args
99
+ subject.send :build_repository
100
+ end
39
101
  end
40
- end
41
102
 
42
- context "repo does not exist" do
43
- before(:each) { subject.stub(:repo_exists?).and_return false }
103
+ context "repo does not exist" do
104
+ before(:each) { subject.stub(:repo_exists?).and_return false }
44
105
 
45
- it "creates a new repository" do
46
- subject.should_receive(:create_repo).with no_args
47
- subject.send :build_repository
106
+ it "creates a new repository" do
107
+ subject.should_receive(:create_repo).with no_args
108
+ subject.send :build_repository
109
+ end
48
110
  end
49
111
  end
50
- end
51
112
 
52
- describe "#create_repo" do
53
- before(:each) do
54
- subject.should_receive(:`).with "rm -rf #{source}"
55
- subject.should_receive(:`).with "git clone #{repo} app; cd #{source}; git checkout master"
56
- end
113
+ describe "#create_repo" do
114
+ before(:each) { subject.should_receive(:`).with "rm -rf #{source}" }
57
115
 
58
- it { subject.send :create_repo }
59
- end
116
+ context "without key" do
117
+ it "should call git clone" do
118
+ subject.should_receive(:`).with "git clone #{repo} app; cd #{source}; git checkout master"
119
+ subject.send :create_repo
120
+ end
121
+ end
60
122
 
61
- describe "#update_repo" do
62
- before(:each) { subject.should_receive(:`).with "cd #{source}; git checkout master; git pull" }
123
+ context "with key" do
124
+ let(:options) { {key: 'keyfile', url: url, branch: 'master', destination: '/var/www', type: 'static'} }
125
+ it "should call git clone" do
126
+ subject.should_receive(:`).with "ssh-agent bash -c 'ssh-add keyfile; git clone #{repo} app'; cd #{source}; git checkout master"
127
+ subject.send :create_repo
128
+ end
129
+ end
130
+ end
63
131
 
64
- it { subject.send :update_repo }
65
- end
132
+ describe "#update_repo" do
133
+ context "without key" do
134
+ it "should call git pull" do
135
+ subject.should_receive(:`).with "cd #{source}; git checkout master; git pull origin master"
136
+ subject.send :update_repo
137
+ end
138
+ end
66
139
 
67
- describe "#repo_exists?" do
68
- before(:each) do
69
- File.should_receive(:exist?).with File.join(source, '.git')
140
+ context "with key" do
141
+ let(:options) { {key: 'keyfile', url: url, branch: 'master', destination: '/var/www', type: 'static'} }
142
+ it "should call git pull" do
143
+ subject.should_receive(:`).with "cd #{source}; git checkout master; ssh-agent bash -c 'ssh-add keyfile; git pull origin master'"
144
+ subject.send :update_repo
145
+ end
146
+ end
70
147
  end
71
148
 
72
- it { subject.send :repo_exists? }
149
+ describe "#repo_exists?" do
150
+ before(:each) do
151
+ File.should_receive(:exist?).with File.join(source, '.git')
152
+ end
153
+
154
+ it { subject.send :repo_exists? }
155
+ end
73
156
  end
74
157
  end
@@ -6,17 +6,16 @@ describe Skynet::Builder::Jekyll do
6
6
  let(:dest) { '/var/www/app' }
7
7
  let(:options) { {destination: dest} }
8
8
  let(:source) { File.join Dir.pwd, app, '.' }
9
- subject { described_class.new app, options }
10
-
11
- describe "#build" do
12
- before(:each) do
13
- subject.should_receive :build_repository
14
- subject.stub(:valid?).and_return true
9
+ subject do
10
+ described_class.new(app, options).tap do |b|
11
+ b.destination = dest
15
12
  end
13
+ end
16
14
 
15
+ describe "#execute" do
17
16
  it "runs jekyll with the source and destination" do
18
17
  subject.should_receive(:`).with "jekyll #{source} #{dest}"
19
- subject.build
18
+ subject.execute
20
19
  end
21
20
  end
22
21
  end
@@ -6,34 +6,34 @@ describe Skynet::Builder::Static do
6
6
  let(:dest) { '/var/www/app' }
7
7
  let(:options) { {destination: dest} }
8
8
  let(:source) { File.join Dir.pwd, app, '.' }
9
- subject { described_class.new app, options }
10
-
11
- describe "#build" do
12
- before(:each) do
13
- subject.should_receive :build_repository
14
- subject.stub(:valid?).and_return true
15
- Dir.stub(:glob).and_return [:one, :two]
9
+ subject do
10
+ described_class.new(app, options).tap do |b|
11
+ b.destination = dest
16
12
  end
13
+ end
14
+
15
+ describe "#execute" do
16
+ before(:each) { Dir.stub(:glob).and_return [:one, :two] }
17
17
 
18
18
  it "removes destination files first" do
19
19
  FileUtils.stub :remove_entry_secure
20
20
  FileUtils.stub :cp_r
21
21
  FileUtils.should_receive(:rm_rf).with [:one, :two], secure: true
22
- subject.build
22
+ subject.execute
23
23
  end
24
24
 
25
25
  it "copies files to the destination" do
26
26
  FileUtils.stub :rm_rf
27
27
  FileUtils.stub :remove_entry_secure
28
28
  FileUtils.should_receive(:cp_r).with(source, dest)
29
- subject.build
29
+ subject.execute
30
30
  end
31
31
 
32
32
  it "removes .git from the destination" do
33
33
  FileUtils.stub :rm_rf
34
34
  FileUtils.stub :cp_r
35
35
  FileUtils.should_receive(:remove_entry_secure).with "#{dest}/.git"
36
- subject.build
36
+ subject.execute
37
37
  end
38
38
  end
39
39
  end
@@ -5,9 +5,10 @@ describe Skynet::Builder do
5
5
  let(:builder) { mock('builder').as_null_object }
6
6
  let(:mock_class) { mock('builder class').as_null_object }
7
7
  let(:config) { {type: 'static'} }
8
- let(:args) { [:app, config] }
9
8
 
10
9
  describe ".for_app" do
10
+ let(:args) { [:app, config] }
11
+
11
12
  it "initializes a new builder class" do
12
13
  described_class.should_receive(:const_get).with('Static').and_return mock_class
13
14
  mock_class.should_receive(:new).with(:app, config).and_return builder
@@ -17,9 +18,11 @@ describe Skynet::Builder do
17
18
  end
18
19
 
19
20
  describe ".build" do
21
+ let(:args) { [:app, config, :master] }
22
+
20
23
  it "calls build on the new builder" do
21
24
  described_class.stub(:for_app).and_return builder
22
- builder.should_receive(:build).with no_args
25
+ builder.should_receive(:build).with :master
23
26
 
24
27
  described_class.build *args
25
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skynet-deploy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-22 00:00:00.000000000 Z
12
+ date: 2012-09-07 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sinatra
16
- requirement: !ruby/object:Gem::Requirement
16
+ requirement: &70212012481880 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,15 +21,10 @@ dependencies:
21
21
  version: '1.3'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ~>
28
- - !ruby/object:Gem::Version
29
- version: '1.3'
24
+ version_requirements: *70212012481880
30
25
  - !ruby/object:Gem::Dependency
31
26
  name: thin
32
- requirement: !ruby/object:Gem::Requirement
27
+ requirement: &70212012481240 !ruby/object:Gem::Requirement
33
28
  none: false
34
29
  requirements:
35
30
  - - ~>
@@ -37,15 +32,10 @@ dependencies:
37
32
  version: '1.4'
38
33
  type: :runtime
39
34
  prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ~>
44
- - !ruby/object:Gem::Version
45
- version: '1.4'
35
+ version_requirements: *70212012481240
46
36
  - !ruby/object:Gem::Dependency
47
37
  name: json
48
- requirement: !ruby/object:Gem::Requirement
38
+ requirement: &70212012480460 !ruby/object:Gem::Requirement
49
39
  none: false
50
40
  requirements:
51
41
  - - ~>
@@ -53,15 +43,10 @@ dependencies:
53
43
  version: '1.7'
54
44
  type: :runtime
55
45
  prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ~>
60
- - !ruby/object:Gem::Version
61
- version: '1.7'
46
+ version_requirements: *70212012480460
62
47
  - !ruby/object:Gem::Dependency
63
48
  name: jekyll
64
- requirement: !ruby/object:Gem::Requirement
49
+ requirement: &70212012479780 !ruby/object:Gem::Requirement
65
50
  none: false
66
51
  requirements:
67
52
  - - ~>
@@ -69,15 +54,10 @@ dependencies:
69
54
  version: '0.11'
70
55
  type: :runtime
71
56
  prerelease: false
72
- version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
75
- - - ~>
76
- - !ruby/object:Gem::Version
77
- version: '0.11'
57
+ version_requirements: *70212012479780
78
58
  - !ruby/object:Gem::Dependency
79
59
  name: thor
80
- requirement: !ruby/object:Gem::Requirement
60
+ requirement: &70212012479240 !ruby/object:Gem::Requirement
81
61
  none: false
82
62
  requirements:
83
63
  - - ~>
@@ -85,15 +65,10 @@ dependencies:
85
65
  version: '0.16'
86
66
  type: :runtime
87
67
  prerelease: false
88
- version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
- requirements:
91
- - - ~>
92
- - !ruby/object:Gem::Version
93
- version: '0.16'
68
+ version_requirements: *70212012479240
94
69
  - !ruby/object:Gem::Dependency
95
70
  name: activesupport
96
- requirement: !ruby/object:Gem::Requirement
71
+ requirement: &70212012478540 !ruby/object:Gem::Requirement
97
72
  none: false
98
73
  requirements:
99
74
  - - ~>
@@ -101,15 +76,10 @@ dependencies:
101
76
  version: '3.2'
102
77
  type: :runtime
103
78
  prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
- requirements:
107
- - - ~>
108
- - !ruby/object:Gem::Version
109
- version: '3.2'
79
+ version_requirements: *70212012478540
110
80
  - !ruby/object:Gem::Dependency
111
81
  name: activemodel
112
- requirement: !ruby/object:Gem::Requirement
82
+ requirement: &70212012477820 !ruby/object:Gem::Requirement
113
83
  none: false
114
84
  requirements:
115
85
  - - ~>
@@ -117,15 +87,10 @@ dependencies:
117
87
  version: '3.2'
118
88
  type: :runtime
119
89
  prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
- requirements:
123
- - - ~>
124
- - !ruby/object:Gem::Version
125
- version: '3.2'
90
+ version_requirements: *70212012477820
126
91
  - !ruby/object:Gem::Dependency
127
92
  name: rake
128
- requirement: !ruby/object:Gem::Requirement
93
+ requirement: &70212012477360 !ruby/object:Gem::Requirement
129
94
  none: false
130
95
  requirements:
131
96
  - - ~>
@@ -133,15 +98,10 @@ dependencies:
133
98
  version: '0.9'
134
99
  type: :development
135
100
  prerelease: false
136
- version_requirements: !ruby/object:Gem::Requirement
137
- none: false
138
- requirements:
139
- - - ~>
140
- - !ruby/object:Gem::Version
141
- version: '0.9'
101
+ version_requirements: *70212012477360
142
102
  - !ruby/object:Gem::Dependency
143
103
  name: rspec
144
- requirement: !ruby/object:Gem::Requirement
104
+ requirement: &70212012476820 !ruby/object:Gem::Requirement
145
105
  none: false
146
106
  requirements:
147
107
  - - ~>
@@ -149,15 +109,10 @@ dependencies:
149
109
  version: '2.11'
150
110
  type: :development
151
111
  prerelease: false
152
- version_requirements: !ruby/object:Gem::Requirement
153
- none: false
154
- requirements:
155
- - - ~>
156
- - !ruby/object:Gem::Version
157
- version: '2.11'
112
+ version_requirements: *70212012476820
158
113
  - !ruby/object:Gem::Dependency
159
114
  name: shoulda-matchers
160
- requirement: !ruby/object:Gem::Requirement
115
+ requirement: &70212012476100 !ruby/object:Gem::Requirement
161
116
  none: false
162
117
  requirements:
163
118
  - - ~>
@@ -165,12 +120,7 @@ dependencies:
165
120
  version: '1.2'
166
121
  type: :development
167
122
  prerelease: false
168
- version_requirements: !ruby/object:Gem::Requirement
169
- none: false
170
- requirements:
171
- - - ~>
172
- - !ruby/object:Gem::Version
173
- version: '1.2'
123
+ version_requirements: *70212012476100
174
124
  description: Sinatra app that listens for GitHub post-receive callbacks and deploys
175
125
  your code
176
126
  email:
@@ -222,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
172
  version: 1.3.6
223
173
  requirements: []
224
174
  rubyforge_project:
225
- rubygems_version: 1.8.21
175
+ rubygems_version: 1.8.10
226
176
  signing_key:
227
177
  specification_version: 3
228
178
  summary: Sinatra app that listens for GitHub post-receive callbacks and deploys your