travis-deploy 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ script: rspec
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - jruby
7
+ notifications:
8
+ irc: "irc.freenode.org#travis"
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+ gem 'rake'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT LICENSE
2
+
3
+ Copyright (c) Sven Fuchs <svenfuchs@artweb-design.de>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Travis Deploy Tool
2
+
3
+ Deployment tool for Travis CI
4
+
5
+ Currently supports the following commands:
6
+
7
+ $ travis deploy [remote] # deploy to remote
8
+ $ travis config [remote] # sync the local config file from travis-keychain and push the config to remote
9
+
10
+ The tool relies on git remotes being defined in `.git/config`. So, in order to deploy to production there needs to be a `production` remote repository defined in the git config.
11
+
12
+ ## Deployment
13
+
14
+ Deploying to `staging` will just push to staging and run the migrations if `-m` was given. One can also pass `-c` in order to configure the app.
15
+
16
+ Deploying to production.
17
+ $ git push staging HEAD:master
18
+ Running migrations.
19
+ $ heroku run rake db:migrate -r staging
20
+
21
+ Deploying to production will also update the production branch and tag the current commit.
22
+
23
+ Updating production branch.
24
+ $ git checkout production
25
+ $ git reset --hard master
26
+ $ git push origin production -f
27
+ Tagging deploy 2011-12-11 16:04.
28
+ $ git tag -a 'deploy.2011-12-11.16-04' -m 'deploy 2011-12-11 16:04'
29
+ $ git push --tags
30
+ $ git checkout master
31
+ Deploying to production.
32
+ $ git push production HEAD:master -f
33
+ Running migrations.
34
+ $ heroku run rake db:migrate -r production
35
+
36
+ WARNING:
37
+
38
+ The production branch is updated using `git reset --hard [branch]` and pushed using `git push origin production -f`.
39
+
40
+ That means that all commits in the `production` branch that are not present in the target branch (e.g. `master`) will be removed from the history of `production`.
41
+
42
+ **So never commit to the production branch directly!**
43
+
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new(:spec)
4
+
5
+ task :default => :spec
data/bin/travis-deploy ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'rubygems'
6
+ require 'travis/deploy'
7
+ require 'thor/runner'
8
+
9
+ klass, task = Thor::Util.find_class_and_task_by_namespace("travis:#{ARGV.shift}")
10
+ ARGV.unshift(task) if task
11
+ klass.start(ARGV, :shell => Thor::Base.shell.new)
@@ -0,0 +1,52 @@
1
+ require 'thor'
2
+
3
+ $stdout.sync = true
4
+
5
+ module Travis
6
+ autoload :Keychain, 'travis/keychain'
7
+
8
+ class Deploy < Thor
9
+ autoload :Config, 'travis/deploy/config'
10
+ autoload :Deploy, 'travis/deploy/deploy'
11
+ autoload :Helper, 'travis/deploy/helper'
12
+ autoload :SecureKey, 'travis/deploy/secure_key'
13
+
14
+ namespace 'travis'
15
+
16
+ desc 'config', 'Sync config between keychain, app and local working directory'
17
+ method_option :env, :aliases => '-e', :type => :string
18
+ method_option :source, :aliases => '-s', :type => :string
19
+ method_option :backup, :aliases => '-b', :type => :boolean, :default => false
20
+
21
+ def config(remote)
22
+ Config.new(shell, remote, options).invoke
23
+ end
24
+
25
+ desc 'deploy', 'Deploy to the given remote'
26
+ method_option :migrate, :aliases => '-m', :type => :boolean, :default => false
27
+ method_option :configure, :aliases => '-c', :type => :boolean, :default => false
28
+
29
+ def deploy(remote)
30
+ Deploy.new(shell, remote, options).invoke
31
+ end
32
+
33
+ desc 'encrypt <slug> <secret>', 'Encrypt string for a repository'
34
+ method_option :host, :aliases => '-h', :type => :string
35
+
36
+ def encrypt(slug, secret)
37
+ puts "\nAbout to encrypt '#{secret}' for '#{slug}'\n\n"
38
+
39
+ encrypted = nil
40
+ begin
41
+ encrypted = SecureKey.new(slug, options[:host]).encrypt(secret)
42
+ rescue SecureKey::FetchKeyError
43
+ abort 'There was an error while fetching public key, please check if you entered correct slug'
44
+ end
45
+
46
+ puts "Please add the following to your .travis.yml file:"
47
+ puts ""
48
+ puts " secure: \"#{Base64.encode64(encrypted).strip.gsub("\n", "\\n")}\""
49
+ puts ""
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,70 @@
1
+ require 'shellwords'
2
+ require 'yaml'
3
+
4
+ module Travis
5
+ class Deploy
6
+ class Config
7
+ include Helper
8
+
9
+ attr_reader :shell, :remote, :env, :options
10
+
11
+ def initialize(shell, remote, options)
12
+ @remote = remote
13
+ @options = options
14
+ @shell = shell
15
+ @env = options['env'] || remote
16
+ end
17
+
18
+ def invoke
19
+ store unless options['source']
20
+ push
21
+ end
22
+
23
+ protected
24
+
25
+ def app
26
+ @app ||= begin
27
+ app = File.basename(Dir.pwd).gsub('travis-', '')
28
+ app = 'web' if app == 'ci'
29
+ app
30
+ end
31
+ end
32
+
33
+ def config
34
+ @config ||= source || keychain.fetch
35
+ end
36
+
37
+ def source
38
+ File.read(options['source']) if options['source']
39
+ end
40
+
41
+ def keychain
42
+ @keychain ||= Keychain.new(app, shell)
43
+ end
44
+
45
+ def store
46
+ backup if backup?
47
+ File.open(filename, 'w+') { |f| f.write(config) }
48
+ end
49
+
50
+ def push
51
+ say 'Configuring the app ...'
52
+ config = Shellwords.escape(YAML.dump(YAML.load(self.config)[env]))
53
+ run "heroku config:add travis_config=#{config} -r #{remote}", :echo => "heroku config:add travis_config=... -r #{remote}"
54
+ end
55
+
56
+ def backup
57
+ say 'Backing up the old config file ...'
58
+ run "cp #{filename} #{filename}.backup"
59
+ end
60
+
61
+ def backup?
62
+ !!options['backup']
63
+ end
64
+
65
+ def filename
66
+ "config/travis.yml"
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,89 @@
1
+ module Travis
2
+ class Deploy
3
+ class Deploy
4
+ include Helper
5
+
6
+ attr_reader :shell, :remote, :options
7
+
8
+ def initialize(shell, remote, options)
9
+ @remote = remote
10
+ @options = options
11
+ @shell = shell
12
+ end
13
+
14
+ def invoke
15
+ if clean?
16
+ tag if remote == 'production'
17
+ configure if configure?
18
+ push
19
+ migrate if migrate?
20
+ else
21
+ error 'There are unstaged changes.'
22
+ end
23
+ end
24
+
25
+ protected
26
+
27
+ attr_reader :remote
28
+
29
+ def clean?
30
+ `git status`.include?('working directory clean')
31
+ end
32
+
33
+ def push
34
+ say "Deploying to #{remote}."
35
+ run "git push #{remote} HEAD:master -f".strip
36
+ end
37
+
38
+ def tag
39
+ say "Updating production branch."
40
+ with_branch('production') do |branch|
41
+ run "git reset --hard #{branch}"
42
+ run 'git push origin production -f'
43
+
44
+ say "Tagging #{version}."
45
+ run "git tag -a '#{version.gsub(':', '-').gsub(' ', '.')}' -m '#{version}'"
46
+ run 'git push --tags'
47
+ end
48
+ end
49
+
50
+ def with_branch(target)
51
+ current = branch
52
+ run "git checkout #{target}"
53
+ yield current
54
+ run "git checkout #{current}"
55
+ end
56
+
57
+ def branch
58
+ `git branch --no-color 2> /dev/null` =~ /\* (.*)$/ && $1
59
+ end
60
+
61
+ def version
62
+ @version ||= "deploy #{Time.now.utc.strftime('%Y-%m-%d %H:%M')}"
63
+ end
64
+
65
+ def configure?
66
+ !!options['configure']
67
+ end
68
+
69
+ def configure
70
+ Config.new(shell, remote, {}).invoke
71
+ end
72
+
73
+ def migrate?
74
+ !!options['migrate']
75
+ end
76
+
77
+ def migrate
78
+ say 'Running migrations'
79
+ run "heroku run rake db:migrate -r #{remote}"
80
+ restart
81
+ end
82
+
83
+ def restart
84
+ say 'Restarting the app ...'
85
+ run "heroku restart -r #{remote}"
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,23 @@
1
+ module Travis
2
+ class Deploy
3
+ module Helper
4
+ protected
5
+
6
+ def run(cmd, options = {})
7
+ cmd = cmd.strip
8
+ puts "$ #{options[:echo] || cmd}" unless options[:echo].is_a?(FalseClass)
9
+ exit unless system(cmd)
10
+ end
11
+
12
+ def say(message)
13
+ shell.say(message, :green)
14
+ end
15
+
16
+ def error(message)
17
+ message = shell.set_color(message, :red)
18
+ shell.error(message)
19
+ exit 1
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'multi_json'
5
+ require 'openssl'
6
+ require 'base64'
7
+
8
+ module Travis
9
+ class Deploy
10
+ class SecureKey
11
+ class FetchKeyError < StandardError; end
12
+ attr_reader :slug, :host
13
+
14
+ def initialize(slug, host = nil)
15
+ @slug = slug
16
+ @host = host || "api.travis-ci.org"
17
+ end
18
+
19
+ def encrypt(secret)
20
+ encrypted = key.public_encrypt(secret)
21
+ end
22
+
23
+ def key
24
+ @key ||= fetch_key
25
+ end
26
+
27
+ def fetch_key
28
+ uri = URI.parse("https://#{host}/repos/#{slug}/key")
29
+
30
+ http = Net::HTTP.new(uri.host, uri.port)
31
+ http.use_ssl = true
32
+
33
+ request = Net::HTTP::Get.new(uri.request_uri, 'Accept' => 'application/vnd.travis-ci.2+json')
34
+
35
+ response = http.request(request)
36
+
37
+ if response.code.to_i == 200
38
+ body = MultiJson.decode(response.body)
39
+ public_key = body['key']
40
+ begin
41
+ OpenSSL::PKey::RSA.new(public_key)
42
+ rescue OpenSSL::PKey::RSAError
43
+ # unsure why, but it seems that some keys are generated in a
44
+ # wrong way
45
+ public_key.gsub!('RSA PUBLIC KEY', 'PUBLIC KEY')
46
+ OpenSSL::PKey::RSA.new(public_key)
47
+ end
48
+ else
49
+ raise FetchKeyError
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,39 @@
1
+ module Travis
2
+ class Keychain
3
+ include Deploy::Helper
4
+
5
+ attr_reader :app, :shell, :dir
6
+
7
+ def initialize(app, shell, dir = '../travis-keychain')
8
+ @app = app
9
+ @shell = shell
10
+ @dir = File.expand_path(dir)
11
+ end
12
+
13
+ def fetch
14
+ chdir { pull }
15
+ read
16
+ end
17
+
18
+ protected
19
+
20
+ def pull
21
+ error 'There are unstaged changes in your travis-keychain working directory.' unless clean?
22
+ say 'Fetching the keychain ...'
23
+ run 'git pull'
24
+ end
25
+
26
+ def read
27
+ File.read(File.join(dir, "config/travis.#{app}.yml")) || ''
28
+ end
29
+
30
+ def chdir(&block)
31
+ FileUtils.mkdir_p(dir)
32
+ Dir.chdir(dir, &block)
33
+ end
34
+
35
+ def clean?
36
+ `git status`.include?('working directory clean')
37
+ end
38
+ end
39
+ end
data/lib/travis_cli.rb ADDED
@@ -0,0 +1 @@
1
+ require 'travis/deploy'
@@ -0,0 +1,32 @@
1
+ ENV['RAILS_ENV'] = ENV['ENV'] = 'test'
2
+
3
+ require 'travis/deploy'
4
+ require 'webmock/rspec'
5
+
6
+ RSpec.configure do |c|
7
+ c.before(:each) { Time.stub(:now => Time.now.utc) }
8
+ end
9
+
10
+ module Mock
11
+ class Shell
12
+ def messages
13
+ @messages ||= []
14
+ end
15
+
16
+ def say(*args)
17
+ messages << args
18
+ end
19
+ alias :error :say
20
+ end
21
+ end
22
+
23
+ module Kernel
24
+ def capture_stdout
25
+ out = StringIO.new
26
+ $stdout = out
27
+ yield
28
+ return out.string
29
+ ensure
30
+ $stdout = STDOUT
31
+ end
32
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Travis::Deploy::Config do
4
+ let(:shell) { Mock::Shell.new }
5
+ let(:config) { "staging:\n foo: bar" }
6
+
7
+ before :each do
8
+ Travis::Deploy::Config.any_instance.stub(:clean? => true)
9
+ Travis::Deploy::Config.any_instance.stub(:run)
10
+ Travis::Keychain.any_instance.stub(:fetch => config)
11
+ File.stub(:open)
12
+ end
13
+
14
+ describe 'sync' do
15
+ it 'fetches the config from the keychain' do
16
+ command = Travis::Deploy::Config.new(shell, 'staging', {})
17
+ command.send(:keychain).should_receive(:fetch).and_return(config)
18
+ command.invoke
19
+ end
20
+
21
+ it 'writes the config to the local config file' do
22
+ command = Travis::Deploy::Config.new(shell, 'staging', {})
23
+ File.should_receive(:open).with { |path, mode| path =~ %r(config/travis.yml) }
24
+ command.invoke
25
+ end
26
+
27
+ it 'pushes the config to the given heroku remote' do
28
+ command = Travis::Deploy::Config.new(shell, 'staging', {})
29
+ command.should_receive(:run).with { |cmd, options| cmd =~ /heroku config:add travis_config=.* -r staging/m }
30
+ command.invoke
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ describe Travis::Deploy::Deploy do
4
+ let(:shell) { Mock::Shell.new }
5
+
6
+ before :each do
7
+ $stdout = StringIO.new
8
+ Travis::Deploy::Deploy.any_instance.stub(:clean? => true)
9
+ Travis::Deploy::Deploy.any_instance.stub(:branch => 'master')
10
+ File.stub(:open)
11
+ end
12
+
13
+ after :each do
14
+ $stdout = STDOUT
15
+ end
16
+
17
+ describe 'with a clean working directory' do
18
+ describe 'given remote "production"' do
19
+ let(:command) { Travis::Deploy::Deploy.new(shell, 'production', {}) }
20
+
21
+ before :each do
22
+ command.stub(:system => true)
23
+ end
24
+
25
+ it 'switches to the production branch' do
26
+ command.should_receive(:system).with('git checkout production').and_return(true)
27
+ command.invoke
28
+ end
29
+
30
+ it 'resets the production branch to the current branch' do
31
+ command.should_receive(:system).with('git reset --hard master').and_return(true)
32
+ command.invoke
33
+ end
34
+
35
+ it 'pushes the production branch to origin' do
36
+ command.should_receive(:system).with('git push origin production -f').and_return(true)
37
+ command.invoke
38
+ end
39
+
40
+ it 'switches back to the previous branch' do
41
+ command.should_receive(:system).with('git checkout master').and_return(true)
42
+ command.invoke
43
+ end
44
+
45
+ it 'tags the current commit ' do
46
+ command.should_receive(:system).with { |cmd| cmd =~ /git tag -a 'deploy.*' -m 'deploy.*'/ }.and_return(true)
47
+ command.invoke
48
+ end
49
+
50
+ it 'pushes the tag to origin' do
51
+ command.should_receive(:system).with('git push --tags').and_return(true)
52
+ command.invoke
53
+ end
54
+
55
+ it 'pushes to the given remote' do
56
+ command.should_receive(:system).with('git push production HEAD:master -f').and_return(true)
57
+ command.invoke
58
+ end
59
+ end
60
+
61
+ describe 'given the remote "staging"' do
62
+ let(:command) { Travis::Deploy::Deploy.new(shell, 'staging', {}) }
63
+
64
+ before :each do
65
+ command.stub(:system => true)
66
+ end
67
+
68
+ it 'does not switch to the production branch' do
69
+ command.should_not_receive(:system).with('git checkout production')
70
+ command.invoke
71
+ end
72
+
73
+ it 'does not tag the current commit if the given remote is "staging"' do
74
+ command.should_not_receive(:system).with { |cmd| cmd =~ /git tag -a 'deploy .*' -m 'deploy .*'/ }
75
+ command.invoke
76
+ end
77
+
78
+ it 'pushes to the given remote' do
79
+ command.should_receive(:system).with('git push staging HEAD:master -f').and_return(true)
80
+ command.invoke
81
+ end
82
+ end
83
+
84
+ it 'migrates the database if --migrate is given' do
85
+ command = Travis::Deploy::Deploy.new(shell, 'production', 'migrate' => true)
86
+ command.stub(:system => true)
87
+ command.should_receive(:system).with('heroku run rake db:migrate -r production').and_return(true)
88
+ command.invoke
89
+ end
90
+
91
+ it 'restarts the app when the database is migrated' do
92
+ command = Travis::Deploy::Deploy.new(shell, 'production', 'migrate' => true)
93
+ command.stub(:system => true)
94
+ command.should_receive(:system).with('heroku restart -r production').and_return(true)
95
+ command.invoke
96
+ end
97
+
98
+ it 'configures the application if --configure is given' do
99
+ command = Travis::Deploy::Deploy.new(shell, 'production', 'configure' => true)
100
+ command.stub(:system => true)
101
+ command.should_receive(:configure)
102
+ command.invoke
103
+ end
104
+ end
105
+
106
+ describe 'with a dirty working directory' do
107
+ before :each do
108
+ end
109
+
110
+ it 'outputs an error message' do
111
+ command = Travis::Deploy::Deploy.new(shell, 'production', {})
112
+ command.stub(:clean? => false)
113
+ command.should_receive(:error).with('There are unstaged changes.')
114
+ command.invoke
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe Travis::Deploy::SecureKey do
4
+ describe 'key' do
5
+ before do
6
+ # Travis API requests redirect to HTTPS
7
+ stub_request(:any, %r(^http://secure.travis-ci\.org/)).to_return do |request|
8
+ {
9
+ :body => '',
10
+ :status => [301, 'Moved Permanently'],
11
+ :headers => {
12
+ 'Location' => request.uri.to_s.sub(/^http/, 'https')
13
+ }
14
+ }
15
+ end
16
+ end
17
+
18
+ it 'allows to pass host' do
19
+ slug = 'travis-ci/travis-cli'
20
+ public_key = <<-KEY
21
+ -----BEGIN RSA PUBLIC KEY-----
22
+ MIGJAoGBAON8DcLBjBwkspYPtHvdjoOYwjsUJOh5Otr+TEOlfvUgDjc/kGRjP6ku
23
+ THug6JpLU0GlRqOr4u9sFuJCKlDjCJV+2vWzP4e+3zrP9hZGdQUcbG2fhSOBn2Wv
24
+ 9wFMn+WFgJ3fEsvIb5yzNsRnH3mMe1MZkTPBZIrt+6M1lM1yOZQpAgMBAAE=
25
+ -----END RSA PUBLIC KEY-----
26
+ KEY
27
+
28
+ stub_request(:get, "https://foo.travis-ci.org/repos/#{slug}/key").to_return(
29
+ {
30
+ :body => %({"key":#{MultiJson.dump(public_key)}}),
31
+ :status => [200, 'OK']
32
+ }
33
+ )
34
+
35
+ secure_key = Travis::Deploy::SecureKey.new(slug, 'foo.travis-ci.org')
36
+
37
+ expect{
38
+ secure_key.key
39
+ }.to_not raise_error(Travis::Deploy::SecureKey::FetchKeyError)
40
+
41
+ secure_key.key.to_pem.should == OpenSSL::PKey::RSA.new(public_key).to_pem
42
+ end
43
+
44
+ it 'fetches the public key for a valid slug' do
45
+ slug = 'travis-ci/travis-cli'
46
+ public_key = <<-KEY
47
+ -----BEGIN RSA PUBLIC KEY-----
48
+ MIGJAoGBAON8DcLBjBwkspYPtHvdjoOYwjsUJOh5Otr+TEOlfvUgDjc/kGRjP6ku
49
+ THug6JpLU0GlRqOr4u9sFuJCKlDjCJV+2vWzP4e+3zrP9hZGdQUcbG2fhSOBn2Wv
50
+ 9wFMn+WFgJ3fEsvIb5yzNsRnH3mMe1MZkTPBZIrt+6M1lM1yOZQpAgMBAAE=
51
+ -----END RSA PUBLIC KEY-----
52
+ KEY
53
+
54
+ stub_request(:get, "https://api.travis-ci.org/repos/#{slug}/key").to_return(
55
+ {
56
+ :body => %({"key":#{MultiJson.dump(public_key)}}),
57
+ :status => [200, 'OK']
58
+ }
59
+ ).with(:headers => {'Accept' => 'application/vnd.travis-ci.2+json' })
60
+
61
+ secure_key = Travis::Deploy::SecureKey.new(slug)
62
+
63
+ expect{
64
+ secure_key.key
65
+ }.to_not raise_error(Travis::Deploy::SecureKey::FetchKeyError)
66
+
67
+ secure_key.key.to_pem.should == OpenSSL::PKey::RSA.new(public_key).to_pem
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Travis::Keychain do
4
+ let(:shell) { stub('shell', :say => nil, :error => nil) }
5
+ let(:keychain) { Travis::Keychain.new('hub', shell) }
6
+
7
+ before :each do
8
+ keychain.stub(:system => true)
9
+ keychain.stub(:`)
10
+ keychain.stub(:clean? => true)
11
+ File.stub(:read)
12
+ end
13
+
14
+ def fetch
15
+ capture_stdout do
16
+ keychain.fetch
17
+ end
18
+ end
19
+
20
+ describe 'fetch' do
21
+ it 'changes to the keychain directory' do
22
+ Dir.should_receive(:chdir).with { |path| path =~ %r(/travis-keychain$) }
23
+ fetch
24
+ end
25
+
26
+ it 'errors if the working directory is dirty' do
27
+ keychain.stub(:clean? => false)
28
+ keychain.should_receive(:error).with('There are unstaged changes in your travis-keychain working directory.')
29
+ fetch
30
+ end
31
+
32
+ it 'pulls changes from origin' do
33
+ keychain.should_receive(:run).with('git pull')
34
+ fetch
35
+ end
36
+
37
+ it 'reads the configuration' do
38
+ File.should_receive(:read).with { |path| path =~ %r(config/travis.hub.yml$) }
39
+ fetch
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'travis-deploy'
5
+ gem.version = '0.1.0'
6
+
7
+ gem.authors = ['Travis Deploy Tool']
8
+ gem.email = ['contact@travis-ci.org']
9
+ gem.description = 'A command-line interface to Travis CI'
10
+ gem.summary = gem.description
11
+ gem.homepage = 'https://github.com/travis-ci/travis-cli'
12
+
13
+ gem.add_dependency 'thor', '~> 0.16.0'
14
+ gem.add_dependency 'multi_json', '~> 1.3'
15
+ gem.add_development_dependency 'rspec', '~> 2.6'
16
+ gem.add_development_dependency 'webmock', '~> 1.8'
17
+
18
+ gem.files = `git ls-files`.split($/)
19
+ gem.executables = gem.files.grep(/^bin/).map{|f| File.basename(f) }
20
+ gem.test_files = gem.files.grep(/^spec/)
21
+ gem.require_paths = ['lib']
22
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: travis-deploy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Travis Deploy Tool
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.16.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.16.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: multi_json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.3'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.3'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.6'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.6'
62
+ - !ruby/object:Gem::Dependency
63
+ name: webmock
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '1.8'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '1.8'
78
+ description: A command-line interface to Travis CI
79
+ email:
80
+ - contact@travis-ci.org
81
+ executables:
82
+ - travis-deploy
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - .travis.yml
88
+ - Gemfile
89
+ - LICENSE
90
+ - README.md
91
+ - Rakefile
92
+ - bin/travis-deploy
93
+ - lib/travis/deploy.rb
94
+ - lib/travis/deploy/config.rb
95
+ - lib/travis/deploy/deploy.rb
96
+ - lib/travis/deploy/helper.rb
97
+ - lib/travis/deploy/secure_key.rb
98
+ - lib/travis/keychain.rb
99
+ - lib/travis_cli.rb
100
+ - spec/spec_helper.rb
101
+ - spec/travis/deploy/config_spec.rb
102
+ - spec/travis/deploy/deploy_spec.rb
103
+ - spec/travis/deploy/secure_key_spec.rb
104
+ - spec/travis/keychain_spec.rb
105
+ - travis-deploy.gemspec
106
+ homepage: https://github.com/travis-ci/travis-cli
107
+ licenses: []
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 1.8.23
127
+ signing_key:
128
+ specification_version: 3
129
+ summary: A command-line interface to Travis CI
130
+ test_files:
131
+ - spec/spec_helper.rb
132
+ - spec/travis/deploy/config_spec.rb
133
+ - spec/travis/deploy/deploy_spec.rb
134
+ - spec/travis/deploy/secure_key_spec.rb
135
+ - spec/travis/keychain_spec.rb
136
+ has_rdoc: