morale-client 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/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
|
+
|