nine-redmine-client 1.0.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fba5a853caa230da439567826e09696d878f377a
4
+ data.tar.gz: 8e48a5be8c0ecf6d5f13964be9f8530658f5fe9c
5
+ SHA512:
6
+ metadata.gz: 0d528a0952735dac141625005248b6ac9253b5e449080fdeb95fa74dafff62a79d7b90af6a94ad0d1996e1d9c634e8860e9cb1ab22ae88abc27ebfb8a6f7f32d
7
+ data.tar.gz: 47f7b69ea73e8c4a3cc41dd157c5eb67ec65e4335c090c202dc8565852c89b413b872eb9e15c2fa0901c130af848632193caccfc3b3ed39bacbba869024e15c2
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+
2
+ Gemfile.lock
3
+ /.bundle
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ redmine-client-ruby
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.1
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.5
5
+ - 2.2.0
6
+
7
+ gemfile:
8
+ - gemfiles/activesupport-4.0.gemfile
9
+ - gemfiles/activesupport-4.1.gemfile
10
+ - gemfiles/activesupport-4.2.gemfile
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+
2
+ # 1.0.0
3
+
4
+
5
+
6
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # Redmine Ruby Client
2
+
3
+ [![Build Status](https://travis-ci.org/ninech/redmine-client.svg?branch=master)](https://travis-ci.org/ninech/redmine-client)
4
+
5
+ Ruby client library for the Redmine API.
6
+
7
+ ## Configuration
8
+
9
+ In your Rails app create a file `config/initializers/redmine.rb` with the following content:
10
+
11
+ ```ruby
12
+ RedmineClient::API.configure do |config|
13
+ config.url = ENV['REDMINE_URL']
14
+ config.token = ENV['REDMINE_TOKEN']
15
+ end
16
+ ```
17
+
18
+ Here you have to set the config values via environment variables. But you're free to do it differently.
19
+
20
+ ## Usage
21
+
22
+ The client is very limited. Actually it can only find, create and update issues. That's all for now. But
23
+ great things start small.
24
+
25
+ ```ruby
26
+ RedmineClient::Issue.create subject: 'Do this and that', project_id: 1
27
+
28
+ issue = RedmineClient::Issue.find(1)
29
+ issue.update subject: 'New Subject'
30
+ ```
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec) do |task|
6
+ task.rspec_opts = '--format doc --profile'
7
+ end
8
+
9
+ task default: :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pathname'
4
+ require 'pry'
5
+
6
+ APP_ROOT = File.join(File.dirname(Pathname.new(__FILE__).realpath),'..')
7
+
8
+ $:.unshift File.join(APP_ROOT, 'lib')
9
+ $:.unshift File.join(APP_ROOT, 'vendor/bundle')
10
+
11
+ Dir.chdir(APP_ROOT)
12
+
13
+ require 'bundler/setup'
14
+ require 'nine-redmine-client'
15
+
16
+ fail 'REDMINE_API_KEY environment variable not set!' unless ENV['REDMINE_API_KEY']
17
+
18
+ RedmineClient::API.configure do |config|
19
+ config.url = 'http://redmine.dev/'
20
+ config.token = ENV['REDMINE_API_KEY']
21
+ end
22
+
23
+ binding.pry
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'activesupport', '~> 4.0.0'
4
+
5
+ gemspec path: '../'
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'activesupport', '~> 4.1.0'
4
+
5
+ gemspec path: '../'
6
+
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'activesupport', '~> 4.2.0'
4
+
5
+ gemspec path: '../'
6
+
@@ -0,0 +1 @@
1
+ require 'redmine_client'
@@ -0,0 +1,9 @@
1
+ require 'httparty'
2
+
3
+ module RedmineClient
4
+ end
5
+
6
+ require 'redmine_client/errors'
7
+ require 'redmine_client/api'
8
+ require 'redmine_client/base'
9
+ require 'redmine_client/issue'
@@ -0,0 +1,21 @@
1
+ require 'active_support/configurable'
2
+
3
+ module RedmineClient
4
+ class API
5
+ def self.config
6
+ @config ||= Configuration.new
7
+ end
8
+
9
+ def self.configure
10
+ yield config
11
+ Base.setup
12
+ end
13
+ end
14
+
15
+ class API::Configuration
16
+ include ActiveSupport::Configurable
17
+
18
+ config_accessor(:url)
19
+ config_accessor(:token)
20
+ end
21
+ end
@@ -0,0 +1,81 @@
1
+ require 'ostruct'
2
+ require 'forwardable'
3
+
4
+ module RedmineClient
5
+ HEADERS = {
6
+ 'User-Agent' => 'Ruby.Redmine.Client',
7
+ 'Accept' => 'application/json',
8
+ 'Content-Type' => 'application/x-www-form-urlencoded',
9
+ }.freeze
10
+
11
+ class Base < OpenStruct
12
+ include HTTParty
13
+
14
+ format :json
15
+
16
+ extend Forwardable
17
+ def_delegators 'self.class', :delete, :get, :post, :put, :resource_path, :resource_name, :bad_response
18
+
19
+ def update(attrs = {})
20
+ resource = put "#{resource_path}/#{id}.json", body: { resource_name => attrs }
21
+ if resource.success?
22
+ data = Hash[attrs.map { |key, value| [key.to_sym, value] }]
23
+ @table.merge!(data)
24
+ else
25
+ false
26
+ end
27
+ end
28
+
29
+ class << self
30
+ def setup
31
+ base_uri RedmineClient::API.config.url
32
+ headers HEADERS.merge('X-Redmine-API-Key' => RedmineClient::API.config.token)
33
+ end
34
+
35
+ def resource_path
36
+ klass = name.split('::').last
37
+ klass[0] = klass[0].chr.downcase
38
+ klass.end_with?('y') ? "/#{klass.chop}ies" : "/#{klass}s"
39
+ end
40
+
41
+ def resource_name
42
+ klass = name.split('::').last
43
+ klass.downcase
44
+ end
45
+
46
+ def bad_response(response, _params = {})
47
+ if response.class == HTTParty::Response
48
+ case response.code
49
+ when 403
50
+ fail Errors::AccessDeniedException
51
+ when 404
52
+ fail Errors::ResourceNotFoundException
53
+ when 422
54
+ fail Errors::UnprocessableEntityException, response
55
+ when 500
56
+ fail Errors::InternalErrorException
57
+ else
58
+ fail HTTParty::ResponseError, response
59
+ end
60
+ end
61
+
62
+ fail StandardError, 'Unknown error'
63
+ end
64
+
65
+ def find(id)
66
+ resource = get "#{resource_path}/#{id}.json"
67
+ resource.ok? ? new(resource[resource_name]) : bad_response(resource, id)
68
+ end
69
+
70
+ def create(attrs = {})
71
+ resource = post "#{resource_path}.json", body: { resource_name => attrs }
72
+ if resource.success?
73
+ data = attrs.merge resource[resource_name]
74
+ new(data)
75
+ else
76
+ bad_response(resource, attrs)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,31 @@
1
+ module RedmineClient
2
+ module Errors
3
+ class AccessDeniedException < StandardError
4
+ def to_s
5
+ 'Access denied.'
6
+ end
7
+ end
8
+
9
+ class ResourceNotFoundException < StandardError
10
+ def to_s
11
+ 'Resource not found.'
12
+ end
13
+ end
14
+
15
+ class UnprocessableEntityException < StandardError
16
+ def initialize(response)
17
+ @errors = response.parsed_response['errors']
18
+ end
19
+
20
+ def to_s
21
+ @errors.join(', ')
22
+ end
23
+ end
24
+
25
+ class InternalErrorException < StandardError
26
+ def to_s
27
+ 'Internal error'
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,12 @@
1
+ module RedmineClient
2
+ class Issue < Base
3
+ def self.search(arguments)
4
+ issues = get "#{resource_path}.json", query: arguments
5
+ if issues.ok?
6
+ issues['issues'].map { |issue| new(issue) }
7
+ else
8
+ bad_response(issues, arguments)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ $:.push File.expand_path('../lib', __FILE__)
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'nine-redmine-client'
7
+ s.version = File.read(File.expand_path('../VERSION', __FILE__)).strip
8
+ s.authors = ['nine.ch Development-Team']
9
+ s.email = ['development@nine.ch']
10
+ s.homepage = 'http://github.com/ninech/'
11
+ s.license = 'MIT'
12
+ s.summary = 'Redmine API ruby client library'
13
+ s.description = 'To access the Redmine API from ruby scripts.'
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ['lib']
19
+
20
+ s.add_development_dependency 'rake', '~> 10.0'
21
+ s.add_development_dependency 'rspec', '~> 3.0'
22
+ s.add_development_dependency 'pry', '~> 0.10.0'
23
+
24
+ s.add_runtime_dependency 'httparty'
25
+ s.add_runtime_dependency 'activesupport', '>= 4.0.0'
26
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RedmineClient::Base do
4
+ describe '.resource_path' do
5
+ subject { RedmineClient::Base.resource_path }
6
+ it { should eq '/bases' }
7
+ end
8
+
9
+ describe '.resource_name' do
10
+ subject { RedmineClient::Base.resource_name }
11
+ it { should eq 'base' }
12
+ end
13
+
14
+ describe '.bad_response' do
15
+ subject { described_class.bad_response(response) }
16
+
17
+ context 'valid response object' do
18
+ let(:response) { instance_double('HTTParty::Response', class: HTTParty::Response, code: 500) }
19
+
20
+ it 'raises a response error' do
21
+ expect { subject }.to raise_error RedmineClient::Errors::InternalErrorException
22
+ end
23
+ end
24
+
25
+ context 'unknown error' do
26
+ let(:response) { double }
27
+
28
+ it 'raises a standard error' do
29
+ expect { subject }.to raise_error StandardError
30
+ end
31
+ end
32
+
33
+ context 'access denied' do
34
+ let(:response) { instance_double('HTTParty::Response', class: HTTParty::Response, code: 403) }
35
+
36
+ it 'raises the correct error' do
37
+ expect { subject }.to raise_error RedmineClient::Errors::AccessDeniedException
38
+ end
39
+ end
40
+
41
+ context 'resource not found' do
42
+ let(:response) { instance_double('HTTParty::Response', class: HTTParty::Response, code: 404) }
43
+
44
+ it 'raises the correct error' do
45
+ expect { subject }.to raise_error RedmineClient::Errors::ResourceNotFoundException
46
+ end
47
+ end
48
+
49
+ context 'Unprocessable entity error' do
50
+ let(:response) { instance_double('HTTParty::Response', class: HTTParty::Response, code: 422) }
51
+
52
+ before do
53
+ allow(response).to receive(:parsed_response).
54
+ and_return('errors' => ['a is bad', 'b is bad'])
55
+ end
56
+
57
+ it 'raises the correct error' do
58
+ expect { subject }.to raise_error RedmineClient::Errors::UnprocessableEntityException
59
+ end
60
+
61
+ it 'displays a human-readable error message' do
62
+ expect { subject }.to raise_error(
63
+ RedmineClient::Errors::UnprocessableEntityException,
64
+ 'a is bad, b is bad'
65
+ )
66
+ end
67
+ end
68
+ end
69
+
70
+ describe '.find' do
71
+ subject { RedmineClient::Base.find(1) }
72
+
73
+ it 'starts a get request with the correct path' do
74
+ allow(RedmineClient::Base).to receive(:new)
75
+
76
+ expect(RedmineClient::Base).to receive(:get).with('/bases/1.json').and_return double(ok?: true, :[] => '')
77
+
78
+ RedmineClient::Base.find(1)
79
+ end
80
+
81
+ it 'creates a new instance when the response is ok' do
82
+ response = double(ok?: true, :[] => {})
83
+ allow(RedmineClient::Base).to receive(:get).and_return(response)
84
+
85
+ expect(RedmineClient::Base).to receive(:new).with({})
86
+ RedmineClient::Base.find(1)
87
+ end
88
+
89
+ it 'fails when the response smells' do
90
+ response = double(ok?: false)
91
+ allow(RedmineClient::Base).to receive(:get).and_return(response)
92
+ expect(RedmineClient::Base).to receive(:bad_response).with(response, 1)
93
+ RedmineClient::Base.find(1)
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RedmineClient::Issue do
4
+ describe '.search' do
5
+ subject { RedmineClient::Issue.search(subject: 'nice subject', status_id: '*') }
6
+
7
+ it 'starts a get request with the correct path' do
8
+ allow(RedmineClient::Issue).to receive(:new)
9
+ expect(RedmineClient::Issue).
10
+ to receive(:get).with('/issues.json', query: { subject: 'nice subject', status_id: '*'}).
11
+ and_return double(ok?: true, :[] => [])
12
+ subject
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ require 'redmine_client'
2
+
3
+ RedmineClient::API.configure do |config|
4
+ config.url = 'http://redmine.test'
5
+ config.token = 'abcd'
6
+ end
7
+
8
+ require 'pry'
9
+
10
+ Dir["./spec/support/**/*.rb"].sort.each { |f| require f}
11
+
12
+ RSpec.configure do |config|
13
+ config.filter_run :focus
14
+ config.run_all_when_everything_filtered = true
15
+
16
+ if config.files_to_run.one?
17
+ config.default_formatter = 'doc'
18
+ end
19
+
20
+ config.order = :random
21
+ Kernel.srand config.seed
22
+
23
+ config.expect_with :rspec do |expectations|
24
+ expectations.syntax = :expect
25
+ end
26
+
27
+ config.mock_with :rspec do |mocks|
28
+ mocks.syntax = :expect
29
+ mocks.verify_partial_doubles = true
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nine-redmine-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - nine.ch Development-Team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '10.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '10.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.10.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.10.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: httparty
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 4.0.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 4.0.0
83
+ description: To access the Redmine API from ruby scripts.
84
+ email:
85
+ - development@nine.ch
86
+ executables:
87
+ - nine-redmine-client
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - ".rspec"
93
+ - ".ruby-gemset"
94
+ - ".ruby-version"
95
+ - ".travis.yml"
96
+ - CHANGELOG.md
97
+ - Gemfile
98
+ - README.md
99
+ - Rakefile
100
+ - VERSION
101
+ - bin/nine-redmine-client
102
+ - gemfiles/activesupport-4.0.gemfile
103
+ - gemfiles/activesupport-4.1.gemfile
104
+ - gemfiles/activesupport-4.2.gemfile
105
+ - lib/nine-redmine-client.rb
106
+ - lib/redmine_client.rb
107
+ - lib/redmine_client/api.rb
108
+ - lib/redmine_client/base.rb
109
+ - lib/redmine_client/errors.rb
110
+ - lib/redmine_client/issue.rb
111
+ - nine-redmine-client.gemspec
112
+ - spec/redmine_client/base_spec.rb
113
+ - spec/redmine_client/issue_spec.rb
114
+ - spec/spec_helper.rb
115
+ homepage: http://github.com/ninech/
116
+ licenses:
117
+ - MIT
118
+ metadata: {}
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 2.5.1
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: Redmine API ruby client library
139
+ test_files: []