skynet-deploy 0.9.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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