winnie 0.0.1

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/.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