rujira 0.7.0 → 0.7.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.
- checksums.yaml +4 -4
- data/README.md +23 -1
- data/compose.yaml +1 -1
- data/lib/rujira/api/board.rb +140 -1
- data/lib/rujira/api/common.rb +10 -4
- data/lib/rujira/client.rb +3 -3
- data/lib/rujira/resource/common.rb +1 -1
- data/lib/rujira/resource/issue.rb +4 -0
- data/lib/rujira/resource/myself.rb +12 -0
- data/lib/rujira/resource/project.rb +13 -0
- data/lib/rujira/tasks/generate.rake +17 -5
- data/lib/rujira/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0f34a8819ae3c7e4746ba9230b4a90fc4e12bbd07511b637bc9f525e154658cb
|
|
4
|
+
data.tar.gz: 0ae20244cf2b25fff933d644499d749d62e41a69fefe71f98c884d716935e6ce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0a7f45cf6ca2ec3b6e812d1acc0c4286453da1b0f5695f19c4bb73e27e5b12f2ed6b3c13a0b8f3c887035c93fb4d84c4bdcb209e1374bcfd42d259d843f966d4
|
|
7
|
+
data.tar.gz: '07279fa66131a36441a959028e7d41ee6cffade569f4fe251db24dff47ba412452810f1930c321a7c999aa9dbf1f77414f31f3f345c66f4425721f5d8e64a608'
|
data/README.md
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# RUJIRA
|
|
2
2
|
|
|
3
|
+
[](https://github.com/itmagelab/rujira/actions/workflows/ruby.yml)
|
|
4
|
+
|
|
3
5
|
**RUJIRA** is a Ruby gem for easy interaction with the Jira API. It provides a simple and flexible interface to work with Jira resources and includes Rake tasks for convenient command-line operations.
|
|
4
6
|
|
|
7
|
+
This project was created as an alternative to <https://github.com/sumoheavy/jira-ruby>, offering a more user-friendly and intuitive interface. It lets you work with requests as objects or hash arrays, provides flexibility in choosing a connection adapter, and makes the codebase easier to maintain.
|
|
8
|
+
|
|
5
9
|
---
|
|
6
10
|
|
|
7
11
|
## Features
|
|
@@ -16,7 +20,7 @@
|
|
|
16
20
|
Add to your `Gemfile`:
|
|
17
21
|
|
|
18
22
|
```ruby
|
|
19
|
-
gem 'rujira', '~> 0.
|
|
23
|
+
gem 'rujira', '~> 0.7.0'
|
|
20
24
|
```
|
|
21
25
|
|
|
22
26
|
Or install directly:
|
|
@@ -40,6 +44,24 @@ LOG_LEVEL=error
|
|
|
40
44
|
|
|
41
45
|
### Example of usage
|
|
42
46
|
|
|
47
|
+
By default, we can use an object-oriented approach, but this method does not cover all API capabilities.
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
url = ENV.fetch('RUJIRA_URL', 'http://localhost:8080')
|
|
51
|
+
client = Rujira::Client.new(url, dispatchable: false)
|
|
52
|
+
|
|
53
|
+
project = random_name
|
|
54
|
+
me = client.Myself.get
|
|
55
|
+
project = me.create_software_project key: project.to_s,
|
|
56
|
+
name: project.to_s
|
|
57
|
+
task = project.add_task summary: 'BOT: added a new task.',
|
|
58
|
+
description: 'This task was generated by the bot when creating changes in the repository.'
|
|
59
|
+
task.add_comment 'Bot added a comment as obj #1'
|
|
60
|
+
task.attach_file '/tmp/upload.file'
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Alternatively, we can work with the API directly, as with a regular request dispatcher; in this form, most operations are available.
|
|
64
|
+
|
|
43
65
|
```ruby
|
|
44
66
|
require 'date'
|
|
45
67
|
|
data/compose.yaml
CHANGED
data/lib/rujira/api/board.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Rujira
|
|
|
8
8
|
# API reference:
|
|
9
9
|
# https://docs.atlassian.com/jira-software/REST/9.17.0/#agile/1.0/board
|
|
10
10
|
#
|
|
11
|
-
class Board < Common
|
|
11
|
+
class Board < Common # rubocop:disable Metrics/ClassLength
|
|
12
12
|
# Initializes a new Board API client.
|
|
13
13
|
#
|
|
14
14
|
# @param [Object] client The HTTP client instance used to perform requests.
|
|
@@ -63,6 +63,145 @@ module Rujira
|
|
|
63
63
|
call
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
+
def create(&block)
|
|
67
|
+
builder do
|
|
68
|
+
method :post
|
|
69
|
+
path 'board'
|
|
70
|
+
instance_eval(&block) if block_given?
|
|
71
|
+
end
|
|
72
|
+
call
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def delete(id, &block)
|
|
76
|
+
abort 'Board ID is required' if id.to_s.strip.empty?
|
|
77
|
+
builder do
|
|
78
|
+
method :delete
|
|
79
|
+
path "board/#{id}"
|
|
80
|
+
instance_eval(&block) if block_given?
|
|
81
|
+
end
|
|
82
|
+
call
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def backlog(id, &block)
|
|
86
|
+
abort 'Board ID is required' if id.to_s.strip.empty?
|
|
87
|
+
builder do
|
|
88
|
+
path "board/#{id}/backlog"
|
|
89
|
+
instance_eval(&block) if block_given?
|
|
90
|
+
end
|
|
91
|
+
call
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def configuration(id, &block)
|
|
95
|
+
abort 'Board ID is required' if id.to_s.strip.empty?
|
|
96
|
+
builder do
|
|
97
|
+
path "board/#{id}/configuration"
|
|
98
|
+
instance_eval(&block) if block_given?
|
|
99
|
+
end
|
|
100
|
+
call
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def issue(id, &block)
|
|
104
|
+
abort 'Board ID is required' if id.to_s.strip.empty?
|
|
105
|
+
builder do
|
|
106
|
+
path "board/#{id}/issue"
|
|
107
|
+
instance_eval(&block) if block_given?
|
|
108
|
+
end
|
|
109
|
+
call
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def epic(id, &block)
|
|
113
|
+
abort 'Board ID is required' if id.to_s.strip.empty?
|
|
114
|
+
builder do
|
|
115
|
+
path "board/#{id}/epic"
|
|
116
|
+
instance_eval(&block) if block_given?
|
|
117
|
+
end
|
|
118
|
+
call
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def epic_issues(id, epic_id, &block)
|
|
122
|
+
abort 'Board ID is required' if id.to_s.strip.empty?
|
|
123
|
+
builder do
|
|
124
|
+
path "board/#{id}/epic/#{epic_id}/issue"
|
|
125
|
+
instance_eval(&block) if block_given?
|
|
126
|
+
end
|
|
127
|
+
call
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def epic_none_issues(id, &block)
|
|
131
|
+
abort 'Board ID is required' if id.to_s.strip.empty?
|
|
132
|
+
builder do
|
|
133
|
+
path "board/#{id}/epic/none/issue"
|
|
134
|
+
instance_eval(&block) if block_given?
|
|
135
|
+
end
|
|
136
|
+
call
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def project(id, &block)
|
|
140
|
+
abort 'Board ID is required' if id.to_s.strip.empty?
|
|
141
|
+
builder do
|
|
142
|
+
path "board/#{id}/project"
|
|
143
|
+
instance_eval(&block) if block_given?
|
|
144
|
+
end
|
|
145
|
+
call
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def settings(id, &block)
|
|
149
|
+
abort 'Board ID is required' if id.to_s.strip.empty?
|
|
150
|
+
builder do
|
|
151
|
+
path "board/#{id}/settings/refined-velocity"
|
|
152
|
+
instance_eval(&block) if block_given?
|
|
153
|
+
end
|
|
154
|
+
call
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def set_settings(id, &block)
|
|
158
|
+
abort 'Board ID is required' if id.to_s.strip.empty?
|
|
159
|
+
builder do
|
|
160
|
+
method :put
|
|
161
|
+
path "board/#{id}/settings/refined-velocity"
|
|
162
|
+
instance_eval(&block) if block_given?
|
|
163
|
+
end
|
|
164
|
+
call
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def properties(id, &block)
|
|
168
|
+
abort 'Board ID is required' if id.to_s.strip.empty?
|
|
169
|
+
builder do
|
|
170
|
+
path "board/#{id}/properties"
|
|
171
|
+
instance_eval(&block) if block_given?
|
|
172
|
+
end
|
|
173
|
+
call
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def set_properties(id, property_key, &block)
|
|
177
|
+
abort 'board id is required' if id.to_s.strip.empty?
|
|
178
|
+
builder do
|
|
179
|
+
method :put
|
|
180
|
+
path "board/#{id}/properties/#{property_key}"
|
|
181
|
+
instance_eval(&block) if block_given?
|
|
182
|
+
end
|
|
183
|
+
call
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def get_properties(id, property_key, &block)
|
|
187
|
+
abort 'board id is required' if id.to_s.strip.empty?
|
|
188
|
+
builder do
|
|
189
|
+
path "board/#{id}/properties/#{property_key}"
|
|
190
|
+
instance_eval(&block) if block_given?
|
|
191
|
+
end
|
|
192
|
+
call
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def delete_properties(id, property_key, &block)
|
|
196
|
+
abort 'board id is required' if id.to_s.strip.empty?
|
|
197
|
+
builder do
|
|
198
|
+
method :delete
|
|
199
|
+
path "board/#{id}/properties/#{property_key}"
|
|
200
|
+
instance_eval(&block) if block_given?
|
|
201
|
+
end
|
|
202
|
+
call
|
|
203
|
+
end
|
|
204
|
+
|
|
66
205
|
# Retrieves all sprints for a specific board.
|
|
67
206
|
#
|
|
68
207
|
# Available query parameters:
|
data/lib/rujira/api/common.rb
CHANGED
|
@@ -41,7 +41,7 @@ module Rujira
|
|
|
41
41
|
def call
|
|
42
42
|
@client.logger.debug "Call the method: #{caller_locations(1, 1)[0].label}"
|
|
43
43
|
return @client.dispatch(@request) if @client.dispatchable
|
|
44
|
-
return self if @client.
|
|
44
|
+
return self if @client.lazy
|
|
45
45
|
|
|
46
46
|
to_obj
|
|
47
47
|
end
|
|
@@ -52,6 +52,7 @@ module Rujira
|
|
|
52
52
|
def commit
|
|
53
53
|
@client.dispatch(@request)
|
|
54
54
|
end
|
|
55
|
+
alias execute commit
|
|
55
56
|
|
|
56
57
|
# Converts the API response into structured Ruby objects.
|
|
57
58
|
# If the response is an array of hashes, maps each element through `process`.
|
|
@@ -59,9 +60,9 @@ module Rujira
|
|
|
59
60
|
#
|
|
60
61
|
# @return [Object] Processed response as one or more resource objects, or original response.
|
|
61
62
|
def to_obj
|
|
62
|
-
response =
|
|
63
|
+
response = execute
|
|
63
64
|
|
|
64
|
-
return response.map { |el| process(el) } if response.is_a?(Array) && response.all?
|
|
65
|
+
return response.map { |el| process(el) } if response.is_a?(Array) && response.all?(Hash)
|
|
65
66
|
return response unless response.is_a?(Hash)
|
|
66
67
|
|
|
67
68
|
process response
|
|
@@ -76,7 +77,12 @@ module Rujira
|
|
|
76
77
|
def process(response)
|
|
77
78
|
response.merge!(@metadata)
|
|
78
79
|
resource_class_name = self.class.name.sub('Api', 'Resource')
|
|
79
|
-
|
|
80
|
+
begin
|
|
81
|
+
Object.const_get(resource_class_name).new(@client, **response)
|
|
82
|
+
rescue NameError
|
|
83
|
+
raise "Resource class '#{resource_class_name}' not found. " \
|
|
84
|
+
'Please ensure the class exists or use dispatchable mode.'
|
|
85
|
+
end
|
|
80
86
|
end
|
|
81
87
|
|
|
82
88
|
# Sets ownership context for the resource by storing a parent ID or key
|
data/lib/rujira/client.rb
CHANGED
|
@@ -11,7 +11,7 @@ module Rujira
|
|
|
11
11
|
# client.issue.get("TEST-123")
|
|
12
12
|
#
|
|
13
13
|
class Client
|
|
14
|
-
attr_reader :dispatchable, :logger, :
|
|
14
|
+
attr_reader :dispatchable, :logger, :lazy
|
|
15
15
|
|
|
16
16
|
SUPPORTED_METHODS = %i[get delete head post put patch].freeze
|
|
17
17
|
|
|
@@ -23,9 +23,9 @@ module Rujira
|
|
|
23
23
|
# @example Initialize client
|
|
24
24
|
# client = Rujira::Client.new("https://jira.example.com", debug: true)
|
|
25
25
|
#
|
|
26
|
-
def initialize(url, debug: false, dispatchable: true,
|
|
26
|
+
def initialize(url, debug: false, dispatchable: true, lazy: false, log_level: 'error') # rubocop:disable Metrics/MethodLength
|
|
27
27
|
@dispatchable = dispatchable
|
|
28
|
-
@
|
|
28
|
+
@lazy = lazy
|
|
29
29
|
@uri = URI(url)
|
|
30
30
|
@debug = ENV.fetch('RUJIRA_DEBUG', debug.to_s) == 'true'
|
|
31
31
|
@raise_error = false
|
|
@@ -25,6 +25,18 @@ module Rujira
|
|
|
25
25
|
@name = args['name']
|
|
26
26
|
@email = args['emailAddress']
|
|
27
27
|
end
|
|
28
|
+
|
|
29
|
+
def create_software_project(**args)
|
|
30
|
+
key = args[:key]
|
|
31
|
+
project_name = args[:name]
|
|
32
|
+
name = @name
|
|
33
|
+
@client.Project.create do
|
|
34
|
+
payload key: key,
|
|
35
|
+
name: project_name,
|
|
36
|
+
projectTypeKey: 'software',
|
|
37
|
+
lead: name
|
|
38
|
+
end
|
|
39
|
+
end
|
|
28
40
|
end
|
|
29
41
|
end
|
|
30
42
|
end
|
|
@@ -30,6 +30,19 @@ module Rujira
|
|
|
30
30
|
def delete
|
|
31
31
|
@client.Project.delete(@id)
|
|
32
32
|
end
|
|
33
|
+
|
|
34
|
+
def add_task(**args)
|
|
35
|
+
key = @key
|
|
36
|
+
@client.Issue.create do
|
|
37
|
+
payload fields: {
|
|
38
|
+
project: { key: key },
|
|
39
|
+
summary: args[:summary],
|
|
40
|
+
description: args[:description],
|
|
41
|
+
issuetype: { name: 'Task' }
|
|
42
|
+
}
|
|
43
|
+
params updateHistory: true
|
|
44
|
+
end
|
|
45
|
+
end
|
|
33
46
|
end
|
|
34
47
|
end
|
|
35
48
|
end
|
|
@@ -8,7 +8,7 @@ require 'json'
|
|
|
8
8
|
module Rujira
|
|
9
9
|
module Tasks
|
|
10
10
|
# TODO
|
|
11
|
-
class Jira
|
|
11
|
+
class Jira # rubocop:disable Metrics/ClassLength
|
|
12
12
|
include Rake::DSL if defined?(Rake::DSL)
|
|
13
13
|
def initialize
|
|
14
14
|
generate
|
|
@@ -34,7 +34,7 @@ module Rujira
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def generate # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
37
|
-
namespace :jira do
|
|
37
|
+
namespace :jira do # rubocop:disable Metrics/BlockLength
|
|
38
38
|
desc 'Test connection by getting username'
|
|
39
39
|
task :whoami do
|
|
40
40
|
result = client.Myself.get
|
|
@@ -53,6 +53,18 @@ module Rujira
|
|
|
53
53
|
result = client.Project.list
|
|
54
54
|
puts JSON.pretty_generate(result)
|
|
55
55
|
end
|
|
56
|
+
|
|
57
|
+
desc 'Create project'
|
|
58
|
+
task :create do |t|
|
|
59
|
+
options = fetch_options(%w[KEY NAME TYPE LEAD], t.name)
|
|
60
|
+
result = client.Project.create do
|
|
61
|
+
payload key: options[:key],
|
|
62
|
+
name: options[:name],
|
|
63
|
+
projectTypeKey: options[:type],
|
|
64
|
+
lead: options[:lead]
|
|
65
|
+
end
|
|
66
|
+
puts JSON.pretty_generate(result)
|
|
67
|
+
end
|
|
56
68
|
end
|
|
57
69
|
|
|
58
70
|
namespace :dashboard do
|
|
@@ -107,15 +119,15 @@ module Rujira
|
|
|
107
119
|
end
|
|
108
120
|
end
|
|
109
121
|
|
|
110
|
-
namespace :issue do
|
|
122
|
+
namespace :issue do # rubocop:disable Metrics/BlockLength
|
|
111
123
|
desc 'Create a issue'
|
|
112
124
|
task :create do |t|
|
|
113
|
-
options = fetch_options(%w[
|
|
125
|
+
options = fetch_options(%w[PROJECT_KEY SUMMARY DESCRIPTION ISSUETYPE], t.name)
|
|
114
126
|
abort 'ISSUETYPE must start with a capital letter' unless options[:issuetype].match?(/\A[A-Z]/)
|
|
115
127
|
|
|
116
128
|
result = client.Issue.create do
|
|
117
129
|
payload fields: {
|
|
118
|
-
project: { key: options[:
|
|
130
|
+
project: { key: options[:project_key] },
|
|
119
131
|
summary: options[:summary],
|
|
120
132
|
issuetype: { name: options[:issuetype] },
|
|
121
133
|
description: options[:description]
|
data/lib/rujira/version.rb
CHANGED