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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5e934f91388416b891e49d824c5f3d875708d5102d2084d8fa3c641be5006d02
4
- data.tar.gz: 5cc8ee2aa9475057ae26953287f5f99c9be83adc0cd578236d17b758d5c82486
3
+ metadata.gz: 0f34a8819ae3c7e4746ba9230b4a90fc4e12bbd07511b637bc9f525e154658cb
4
+ data.tar.gz: 0ae20244cf2b25fff933d644499d749d62e41a69fefe71f98c884d716935e6ce
5
5
  SHA512:
6
- metadata.gz: 83a61e445cb8b1a3e2e5f5cb338d9f31070df47c3ea1aff9be54c49a63f8d022658d76856fee5f934b0343b79d37c04ae78bf9cfd17cb721fa988f3971f9ac1f
7
- data.tar.gz: 503b7bc45991306f9346ee2b8cc1b77e492194544caea88bb3931b71d30f04a8f99fc10a76de98f6ff91d008743de259860503c61698f159b1fbc8bfc04c22de
6
+ metadata.gz: 0a7f45cf6ca2ec3b6e812d1acc0c4286453da1b0f5695f19c4bb73e27e5b12f2ed6b3c13a0b8f3c887035c93fb4d84c4bdcb209e1374bcfd42d259d843f966d4
7
+ data.tar.gz: '07279fa66131a36441a959028e7d41ee6cffade569f4fe251db24dff47ba412452810f1930c321a7c999aa9dbf1f77414f31f3f345c66f4425721f5d8e64a608'
data/README.md CHANGED
@@ -1,7 +1,11 @@
1
1
  # RUJIRA
2
2
 
3
+ [![Ruby](https://github.com/itmagelab/rujira/actions/workflows/ruby.yml/badge.svg)](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.6.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
@@ -13,7 +13,7 @@ services:
13
13
 
14
14
  db:
15
15
  image: postgres
16
- mem_limit: 128mb
16
+ mem_limit: 128mb
17
17
  restart: always
18
18
  shm_size: 128mb
19
19
  environment:
@@ -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:
@@ -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.commitable
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 = commit
63
+ response = execute
63
64
 
64
- return response.map { |el| process(el) } if response.is_a?(Array) && response.all? { |el| el.is_a?(Hash) }
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
- Object.const_get(resource_class_name).new(@client, **response)
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, :commitable
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, commitable: false, log_level: 'error') # rubocop:disable Metrics/MethodLength
26
+ def initialize(url, debug: false, dispatchable: true, lazy: false, log_level: 'error') # rubocop:disable Metrics/MethodLength
27
27
  @dispatchable = dispatchable
28
- @commitable = commitable
28
+ @lazy = lazy
29
29
  @uri = URI(url)
30
30
  @debug = ENV.fetch('RUJIRA_DEBUG', debug.to_s) == 'true'
31
31
  @raise_error = false
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Rujira
4
4
  module Resource
5
- class Common
5
+ class Common # rubocop:disable Style/Documentation
6
6
  def initialize(client, **_args)
7
7
  @client = client
8
8
  end
@@ -47,6 +47,10 @@ module Rujira
47
47
  @client.logger.debug "Deleting issue #{@key}"
48
48
  @client.Issue.delete(@id)
49
49
  end
50
+
51
+ def attach_file(path)
52
+ @client.Issue.attachments @key, path
53
+ end
50
54
  end
51
55
  end
52
56
  end
@@ -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[PROJECT SUMMARY DESCRIPTION ISSUETYPE], t.name)
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[:project] },
130
+ project: { key: options[:project_key] },
119
131
  summary: options[:summary],
120
132
  issuetype: { name: options[:issuetype] },
121
133
  description: options[:description]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rujira
4
- VERSION = '0.7.0'
4
+ VERSION = '0.7.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rujira
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey Semenov