morale-client 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +10 -0
- data/Gemfile.lock +30 -0
- data/README.md +40 -0
- data/Rakefile +154 -0
- data/lib/morale/client.rb +82 -0
- data/lib/morale/connection_store.rb +58 -0
- data/lib/morale/platform.rb +11 -0
- data/lib/morale/storage.rb +29 -0
- data/lib/morale.rb +7 -0
- data/morale-client.gemspec +49 -0
- data/spec/morale/client_spec.rb +119 -0
- data/spec/morale/connection_store_spec.rb +65 -0
- data/spec/spec_helper.rb +25 -0
- metadata +101 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.2.6)
|
5
|
+
crack (0.1.8)
|
6
|
+
diff-lcs (1.1.3)
|
7
|
+
httparty (0.7.8)
|
8
|
+
crack (= 0.1.8)
|
9
|
+
json (1.4.6)
|
10
|
+
rspec (2.6.0)
|
11
|
+
rspec-core (~> 2.6.0)
|
12
|
+
rspec-expectations (~> 2.6.0)
|
13
|
+
rspec-mocks (~> 2.6.0)
|
14
|
+
rspec-core (2.6.4)
|
15
|
+
rspec-expectations (2.6.0)
|
16
|
+
diff-lcs (~> 1.1.2)
|
17
|
+
rspec-mocks (2.6.0)
|
18
|
+
webmock (1.7.8)
|
19
|
+
addressable (~> 2.2, > 2.2.5)
|
20
|
+
crack (>= 0.1.7)
|
21
|
+
|
22
|
+
PLATFORMS
|
23
|
+
ruby
|
24
|
+
|
25
|
+
DEPENDENCIES
|
26
|
+
diff-lcs (= 1.1.3)
|
27
|
+
httparty (= 0.7.8)
|
28
|
+
json (= 1.4.6)
|
29
|
+
rspec (= 2.6.0)
|
30
|
+
webmock
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
Morale Client
|
2
|
+
=============
|
3
|
+
|
4
|
+
Description
|
5
|
+
-----------
|
6
|
+
|
7
|
+
This gem is a Ruby wrapper that allows you to communicate to <http://teammorale.com> via the Morale API.
|
8
|
+
|
9
|
+
For more information about Morale see <http://teammorale.com>.
|
10
|
+
|
11
|
+
Installation
|
12
|
+
------------
|
13
|
+
|
14
|
+
This library can be installed as a gem. It is hosted on [Rubygems](http://rubygems.org/gems/morale-client).
|
15
|
+
|
16
|
+
You can install this library as a gem using the following command:
|
17
|
+
|
18
|
+
gem install morale-client
|
19
|
+
|
20
|
+
Usage
|
21
|
+
-----
|
22
|
+
|
23
|
+
Simply require this library before you use it:
|
24
|
+
|
25
|
+
require 'morale-client'
|
26
|
+
|
27
|
+
Contributing
|
28
|
+
------------
|
29
|
+
|
30
|
+
1. Fork it.
|
31
|
+
2. Create a new branch.
|
32
|
+
3. Create tests for your changes.
|
33
|
+
4. Make your changes.
|
34
|
+
5. Run the tests.
|
35
|
+
6. Commit your changes.
|
36
|
+
7. Push your branch.
|
37
|
+
8. Create a pull request from your change.
|
38
|
+
|
39
|
+
Released under the [MIT license](http://www.opensource.org/licenses/mit-license.php).
|
40
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
#############################################################################
|
6
|
+
#
|
7
|
+
# Helper functions
|
8
|
+
#
|
9
|
+
#############################################################################
|
10
|
+
|
11
|
+
def name
|
12
|
+
@name ||= Dir['*.gemspec'].first.split('.').first
|
13
|
+
end
|
14
|
+
|
15
|
+
def dir_name
|
16
|
+
"morale"
|
17
|
+
end
|
18
|
+
|
19
|
+
def version
|
20
|
+
line = File.read("lib/#{dir_name}.rb")[/^\s*VERSION\s*=\s*.*/]
|
21
|
+
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
22
|
+
end
|
23
|
+
|
24
|
+
def date
|
25
|
+
Date.today.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
def rubyforge_project
|
29
|
+
name
|
30
|
+
end
|
31
|
+
|
32
|
+
def gemspec_file
|
33
|
+
"#{name}.gemspec"
|
34
|
+
end
|
35
|
+
|
36
|
+
def gem_file
|
37
|
+
"#{name}-#{version}.gem"
|
38
|
+
end
|
39
|
+
|
40
|
+
def replace_header(head, header_name)
|
41
|
+
head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
|
42
|
+
end
|
43
|
+
|
44
|
+
#############################################################################
|
45
|
+
#
|
46
|
+
# Standard tasks
|
47
|
+
#
|
48
|
+
#############################################################################
|
49
|
+
|
50
|
+
task :default => :test
|
51
|
+
|
52
|
+
require 'rake/testtask'
|
53
|
+
Rake::TestTask.new(:test) do |test|
|
54
|
+
test.libs << 'lib' << 'test'
|
55
|
+
test.pattern = 'test/**/test_*.rb'
|
56
|
+
test.verbose = true
|
57
|
+
end
|
58
|
+
|
59
|
+
desc "Generate RCov test coverage and open in your browser"
|
60
|
+
task :coverage do
|
61
|
+
require 'rcov'
|
62
|
+
sh "rm -fr coverage"
|
63
|
+
sh "rcov test/test_*.rb"
|
64
|
+
sh "open coverage/index.html"
|
65
|
+
end
|
66
|
+
|
67
|
+
require 'rdoc/task'
|
68
|
+
Rake::RDocTask.new do |rdoc|
|
69
|
+
rdoc.rdoc_dir = 'rdoc'
|
70
|
+
rdoc.title = "#{name} #{version}"
|
71
|
+
rdoc.rdoc_files.include('README*')
|
72
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
73
|
+
end
|
74
|
+
|
75
|
+
desc "Open an irb session preloaded with this library"
|
76
|
+
task :console do
|
77
|
+
sh "irb -rubygems -r ./lib/#{dir_name}.rb"
|
78
|
+
end
|
79
|
+
|
80
|
+
#############################################################################
|
81
|
+
#
|
82
|
+
# Custom tasks (add your own tasks here)
|
83
|
+
#
|
84
|
+
#############################################################################
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
#############################################################################
|
89
|
+
#
|
90
|
+
# Packaging tasks
|
91
|
+
#
|
92
|
+
#############################################################################
|
93
|
+
|
94
|
+
desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
|
95
|
+
task :release => :build do
|
96
|
+
unless `git branch` =~ /^\* master$/
|
97
|
+
puts "You must be on the master branch to release!"
|
98
|
+
exit!
|
99
|
+
end
|
100
|
+
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
101
|
+
sh "git tag v#{version}"
|
102
|
+
sh "git push origin master"
|
103
|
+
sh "git push origin v#{version}"
|
104
|
+
sh "gem push pkg/#{name}-#{version}.gem"
|
105
|
+
end
|
106
|
+
|
107
|
+
desc "Build #{gem_file} into the pkg directory"
|
108
|
+
task :build => :gemspec do
|
109
|
+
sh "mkdir -p pkg"
|
110
|
+
sh "gem build #{gemspec_file}"
|
111
|
+
sh "mv #{gem_file} pkg"
|
112
|
+
end
|
113
|
+
|
114
|
+
desc "Generate #{gemspec_file}"
|
115
|
+
task :gemspec => :validate do
|
116
|
+
# read spec file and split out manifest section
|
117
|
+
spec = File.read(gemspec_file)
|
118
|
+
head, manifest, tail = spec.split(" # = MANIFEST =\n")
|
119
|
+
|
120
|
+
# replace name version and date
|
121
|
+
replace_header(head, :name)
|
122
|
+
replace_header(head, :version)
|
123
|
+
replace_header(head, :date)
|
124
|
+
#comment this out if your rubyforge_project has a different name
|
125
|
+
replace_header(head, :rubyforge_project)
|
126
|
+
|
127
|
+
# determine file list from git ls-files
|
128
|
+
files = `git ls-files`.
|
129
|
+
split("\n").
|
130
|
+
sort.
|
131
|
+
reject { |file| file =~ /^\./ }.
|
132
|
+
reject { |file| file =~ /^(rdoc|pkg)/ }.
|
133
|
+
map { |file| " #{file}" }.
|
134
|
+
join("\n")
|
135
|
+
|
136
|
+
# piece file back together and write
|
137
|
+
manifest = " s.files = %w[\n#{files}\n ]\n"
|
138
|
+
spec = [head, manifest, tail].join(" # = MANIFEST =\n")
|
139
|
+
File.open(gemspec_file, 'w') { |io| io.write(spec) }
|
140
|
+
puts "Updated #{gemspec_file}"
|
141
|
+
end
|
142
|
+
|
143
|
+
desc "Validate #{gemspec_file}"
|
144
|
+
task :validate do
|
145
|
+
libfiles = Dir['lib/*'] - ["lib/#{dir_name}.rb", "lib/#{dir_name}"]
|
146
|
+
unless libfiles.empty?
|
147
|
+
puts "Directory `lib` should only contain a `#{dir_name}.rb` file and `#{dir_name}` dir."
|
148
|
+
exit!
|
149
|
+
end
|
150
|
+
unless Dir['VERSION*'].empty?
|
151
|
+
puts "A `VERSION` file at root level violates Gem best practices."
|
152
|
+
exit!
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'json'
|
3
|
+
require 'morale/connection_store'
|
4
|
+
|
5
|
+
module Morale
|
6
|
+
class Client
|
7
|
+
class Unauthorized < RuntimeError; end
|
8
|
+
class NotFound < RuntimeError; end
|
9
|
+
|
10
|
+
include HTTParty
|
11
|
+
extend Morale::ConnectionStore
|
12
|
+
|
13
|
+
format :json
|
14
|
+
|
15
|
+
API_VERSION = 'v1'
|
16
|
+
|
17
|
+
attr_accessor :api_key
|
18
|
+
attr_reader :subdomain
|
19
|
+
|
20
|
+
def self.authorize(user, password, subdomain)
|
21
|
+
client = new(subdomain)
|
22
|
+
client.unauthorize
|
23
|
+
client.api_key = client.class.post('/in', :body => { :email => user, :password => password })["api_key"]
|
24
|
+
return client
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.accounts(user)
|
28
|
+
client = new
|
29
|
+
client.unauthorize
|
30
|
+
response = client.class.get("/accounts", :query => { :email => user })
|
31
|
+
raise Unauthorized if response.code == 401
|
32
|
+
raise NotFound if response.code == 404
|
33
|
+
response
|
34
|
+
end
|
35
|
+
|
36
|
+
def accounts
|
37
|
+
authorize
|
38
|
+
response = self.class.get("/accounts", :query => { :api_key => @api_key })
|
39
|
+
raise Unauthorized if response.code == 401
|
40
|
+
raise NotFound if response.code == 404
|
41
|
+
response
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(subdomain="", api_key="")
|
45
|
+
@api_key = api_key
|
46
|
+
@subdomain = subdomain
|
47
|
+
self.class.default_options[:base_uri] = HTTParty.normalize_base_uri("#{subdomain}#{"." unless subdomain.nil? || subdomain.empty?}#{self.class.base_url}/api/#{API_VERSION}")
|
48
|
+
end
|
49
|
+
|
50
|
+
def projects
|
51
|
+
authorize
|
52
|
+
response = self.class.get('/projects')
|
53
|
+
raise Unauthorized if response.code == 401
|
54
|
+
raise NotFound if response.code == 404
|
55
|
+
response
|
56
|
+
end
|
57
|
+
|
58
|
+
def tickets(options={})
|
59
|
+
authorize
|
60
|
+
response = self.class.get("/projects/#{options[:project_id]}/tickets")
|
61
|
+
raise Unauthorized if response.code == 401
|
62
|
+
raise NotFound if response.code == 404
|
63
|
+
response
|
64
|
+
end
|
65
|
+
|
66
|
+
def ticket(project_id, command)
|
67
|
+
authorize
|
68
|
+
response = self.class.post("/projects/#{project_id}/tickets", :body => { :command => command })
|
69
|
+
raise Unauthorized if response.code == 401
|
70
|
+
raise NotFound if response.code == 404
|
71
|
+
response
|
72
|
+
end
|
73
|
+
|
74
|
+
def authorize
|
75
|
+
self.class.basic_auth @subdomain, @api_key
|
76
|
+
end
|
77
|
+
|
78
|
+
def unauthorize
|
79
|
+
self.class.basic_auth nil, nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'morale/storage'
|
2
|
+
require 'morale/platform'
|
3
|
+
|
4
|
+
module Morale
|
5
|
+
module ConnectionStore
|
6
|
+
include Morale::Storage
|
7
|
+
include Morale::Platform
|
8
|
+
|
9
|
+
def base_url
|
10
|
+
if @base_url.nil?
|
11
|
+
@base_url = read_connection
|
12
|
+
if @base_url.nil?
|
13
|
+
@base_url = default_base_url
|
14
|
+
self.write_connection
|
15
|
+
end
|
16
|
+
end
|
17
|
+
@base_url
|
18
|
+
end
|
19
|
+
|
20
|
+
def base_url=(value)
|
21
|
+
@base_url = value
|
22
|
+
self.write_connection
|
23
|
+
end
|
24
|
+
|
25
|
+
def location
|
26
|
+
ENV['CONNECTION_LOCATION'] || default_location
|
27
|
+
end
|
28
|
+
|
29
|
+
def location=(value)
|
30
|
+
ENV['CONNECTION_LOCATION'] = value
|
31
|
+
end
|
32
|
+
|
33
|
+
def default_location
|
34
|
+
"#{home_directory}/.morale/connection"
|
35
|
+
end
|
36
|
+
|
37
|
+
def delete_connection
|
38
|
+
self.delete
|
39
|
+
@base_url = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def read_connection
|
43
|
+
connection = self.read
|
44
|
+
connection.split("\n") if connection
|
45
|
+
end
|
46
|
+
|
47
|
+
def write_connection
|
48
|
+
self.write self.base_url
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def default_base_url
|
54
|
+
ENV['DEFAULT_BASE_URL'] || "teammorale.com"
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Morale
|
2
|
+
module Storage
|
3
|
+
|
4
|
+
attr_accessor :location
|
5
|
+
|
6
|
+
def delete
|
7
|
+
FileUtils.rm_f(location)
|
8
|
+
end
|
9
|
+
|
10
|
+
def read
|
11
|
+
File.exists?(location) and File.read(location)
|
12
|
+
end
|
13
|
+
|
14
|
+
def write(data)
|
15
|
+
FileUtils.mkdir_p(File.dirname(location))
|
16
|
+
f = File.open(location, 'w')
|
17
|
+
f.puts data
|
18
|
+
f.close
|
19
|
+
set_permissions
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def set_permissions
|
25
|
+
FileUtils.chmod 0700, File.dirname(location)
|
26
|
+
FileUtils.chmod 0600, location
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/morale.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
4
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
5
|
+
s.rubygems_version = '1.3.5'
|
6
|
+
|
7
|
+
s.name = 'morale-client'
|
8
|
+
s.version = '0.0.1'
|
9
|
+
s.date = '2011-12-12'
|
10
|
+
s.rubyforge_project = 'morale-client'
|
11
|
+
|
12
|
+
s.summary = "A Ruby wrapper for the Morale REST API."
|
13
|
+
s.description = "A Ruby wrapper for the Morale REST API. Call the Morale API from any Ruby application to manage tickets and projects."
|
14
|
+
|
15
|
+
s.authors = ["Brilliant Fantastic"]
|
16
|
+
s.email = 'support@teammorale.com'
|
17
|
+
s.homepage = 'http://teammorale.com'
|
18
|
+
|
19
|
+
s.require_paths = %w[lib]
|
20
|
+
|
21
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
22
|
+
s.extra_rdoc_files = %w[README.md]
|
23
|
+
|
24
|
+
s.add_dependency('httparty', "~> 0.7.8")
|
25
|
+
s.add_dependency('json', "~> 1.4.6")
|
26
|
+
|
27
|
+
#s.add_development_dependency('DEVDEPNAME', [">= 1.1.0", "< 2.0.0"])
|
28
|
+
|
29
|
+
## Leave this section as-is. It will be automatically generated from the
|
30
|
+
## contents of your Git repository via the gemspec task. DO NOT REMOVE
|
31
|
+
## THE MANIFEST COMMENTS, they are used as delimiters by the task.
|
32
|
+
# = MANIFEST =
|
33
|
+
s.files = %w[
|
34
|
+
Gemfile
|
35
|
+
Gemfile.lock
|
36
|
+
README.md
|
37
|
+
Rakefile
|
38
|
+
lib/morale.rb
|
39
|
+
lib/morale/client.rb
|
40
|
+
lib/morale/connection_store.rb
|
41
|
+
lib/morale/platform.rb
|
42
|
+
lib/morale/storage.rb
|
43
|
+
morale-client.gemspec
|
44
|
+
spec/morale/client_spec.rb
|
45
|
+
spec/morale/connection_store_spec.rb
|
46
|
+
spec/spec_helper.rb
|
47
|
+
]
|
48
|
+
# = MANIFEST =
|
49
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "json"
|
3
|
+
require "morale/client"
|
4
|
+
|
5
|
+
describe Morale::Client do
|
6
|
+
describe "#authorize" do
|
7
|
+
it "authorizes a user with a valid email address and password" do
|
8
|
+
api_key = "blah"
|
9
|
+
stub_request(:post, "http://blah.lvh.me:3000/api/v1/in").to_return(:body => { "api_key" => "#{api_key}" }.to_json)
|
10
|
+
Morale::Client.authorize(nil, nil, 'blah').api_key.should == api_key
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#accounts" do
|
15
|
+
it "displays all the accounts for a specific user based on their email" do
|
16
|
+
stub_request(:get, "http://lvh.me:3000/api/v1/accounts?email=someone@example.com").to_return(:body =>
|
17
|
+
[{"account" => {"group_name" => "Shimmy Sham","site_address"=>"shimmy_sham","created_at" => "2011-07-31T21:28:53Z","updated_at" => "2011-07-31T21:28:53Z","plan_id" => 1,"id" => 2}},
|
18
|
+
{"account" => {"group_name" => "Pumpkin Tarts","site_address"=>"pumpkin_tarts","created_at" => "2011-07-31T21:40:24Z","updated_at" => "2011-07-31T21:40:24Z","plan_id" => 1,"id" => 1}}].to_json)
|
19
|
+
|
20
|
+
accounts = Morale::Client.accounts('someone@example.com')
|
21
|
+
accounts.count.should == 2
|
22
|
+
end
|
23
|
+
|
24
|
+
it "displays all the accounts for a specific user based on their api_key" do
|
25
|
+
stub_request(:get, "http://blah:@blah.lvh.me:3000/api/v1/accounts?api_key=").to_return(:body =>
|
26
|
+
[{"account" => {"group_name" => "Shimmy Sham","site_address"=>"shimmy_sham","created_at" => "2011-07-31T21:28:53Z","updated_at" => "2011-07-31T21:28:53Z","plan_id" => 1,"id" => 2}},
|
27
|
+
{"account" => {"group_name" => "Pumpkin Tarts","site_address"=>"pumpkin_tarts","created_at" => "2011-07-31T21:40:24Z","updated_at" => "2011-07-31T21:40:24Z","plan_id" => 1,"id" => 1}}].to_json)
|
28
|
+
|
29
|
+
client = Morale::Client.new('blah')
|
30
|
+
client.accounts.count.should == 2
|
31
|
+
client.accounts[0]["account"]["group_name"].should == "Shimmy Sham"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#projects" do
|
36
|
+
it "displays all the projects for a specific account" do
|
37
|
+
stub_request(:get, "http://blah:@blah.lvh.me:3000/api/v1/projects").to_return(:body =>
|
38
|
+
[{"project" => {"name" => "Skunk Works","created_at" => "2011-07-31T21:40:24Z","updated_at" => "2011-07-31T21:40:24Z","account_id" => 1,"id" => 1}},
|
39
|
+
{"project" => {"name" => "Poop Shoot","created_at" => "2011-07-31T21:28:53Z","updated_at" => "2011-07-31T21:28:53Z","account_id" => 1,"id" => 2}}].to_json)
|
40
|
+
client = Morale::Client.new('blah')
|
41
|
+
client.projects.count.should == 2
|
42
|
+
client.projects[0]["project"]["name"].should == "Skunk Works"
|
43
|
+
client.projects[1]["project"]["id"].should == 2
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should raise unauthorized if a 401 is received" do
|
47
|
+
stub_request(:get, "http://blah:@blah.lvh.me:3000/api/v1/projects").to_return(:status => 401)
|
48
|
+
client = Morale::Client.new('blah')
|
49
|
+
lambda { client.projects.count }.should raise_error(Morale::Client::Unauthorized)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#ticket" do
|
54
|
+
it "should return a JSON ticket that was created" do
|
55
|
+
stub_request(:post, "http://blah:123456@blah.lvh.me:3000/api/v1/projects/1/tickets").
|
56
|
+
with(:body => "command=This%20is%20a%20test%20that%20should%20create%20a%20new%20task%20as%3A%20Lester").
|
57
|
+
to_return(:body => {
|
58
|
+
"created_at" => "2011-09-27T02:56:03Z",
|
59
|
+
"assigned_to" => { "user" => { "first_name" => "Lester", "last_name" => "Tester", "email" => "test@test.com" } },
|
60
|
+
"title" => "This is a test that should create a new task",
|
61
|
+
"project_id" => "1",
|
62
|
+
"priority" => "null",
|
63
|
+
"archived" => "false",
|
64
|
+
"id" => "1",
|
65
|
+
"created_by" => { "user" => { "first_name" => "Lester", "last_name" => "Tester", "email" => "test@test.com" } },
|
66
|
+
"due_date" => "null",
|
67
|
+
"identifier" => "1" }.to_json
|
68
|
+
)
|
69
|
+
client = Morale::Client.new('blah', '123456')
|
70
|
+
response = client.ticket(1, "This is a test that should create a new task as: Lester")
|
71
|
+
response['title'].should == "This is a test that should create a new task"
|
72
|
+
response['assigned_to']['user']['first_name'].should == "Lester"
|
73
|
+
response['project_id'].should == "1"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should raise unauthorized if a 401 is received" do
|
77
|
+
stub_request(:post, "http://blah:123456@blah.lvh.me:3000/api/v1/projects/1/tickets").
|
78
|
+
with(:body => "command=This%20is%20a%20test%20that%20should%20create%20a%20new%20task%20as%3A%20Lester").
|
79
|
+
to_return(:status => 401)
|
80
|
+
client = Morale::Client.new('blah', '123456')
|
81
|
+
lambda { client.ticket('1', "This is a test that should create a new task as: Lester") }.should raise_error(Morale::Client::Unauthorized)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should raise notfound if a 404 is received" do
|
85
|
+
stub_request(:post, "http://blah:123456@blah.lvh.me:3000/api/v1/projects/1/tickets").
|
86
|
+
with(:body => "command=This%20is%20a%20test%20that%20should%20create%20a%20new%20task%20as%3A%20Lester").
|
87
|
+
to_return(:status => 404)
|
88
|
+
client = Morale::Client.new('blah', '123456')
|
89
|
+
lambda { client.ticket('1', "This is a test that should create a new task as: Lester") }.should raise_error(Morale::Client::NotFound)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#tickets" do
|
94
|
+
it "should return all active tickets when no options are specified" do
|
95
|
+
stub_request(:get, "http://blah:123456@blah.lvh.me:3000/api/v1/projects/1/tickets").to_return(:body =>
|
96
|
+
[{"ticket" => {"title" => "This is test #1","created_at" => "2011-07-31T21:40:24Z","updated_at" => "2011-07-31T21:40:24Z","project_id" => 1,"id" => 1,"identifier" => "1","type" => "Task","due_date" => "2011-10-15 16:00:00.000000","priority" => nil,"archived" => "f"}},
|
97
|
+
{"ticket" => {"title" => "This is test #2","created_at" => "2011-07-31T21:28:53Z","updated_at" => "2011-07-31T21:28:53Z","project_id" => 1,"id" => 2, "identifier" => "2","type" => "Bug","due_date" => nil,"priority" => "2","archived" => "f"}}].to_json)
|
98
|
+
client = Morale::Client.new('blah', '123456')
|
99
|
+
response = client.tickets({:project_id => 1})
|
100
|
+
response.count.should == 2
|
101
|
+
response[0]["ticket"]["title"].should == "This is test #1"
|
102
|
+
response[1]["ticket"]["title"].should == "This is test #2"
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should raise unauthorized if a 401 is received" do
|
106
|
+
stub_request(:get, "http://blah:123456@blah.lvh.me:3000/api/v1/projects/1/tickets").
|
107
|
+
to_return(:status => 401)
|
108
|
+
client = Morale::Client.new('blah', '123456')
|
109
|
+
lambda { client.tickets({:project_id => 1}) }.should raise_error(Morale::Client::Unauthorized)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should raise notfound if a 404 is received" do
|
113
|
+
stub_request(:get, "http://blah:123456@blah.lvh.me:3000/api/v1/projects/1/tickets").
|
114
|
+
to_return(:status => 404)
|
115
|
+
client = Morale::Client.new('blah', '123456')
|
116
|
+
lambda { client.tickets({ :project_id => 1 }) }.should raise_error(Morale::Client::NotFound)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'morale/connection_store'
|
3
|
+
|
4
|
+
describe Morale::ConnectionStore do
|
5
|
+
|
6
|
+
class Dummy; end
|
7
|
+
before (:each) do
|
8
|
+
@dummy = Dummy.new
|
9
|
+
@dummy.extend(Morale::ConnectionStore)
|
10
|
+
end
|
11
|
+
|
12
|
+
after (:each) do
|
13
|
+
@dummy.delete_connection
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#location" do
|
17
|
+
it "should return the correct location of the connection file" do
|
18
|
+
@dummy.location.should == "#{ENV['HOME']}/.morale/connection"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#base_url" do
|
23
|
+
it "should store the default base url if it is not set" do
|
24
|
+
@dummy.base_url.should == "teammorale.com"
|
25
|
+
File.read(@dummy.location).should =~ /teammorale.com/
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should return the environment variable for the default base url" do
|
29
|
+
@dummy.delete_connection
|
30
|
+
ENV['DEFAULT_BASE_URL'] = "somewhere-else.com"
|
31
|
+
@dummy.base_url.should == "somewhere-else.com"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should store the base url when it is set" do
|
35
|
+
@dummy.base_url = "somewhere-else.com"
|
36
|
+
File.read(@dummy.location).should =~ /somewhere-else.com/
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#delete_connection" do
|
41
|
+
it "should clear the base_url field" do
|
42
|
+
ENV['DEFAULT_BASE_URL'] = nil
|
43
|
+
@dummy.base_url = "Blah!"
|
44
|
+
@dummy.delete_connection
|
45
|
+
@dummy.base_url.should == "teammorale.com"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should delete the connection file" do
|
49
|
+
FileUtils.mkdir_p(File.dirname(@dummy.location))
|
50
|
+
f = File.open(@dummy.location, 'w')
|
51
|
+
f.puts "Blah!"
|
52
|
+
|
53
|
+
@dummy.delete_connection
|
54
|
+
File.exists?(@dummy.location).should be_false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#write_connection" do
|
59
|
+
it "should write data to the location of the connection file" do
|
60
|
+
@dummy.base_url = "Blah!"
|
61
|
+
@dummy.write_connection
|
62
|
+
File.read(@dummy.location).should =~ /Blah!/
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler/setup"
|
3
|
+
|
4
|
+
require "rspec"
|
5
|
+
require "webmock/rspec"
|
6
|
+
|
7
|
+
require "stringio"
|
8
|
+
|
9
|
+
require "morale/client"
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
Morale::Client.base_url = "lvh.me:3000"
|
13
|
+
|
14
|
+
def process(stdin_str = '')
|
15
|
+
begin
|
16
|
+
require 'stringio'
|
17
|
+
$o_stdin, $o_stdout, $o_stderr = $stdin, $stdout, $stderr
|
18
|
+
$stdin, $stdout, $stderr = StringIO.new(stdin_str), StringIO.new, StringIO.new
|
19
|
+
yield
|
20
|
+
{:stdout => $stdout.string, :stderr => $stderr.string}
|
21
|
+
ensure
|
22
|
+
$stdin, $stdout, $stderr = $o_stdin, $o_stdout, $o_stderr
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: morale-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Brilliant Fantastic
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-12-12 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: httparty
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
- 7
|
30
|
+
- 8
|
31
|
+
version: 0.7.8
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: json
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 1
|
43
|
+
- 4
|
44
|
+
- 6
|
45
|
+
version: 1.4.6
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
description: A Ruby wrapper for the Morale REST API. Call the Morale API from any Ruby application to manage tickets and projects.
|
49
|
+
email: support@teammorale.com
|
50
|
+
executables: []
|
51
|
+
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
extra_rdoc_files:
|
55
|
+
- README.md
|
56
|
+
files:
|
57
|
+
- Gemfile
|
58
|
+
- Gemfile.lock
|
59
|
+
- README.md
|
60
|
+
- Rakefile
|
61
|
+
- lib/morale.rb
|
62
|
+
- lib/morale/client.rb
|
63
|
+
- lib/morale/connection_store.rb
|
64
|
+
- lib/morale/platform.rb
|
65
|
+
- lib/morale/storage.rb
|
66
|
+
- morale-client.gemspec
|
67
|
+
- spec/morale/client_spec.rb
|
68
|
+
- spec/morale/connection_store_spec.rb
|
69
|
+
- spec/spec_helper.rb
|
70
|
+
has_rdoc: true
|
71
|
+
homepage: http://teammorale.com
|
72
|
+
licenses: []
|
73
|
+
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options:
|
76
|
+
- --charset=UTF-8
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
segments:
|
84
|
+
- 0
|
85
|
+
version: "0"
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
requirements: []
|
94
|
+
|
95
|
+
rubyforge_project: morale-client
|
96
|
+
rubygems_version: 1.3.6
|
97
|
+
signing_key:
|
98
|
+
specification_version: 2
|
99
|
+
summary: A Ruby wrapper for the Morale REST API.
|
100
|
+
test_files: []
|
101
|
+
|