winnie 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Ragnarson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,11 @@
1
+ = winnie
2
+
3
+ Winnie command line client.
4
+
5
+ = Meta
6
+
7
+ Created and maintained by Ragnarson team, inspired by heroku gem.
8
+
9
+ == Copyright
10
+
11
+ Copyright (c) 2010 Ragnarson. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "winnie"
8
+ gem.summary = %Q{Winnie command line tool}
9
+ gem.description = %Q{Command line tool which allows interacting with winnie's API}
10
+ gem.email = "winnie-devs@ragnarson.com"
11
+ gem.homepage = "http://winniecloud.net"
12
+ gem.authors = ["winnie"]
13
+ gem.add_dependency "json"
14
+ gem.add_dependency "rest-client"
15
+ gem.add_development_dependency "rspec", ">= 1.2.9"
16
+ gem.add_development_dependency "fakefs"
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ require 'spec/rake/spectask'
24
+ Spec::Rake::SpecTask.new(:spec) do |spec|
25
+ spec.libs << 'lib' << 'spec'
26
+ spec.spec_files = FileList['spec/**/*_spec.rb']
27
+ end
28
+
29
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
30
+ spec.libs << 'lib' << 'spec'
31
+ spec.pattern = 'spec/**/*_spec.rb'
32
+ spec.rcov = true
33
+ end
34
+
35
+ task :spec => :check_dependencies
36
+
37
+ task :default => :spec
38
+
39
+ require 'rake/rdoctask'
40
+ Rake::RDocTask.new do |rdoc|
41
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
42
+
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = "winnie #{version}"
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/bin/winnie ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ require File.join(File.dirname(__FILE__), '../lib/winnie/winnie')
3
+
4
+ args = ARGV.dup
5
+ ARGV.clear
6
+ command = args.shift.strip rescue 'help'
7
+
8
+ Winnie::Command.run(command, args)
@@ -0,0 +1,86 @@
1
+ module Winnie
2
+ class Client
3
+ def initialize(api_key)
4
+ @api_key = api_key
5
+ end
6
+
7
+ def host
8
+ ENV['WINNIE_HOST'] || 'admin.winniecloud.net'
9
+ end
10
+
11
+ def winnie_url
12
+ "http://#{host}"
13
+ end
14
+
15
+ def account
16
+ get('/account')
17
+ end
18
+
19
+ def apps
20
+ get('/apps')
21
+ end
22
+
23
+ def command(command, code_name)
24
+ post("/apps/#{code_name}/command", :body => command)
25
+ end
26
+
27
+ def post(path, params = {})
28
+ request(path, :post, params)
29
+ end
30
+
31
+ def get(path)
32
+ request(path, :get)
33
+ end
34
+
35
+ def request(path, method, params = {})
36
+ headers = {:accept => 'application/json'}.merge(Client.winnie_headers)
37
+ params.merge!(:api_key => @api_key)
38
+
39
+ RestClient::Request.execute(
40
+ :method => method,
41
+ :url => "#{winnie_url}#{path}",
42
+ :headers => headers,
43
+ :payload => params
44
+ ) { |response, request| process_response(response) }
45
+ end
46
+
47
+ class UnauthorizedException < Exception; end
48
+ class ResourceNotFoundException < Exception; end
49
+ class CommandFailedException < Exception; end
50
+
51
+ def self.version
52
+ version_file = File.join(File.dirname(__FILE__), '..', '..', 'VERSION')
53
+ @@version ||= File.read(version_file).strip
54
+ end
55
+
56
+ private
57
+
58
+ def self.winnie_headers
59
+ {'User-Agent' => "winnie-gem-#{version}",
60
+ 'X-Ruby-Version' => RUBY_VERSION}
61
+ end
62
+
63
+ def process_response(response)
64
+ # TODO: this fragment could look better
65
+ if [404, 500, 401].include?(response.code)
66
+
67
+ exception = case response.code
68
+ when 404; ResourceNotFoundException
69
+ when 500; CommandFailedException
70
+ when 401; raise UnauthorizedException.new
71
+ end
72
+
73
+ error = JSON.parse(response.body)['error']
74
+ raise exception.new(error)
75
+ end
76
+
77
+ response.return!
78
+
79
+ if response.code == 302 and response.args[:url] =~ /user_session/
80
+ raise UnauthorizedException.new
81
+ end
82
+
83
+ JSON.parse(response.body)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,38 @@
1
+ module Winnie
2
+ class Command
3
+ extend Helpers
4
+
5
+ def self.run(name, *args)
6
+ begin
7
+ class_name, command_name = name.split(':')
8
+ command_name ||= 'run'
9
+
10
+ begin
11
+ command_class = eval("Winnie::Commands::#{class_name.capitalize}")
12
+ rescue NameError
13
+ command_class = Winnie::Commands::App
14
+ command_name = class_name
15
+ end
16
+
17
+ command = command_class.new(args)
18
+
19
+ if command.respond_to?(command_name)
20
+ command.send(command_name)
21
+ else
22
+ raise UnknownCommandException.new
23
+ end
24
+
25
+ rescue UnknownCommandException
26
+ error 'Unknown command'
27
+ rescue Winnie::Client::UnauthorizedException
28
+ error "Your API key is not correct\nUse 'winnie auth' command to re-enter your winnie API key"
29
+ rescue Winnie::Commands::ApplicationNotSpecyfiedException
30
+ error "Application not specified\nUse --app <code name> to specify the application"
31
+ rescue Winnie::Client::ResourceNotFoundException, Winnie::Client::CommandFailedException => e
32
+ error e.message
33
+ end
34
+ end
35
+
36
+ class UnknownCommandException < Exception; end
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ module Winnie
2
+ module Commands
3
+ class App < Base
4
+ def run
5
+ list
6
+ end
7
+
8
+ def command
9
+ response = winnie.command(args.first, code_name)
10
+ display response['result']
11
+ end
12
+
13
+ def list
14
+ apps = winnie.apps
15
+
16
+ unless apps.empty?
17
+ display_columns "Name", "Code name"
18
+ line
19
+ apps.each do |app|
20
+ display_columns app['app']['name'], app['app']['code_name']
21
+ end
22
+ else
23
+ display "You don't have any apps yet"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,49 @@
1
+ require 'fileutils'
2
+
3
+ module Winnie
4
+ module Commands
5
+ class Auth < Base
6
+ attr_accessor :api_key
7
+
8
+ def initialize(*args)
9
+ super(args)
10
+ load_api_key if api_key_exists?
11
+ end
12
+
13
+ def run
14
+ confirm('Do you want to change your API key?') if api_key_exists?
15
+ ask_for_api_key
16
+ save_api_key
17
+ validate_api_key
18
+ end
19
+
20
+ def ask_for_api_key
21
+ display "Type your Winnie API key"
22
+ display "Key: ", false
23
+ self.api_key = ask
24
+ end
25
+
26
+ def save_api_key
27
+ FileUtils.mkdir_p(config_path)
28
+ File.open(api_key_path, 'w') { |file| file << api_key }
29
+ end
30
+
31
+ def load_api_key
32
+ self.api_key = File.read(api_key_path)
33
+ end
34
+
35
+ def validate_api_key
36
+ winnie.account # If it's not correct, Winnie::Client::UnauthorizedException will be raised
37
+ display 'Your winnie API key is OK!'
38
+ end
39
+
40
+ def api_key_exists?
41
+ File.exists?(api_key_path)
42
+ end
43
+
44
+ def api_key_path
45
+ File.join(config_path, 'api_key')
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,39 @@
1
+ module Winnie
2
+ module Commands
3
+ class Base
4
+ attr_reader :winnie, :args
5
+
6
+ include Winnie::Helpers
7
+
8
+ def initialize(*args)
9
+ @args = args.flatten
10
+ extract_options(@args)
11
+ end
12
+
13
+ def extract_options(args)
14
+ return if args.empty?
15
+
16
+ OptionParser.new do |opts|
17
+ opts.on("-a", "--app [CODE_NAME]", :text, "Run for given application") do |a|
18
+ @code_name = a
19
+ end
20
+ end.parse!(@args)
21
+ end
22
+
23
+ def code_name
24
+ raise ApplicationNotSpecyfiedException.new unless @code_name
25
+ @code_name
26
+ end
27
+
28
+ def winnie
29
+ auth = Winnie::Commands::Auth.new
30
+ @winnie ||= Winnie::Client.new(auth.api_key)
31
+ end
32
+
33
+ def config_path
34
+ File.expand_path('~/.winnie')
35
+ end
36
+ end
37
+ class ApplicationNotSpecyfiedException < Exception; end
38
+ end
39
+ end
@@ -0,0 +1,12 @@
1
+ module Winnie
2
+ module Commands
3
+ class Help < Base
4
+ def run
5
+ display_columns 'auth', 'Configure your winnie username and password'
6
+ display_columns 'command', 'Run single ruby command'
7
+ display_columns 'list', 'List your applications'
8
+ display_columns 'help', 'Show this information'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ module Winnie
2
+ module Helpers
3
+ def display(message, new_line = true)
4
+ STDOUT << message
5
+ STDOUT << "\n" if new_line
6
+ end
7
+
8
+ def display_columns(*columns)
9
+ columns.each { |field| display(field.to_s.ljust(20), false) }
10
+ display ''
11
+ end
12
+
13
+ def line
14
+ display '-' * 45
15
+ end
16
+
17
+ def error(message)
18
+ STDERR << message << "\n"
19
+ exit 1
20
+ end
21
+
22
+ def ask
23
+ gets.strip
24
+ end
25
+
26
+ def confirm(message)
27
+ loop do
28
+ STDERR << message << " (Y/N): "
29
+ case ask.upcase
30
+ when 'Y'; break
31
+ when 'N'; exit 0
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ # TODO: loop here, and load all commands
2
+ module Winnie; end
3
+ require 'rubygems'
4
+ require 'rest_client'
5
+ require 'json'
6
+ require 'optparse'
7
+ require 'winnie/helpers'
8
+ require 'winnie/client'
9
+ require 'winnie/command'
10
+ require 'winnie/commands/base'
11
+ Dir["#{File.dirname(__FILE__)}/commands/*"].each { |c| require c }
@@ -0,0 +1,142 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Winnie::Client do
4
+ before do
5
+ Winnie::Client.stub(:winnie_headers).and_return({})
6
+ @client = Winnie::Client.new('secret_one')
7
+ RestClient::Request.stub!(:execute)
8
+ end
9
+
10
+ describe "request" do
11
+ it "should make a request to give URL" do
12
+ RestClient::Request.should_receive(:execute).with(
13
+ request_parameters('/account', :get)
14
+ )
15
+ @client.request('/account', :get)
16
+ end
17
+
18
+ it "should include provided parameters in the request" do
19
+ RestClient::Request.should_receive(:execute).with(
20
+ request_parameters('/account', :post,
21
+ :payload => {:api_key => 'secret_one', :name => 'test'}
22
+ )
23
+ )
24
+ @client.request('/account', :post, :name => 'test')
25
+ end
26
+
27
+ it "should include api_key in the request parameters" do
28
+ @client = Winnie::Client.new('AABBCC')
29
+ RestClient::Request.should_receive(:execute).with(
30
+ request_parameters('/account', :get,
31
+ :payload => {:api_key => 'AABBCC'}
32
+ )
33
+ )
34
+ @client.request('/account', :get)
35
+ end
36
+
37
+ it "should accept json responses only" do
38
+ RestClient::Request.should_receive(:execute).with(
39
+ request_parameters('/account', :get,
40
+ :headers => {:accept => 'application/json'}
41
+ )
42
+ )
43
+ @client.request('/account', :get)
44
+ end
45
+
46
+ it "should pass response to process_response method" do
47
+ response = mock(RestClient::Response)
48
+ request = mock(RestClient::Request)
49
+ @client.should_receive(:process_response).with(response)
50
+ RestClient::Request.should_receive(:execute).with(request_parameters('/account', :get)).and_yield(response, request)
51
+
52
+ @client.request('/account', :get)
53
+ end
54
+
55
+
56
+ def request_parameters(path, method, params = {})
57
+ {:payload => {:api_key => 'secret_one'},
58
+ :method => method,
59
+ :headers => {:accept => 'application/json'},
60
+ :url => "http://admin.winniecloud.net#{path}"
61
+ }.merge(params)
62
+ end
63
+ end
64
+
65
+ describe "process_response" do
66
+ before do
67
+ @response = mock(RestClient::Response, :code => 200, :body => '{}', :return! => nil)
68
+ @request = mock(RestClient::Request)
69
+ RestClient::Request.stub(:execute).and_yield(@response, @request)
70
+ end
71
+
72
+ it "should not follow redirections" do
73
+ @response.should_receive(:return!)
74
+ @client.get('/account')
75
+ end
76
+
77
+ it "should raise UnauthorizedException when response has 401 code" do
78
+ @response.stub(:code).and_return(401)
79
+ lambda {
80
+ @client.get('/account')
81
+ }.should raise_error(Winnie::Client::UnauthorizedException)
82
+ end
83
+
84
+ it "should raise UnauthorizedException when it gets redirected to login page" do
85
+ @response.stub(:args).and_return({:url => 'user_session'})
86
+ @response.stub(:code).and_return(302)
87
+
88
+ lambda {
89
+ @client.get('/account')
90
+ }.should raise_error(Winnie::Client::UnauthorizedException)
91
+ end
92
+
93
+ it "should raise ResourceNotFoundException when response has 404 code" do
94
+ @response.stub(:code).and_return(404)
95
+ @response.stub(:body).and_return({'error' => 'App not found'}.to_json)
96
+
97
+ lambda {
98
+ @client.post('/apps/flower/command', :body => 'puts User.count')
99
+ }.should raise_error(Winnie::Client::ResourceNotFoundException, 'App not found')
100
+ end
101
+
102
+ it "should raise CommandFailedException when response has 500 code" do
103
+ @response.stub(:code).and_return(500)
104
+ @response.stub(:body).and_return({'error' => 'random error happened'}.to_json)
105
+
106
+ lambda {
107
+ @client.post('/apps/flower/command', :body => 'puts User.count')
108
+ }.should raise_error(Winnie::Client::CommandFailedException, 'random error happened')
109
+ end
110
+ end
111
+
112
+ it "should make GET request to given path" do
113
+ @client.should_receive(:request).with('/account', :get)
114
+ @client.get('/account')
115
+ end
116
+
117
+ it "should make POST request to given path with parameters" do
118
+ @client.should_receive(:request).with('/account', :post, :name => 'pink-one')
119
+ @client.post('/account', :name => 'pink-one')
120
+ end
121
+
122
+ describe "API methods" do
123
+ it "should get the list of user applications" do
124
+ @client.should_receive(:get).with('/apps')
125
+ @client.apps
126
+ end
127
+
128
+ it "should get account info" do
129
+ @client.should_receive(:get).with('/account')
130
+ @client.account
131
+ end
132
+
133
+ it "should send command to winnie" do
134
+ @client.should_receive(:post).with('/apps/flower-16/command', :body => 'User[:bob].destroy')
135
+ @client.command('User[:bob].destroy', 'flower-16')
136
+ end
137
+ end
138
+
139
+ it "should return winnie-app URL" do
140
+ @client.winnie_url.should == "http://#{@client.host}"
141
+ end
142
+ end
@@ -0,0 +1,68 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Winnie::Command do
4
+ describe "run" do
5
+ before do
6
+ @command = mock(Winnie::Commands::Help.new, :run => '')
7
+ @command.stub!(:respond_to?).and_return(true)
8
+ Winnie::Commands::Help.stub!(:new).and_return(@command)
9
+ end
10
+
11
+ it "should create command class object" do
12
+ Winnie::Command.should_receive(:eval).with('Winnie::Commands::Help').and_return(Winnie::Commands::Help)
13
+ Winnie::Command.run('help')
14
+ end
15
+
16
+ describe "when command class exists" do
17
+ describe "and command name is provided" do
18
+ it "should parse command name and invoke it" do
19
+ @command.should_receive(:connection).and_return(true)
20
+ Winnie::Command.run('help:connection')
21
+ end
22
+ end
23
+
24
+ describe "and command name is not provided" do
25
+ it "should invoke run method" do
26
+ @command.should_receive(:run).and_return(true)
27
+ Winnie::Command.run('help').should be_true
28
+ end
29
+ end
30
+ end
31
+
32
+ describe "when command class doesn't exist" do
33
+ before do
34
+ @app = mock('Winnie::Commands::App', :list => [])
35
+ Winnie::Commands::App.stub(:new).and_return(@app)
36
+ end
37
+
38
+ it "should use App command class as default" do
39
+ Winnie::Commands::App.should_receive(:new).and_return(@app)
40
+ Winnie::Command.run('list')
41
+ end
42
+
43
+ it "should use command class name as command name" do
44
+ @app.should_receive(:list)
45
+ Winnie::Command.run('list')
46
+ end
47
+ end
48
+
49
+ it "should notify user when resource doesn't exist" do
50
+ app = mock(Winnie::Commands::App)
51
+ app.should_receive(:command).and_raise(Winnie::Client::ResourceNotFoundException.new('App not found'))
52
+ Winnie::Commands::App.stub(:new).and_return(app)
53
+
54
+ Winnie::Command.should_receive(:error).with('App not found')
55
+
56
+ Winnie::Command.run('command', ["'puts User.count'", '--app', 'flower'])
57
+ end
58
+
59
+ it "should notify user when command doesn't exist" do
60
+ Winnie::Command.should_receive(:error).with('Unknown command')
61
+ Winnie::Command.run('unknown')
62
+
63
+ @command.should_receive(:respond_to?).with("foooo").and_return(false)
64
+ Winnie::Command.should_receive(:error).with('Unknown command')
65
+ Winnie::Command.run('help:foooo')
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,56 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Winnie::Commands::App do
4
+ before do
5
+ @app = Winnie::Commands::App.new('--app', 'flower')
6
+ @app.stub(:display_columns)
7
+ @app.stub(:line)
8
+ @client = mock(Winnie::Client.new('secret-api-key'))
9
+ @app.stub(:winnie).and_return(@client)
10
+ end
11
+
12
+ describe "when user has some apps" do
13
+ it "should list apps" do
14
+ @client.should_receive(:apps).and_return(apps)
15
+ @app.should_receive(:display_columns).exactly(3)
16
+ @app.should_receive(:line)
17
+ @app.list
18
+ end
19
+ end
20
+
21
+ describe "when user doesn't have any app" do
22
+ it "should inform the user that he doesn't have any app" do
23
+ @client.should_receive(:apps).and_return([])
24
+ @app.should_receive(:display).with("You don't have any apps yet")
25
+ @app.list
26
+ end
27
+ end
28
+
29
+ describe "running commands" do
30
+ before do
31
+ @app = Winnie::Commands::App.new('--app', 'shop-16', "Product.cleanup_cache!")
32
+ @app.stub(:display_columns)
33
+ @app.stub(:display)
34
+ @app.stub(:line)
35
+ @app.stub(:winnie).and_return(@client)
36
+ end
37
+
38
+ it "should send command to winnie given as a command line parameter" do
39
+ @client.should_receive(:command).with('Product.cleanup_cache!', 'shop-16').and_return({})
40
+ @app.command
41
+ end
42
+
43
+ it "should display the result" do
44
+ @client.should_receive(:command).with('Product.cleanup_cache!', 'shop-16').and_return('result' => 'foo')
45
+ @app.should_receive(:display).with('foo')
46
+ @app.command
47
+ end
48
+ end
49
+ end
50
+
51
+ def apps
52
+ [
53
+ {"app" => {"name" => "Green One", "code_name" => "green-one"}},
54
+ {"app" => {"name" => "Pink", "code_name" => "pink"}}
55
+ ]
56
+ end
@@ -0,0 +1,92 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Winnie::Commands::Auth do
4
+ include FakeFS::SpecHelpers
5
+
6
+ before do
7
+ @auth = Winnie::Commands::Auth.new
8
+ @auth.stub(:display)
9
+ end
10
+
11
+ describe "initialize" do
12
+ describe "when API key doesn't exist" do
13
+ it "should not load API key" do
14
+ @auth.api_key.should be_nil
15
+ end
16
+ end
17
+
18
+ describe "when API key exists" do
19
+ before { create_api_key_file('NobodyKnowsIt') }
20
+
21
+ it "should load API key" do
22
+ auth = Winnie::Commands::Auth.new
23
+ auth.api_key.should == 'NobodyKnowsIt'
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "run" do
29
+ before do
30
+ @auth.stub(:ask_for_api_key)
31
+ @auth.stub(:save_api_key)
32
+ @auth.stub(:validate_api_key)
33
+ end
34
+
35
+ describe "when API key doesn't exist" do
36
+ it "should ask for API key" do
37
+ @auth.should_receive(:ask_for_api_key)
38
+ @auth.run
39
+ end
40
+
41
+ it "should save API key" do
42
+ @auth.should_receive(:save_api_key)
43
+ @auth.run
44
+ end
45
+
46
+ it "should validate API key" do
47
+ @auth.should_receive(:validate_api_key)
48
+ @auth.run
49
+ end
50
+ end
51
+
52
+ describe "when API key exists" do
53
+ it "should ask if overwrite API key" do
54
+ @auth.should_receive(:confirm).with('Do you want to change your API key?')
55
+ @auth.stub!(:api_key_exists?).and_return(true)
56
+ @auth.run
57
+ end
58
+ end
59
+ end
60
+
61
+ describe "save_api_key" do
62
+ before { @auth.api_key = 'secret_api_key' }
63
+
64
+ it "should create config directory" do
65
+ FileUtils.should_receive(:mkdir_p).with(@auth.config_path)
66
+ @auth.save_api_key
67
+ end
68
+
69
+ it "should save API key to file" do
70
+ @auth.save_api_key
71
+ key = File.read(@auth.api_key_path)
72
+ key.should == 'secret_api_key'
73
+ end
74
+ end
75
+
76
+ describe "load_api_key" do
77
+ before { create_api_key_file('VerySecretOne') }
78
+
79
+ it "should load api key from a file" do
80
+ @auth.load_api_key
81
+ @auth.api_key.should == 'VerySecretOne'
82
+ end
83
+ end
84
+
85
+ it "should return api_key_path" do
86
+ @auth.api_key_path.should == File.join(@auth.config_path, 'api_key')
87
+ end
88
+ end
89
+
90
+ def create_api_key_file(key)
91
+ File.open(@auth.api_key_path, 'w') { |file| file << key }
92
+ end
@@ -0,0 +1,16 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Winnie::Commands::Base do
4
+ describe "config_path" do
5
+ it "should return default config path" do
6
+ Winnie::Commands::Base.new.config_path.should == File.expand_path('~/.winnie')
7
+ end
8
+ end
9
+
10
+ describe "extract_options" do
11
+ it "should extract app code name if provided" do
12
+ base = Winnie::Commands::Base.new('--app', 'crazy-one')
13
+ base.code_name.should == 'crazy-one'
14
+ end
15
+ end
16
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rubygems'
4
+ require 'winnie/winnie'
5
+ require 'spec'
6
+ require 'spec/autorun'
7
+ require 'fakefs'
8
+ require 'fakefs/spec_helpers'
9
+
10
+ Spec::Runner.configure do |config|
11
+
12
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
data/winnie.gemspec ADDED
@@ -0,0 +1,84 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{winnie}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["winnie"]
12
+ s.date = %q{2010-08-27}
13
+ s.default_executable = %q{winnie}
14
+ s.description = %q{Command line tool which allows interacting with winnie's API}
15
+ s.email = %q{winnie-devs@ragnarson.com}
16
+ s.executables = ["winnie"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".gitignore",
24
+ "LICENSE",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "bin/winnie",
29
+ "lib/winnie/client.rb",
30
+ "lib/winnie/command.rb",
31
+ "lib/winnie/commands/app.rb",
32
+ "lib/winnie/commands/auth.rb",
33
+ "lib/winnie/commands/base.rb",
34
+ "lib/winnie/commands/help.rb",
35
+ "lib/winnie/helpers.rb",
36
+ "lib/winnie/winnie.rb",
37
+ "spec/client_spec.rb",
38
+ "spec/command_spec.rb",
39
+ "spec/commands/app_spec.rb",
40
+ "spec/commands/auth_spec.rb",
41
+ "spec/commands/base_spec.rb",
42
+ "spec/spec.opts",
43
+ "spec/spec_helper.rb",
44
+ "spec/winnie_spec.rb",
45
+ "winnie.gemspec"
46
+ ]
47
+ s.homepage = %q{http://winniecloud.net}
48
+ s.rdoc_options = ["--charset=UTF-8"]
49
+ s.require_paths = ["lib"]
50
+ s.rubygems_version = %q{1.3.7}
51
+ s.summary = %q{Winnie command line tool}
52
+ s.test_files = [
53
+ "spec/client_spec.rb",
54
+ "spec/command_spec.rb",
55
+ "spec/commands/app_spec.rb",
56
+ "spec/commands/auth_spec.rb",
57
+ "spec/commands/base_spec.rb",
58
+ "spec/spec_helper.rb",
59
+ "spec/winnie_spec.rb"
60
+ ]
61
+
62
+ if s.respond_to? :specification_version then
63
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
64
+ s.specification_version = 3
65
+
66
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
67
+ s.add_runtime_dependency(%q<json>, [">= 0"])
68
+ s.add_runtime_dependency(%q<rest-client>, [">= 0"])
69
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
70
+ s.add_development_dependency(%q<fakefs>, [">= 0"])
71
+ else
72
+ s.add_dependency(%q<json>, [">= 0"])
73
+ s.add_dependency(%q<rest-client>, [">= 0"])
74
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
75
+ s.add_dependency(%q<fakefs>, [">= 0"])
76
+ end
77
+ else
78
+ s.add_dependency(%q<json>, [">= 0"])
79
+ s.add_dependency(%q<rest-client>, [">= 0"])
80
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
81
+ s.add_dependency(%q<fakefs>, [">= 0"])
82
+ end
83
+ end
84
+
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: winnie
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - winnie
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-27 00:00:00 +02:00
19
+ default_executable: winnie
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: json
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rest-client
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: rspec
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 13
58
+ segments:
59
+ - 1
60
+ - 2
61
+ - 9
62
+ version: 1.2.9
63
+ type: :development
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: fakefs
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ type: :development
78
+ version_requirements: *id004
79
+ description: Command line tool which allows interacting with winnie's API
80
+ email: winnie-devs@ragnarson.com
81
+ executables:
82
+ - winnie
83
+ extensions: []
84
+
85
+ extra_rdoc_files:
86
+ - LICENSE
87
+ - README.rdoc
88
+ files:
89
+ - .document
90
+ - .gitignore
91
+ - LICENSE
92
+ - README.rdoc
93
+ - Rakefile
94
+ - VERSION
95
+ - bin/winnie
96
+ - lib/winnie/client.rb
97
+ - lib/winnie/command.rb
98
+ - lib/winnie/commands/app.rb
99
+ - lib/winnie/commands/auth.rb
100
+ - lib/winnie/commands/base.rb
101
+ - lib/winnie/commands/help.rb
102
+ - lib/winnie/helpers.rb
103
+ - lib/winnie/winnie.rb
104
+ - spec/client_spec.rb
105
+ - spec/command_spec.rb
106
+ - spec/commands/app_spec.rb
107
+ - spec/commands/auth_spec.rb
108
+ - spec/commands/base_spec.rb
109
+ - spec/spec.opts
110
+ - spec/spec_helper.rb
111
+ - spec/winnie_spec.rb
112
+ - winnie.gemspec
113
+ has_rdoc: true
114
+ homepage: http://winniecloud.net
115
+ licenses: []
116
+
117
+ post_install_message:
118
+ rdoc_options:
119
+ - --charset=UTF-8
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ hash: 3
128
+ segments:
129
+ - 0
130
+ version: "0"
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ hash: 3
137
+ segments:
138
+ - 0
139
+ version: "0"
140
+ requirements: []
141
+
142
+ rubyforge_project:
143
+ rubygems_version: 1.3.7
144
+ signing_key:
145
+ specification_version: 3
146
+ summary: Winnie command line tool
147
+ test_files:
148
+ - spec/client_spec.rb
149
+ - spec/command_spec.rb
150
+ - spec/commands/app_spec.rb
151
+ - spec/commands/auth_spec.rb
152
+ - spec/commands/base_spec.rb
153
+ - spec/spec_helper.rb
154
+ - spec/winnie_spec.rb