lazylead 0.1.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 +7 -0
- data/ .dockerignore +12 -0
- data/.0pdd.yml +5 -0
- data/.circleci/config.yml +50 -0
- data/.circleci/release_image.sh +13 -0
- data/.circleci/validate.sh +10 -0
- data/.docker/Dockerfile +31 -0
- data/.docker/build.sh +6 -0
- data/.docker/docker-compose.yml +23 -0
- data/.docker/readme.md +21 -0
- data/.gitattributes +9 -0
- data/.github/CODE_OF_CONDUCT.md +76 -0
- data/.github/CONTRIBUTING.md +9 -0
- data/.github/ISSUE_TEMPLATE.md +14 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +11 -0
- data/.github/tasks.yml +24 -0
- data/.github/trello.md +18 -0
- data/.gitignore +12 -0
- data/.pdd +5 -0
- data/.rubocop.yml +87 -0
- data/.ruby-version +1 -0
- data/.rultor.yml +31 -0
- data/.simplecov +16 -0
- data/.travis.yml +16 -0
- data/Gemfile +27 -0
- data/Guardfile +33 -0
- data/Rakefile +93 -0
- data/appveyor.yml +50 -0
- data/bin/.ruby-version +1 -0
- data/bin/lazylead +99 -0
- data/build.sh +6 -0
- data/deploy.sh +16 -0
- data/lazylead.gemspec +106 -0
- data/lib/lazylead.rb +52 -0
- data/lib/lazylead/allocated.rb +56 -0
- data/lib/lazylead/cli/app.rb +87 -0
- data/lib/lazylead/confluence.rb +157 -0
- data/lib/lazylead/email.rb +74 -0
- data/lib/lazylead/exchange.rb +83 -0
- data/lib/lazylead/log.rb +71 -0
- data/lib/lazylead/model.rb +140 -0
- data/lib/lazylead/postman.rb +78 -0
- data/lib/lazylead/salt.rb +91 -0
- data/lib/lazylead/schedule.rb +88 -0
- data/lib/lazylead/smtp.rb +82 -0
- data/lib/lazylead/system/empty.rb +36 -0
- data/lib/lazylead/system/fake.rb +41 -0
- data/lib/lazylead/system/jira.rb +249 -0
- data/lib/lazylead/system/synced.rb +41 -0
- data/lib/lazylead/task/alert.rb +105 -0
- data/lib/lazylead/task/confluence_ref.rb +59 -0
- data/lib/lazylead/task/echo.rb +38 -0
- data/lib/lazylead/task/fix_version.rb +79 -0
- data/lib/lazylead/task/missing_comment.rb +53 -0
- data/lib/lazylead/version.rb +27 -0
- data/lib/messages/due_date_expired.erb +96 -0
- data/lib/messages/illegal_fixversion_change.erb +120 -0
- data/lib/messages/missing_comment.erb +128 -0
- data/license.txt +21 -0
- data/readme.md +160 -0
- data/test/lazylead/allocated_test.rb +51 -0
- data/test/lazylead/cli/app_test.rb +74 -0
- data/test/lazylead/confluence_test.rb +55 -0
- data/test/lazylead/exchange_test.rb +68 -0
- data/test/lazylead/model_test.rb +65 -0
- data/test/lazylead/salt_test.rb +42 -0
- data/test/lazylead/smoke_test.rb +38 -0
- data/test/lazylead/smtp_test.rb +65 -0
- data/test/lazylead/system/jira_test.rb +110 -0
- data/test/lazylead/task/confluence_ref_test.rb +66 -0
- data/test/lazylead/task/duedate_test.rb +126 -0
- data/test/lazylead/task/echo_test.rb +34 -0
- data/test/lazylead/task/fix_version_test.rb +52 -0
- data/test/lazylead/task/missing_comment_test.rb +56 -0
- data/test/lazylead/version_test.rb +36 -0
- data/test/sqlite_test.rb +80 -0
- data/test/test.rb +103 -0
- data/todo.yml +16 -0
- data/upgrades/sqlite/001-install-main-lazylead-tables.sql +63 -0
- data/upgrades/sqlite/999.testdata.sql +39 -0
- metadata +815 -0
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The MIT License
|
4
|
+
#
|
5
|
+
# Copyright (c) 2019-2020 Yurii Dubinka
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
# of this software and associated documentation files (the "Software"),
|
9
|
+
# to deal in the Software without restriction, including without limitation
|
10
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
11
|
+
# and/or sell copies of the Software, and to permit persons to whom
|
12
|
+
# the Software is furnished to do so, subject to the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be included
|
15
|
+
# in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
22
|
+
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
23
|
+
# OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
|
25
|
+
require "active_support"
|
26
|
+
|
27
|
+
module Lazylead
|
28
|
+
#
|
29
|
+
# A cryptography salt defined in environment variables.
|
30
|
+
#
|
31
|
+
# Salt is random data that is used as an additional input to a one-way
|
32
|
+
# function that hashes data, a password or passphrase. Salts are used to
|
33
|
+
# safeguard passwords in storage. Historically a password was stored in
|
34
|
+
# plaintext on a system, but over time additional safeguards developed to
|
35
|
+
# protect a user's password against being read from the system. A salt is one
|
36
|
+
# of those methods.
|
37
|
+
#
|
38
|
+
# Read more: https://en.wikipedia.org/wiki/Salt_(cryptography).
|
39
|
+
#
|
40
|
+
class Salt
|
41
|
+
attr_reader :id
|
42
|
+
#
|
43
|
+
# Each salt should be defined as a environment variable with id, like
|
44
|
+
# salt1=E1F53135E559C253
|
45
|
+
# salt2=84B03D034B409D4E
|
46
|
+
# ...
|
47
|
+
# saltN=xxxxxxxxx
|
48
|
+
#
|
49
|
+
def initialize(id, env = ENV.to_h)
|
50
|
+
@id = id
|
51
|
+
@env = env
|
52
|
+
end
|
53
|
+
|
54
|
+
def encrypt(password)
|
55
|
+
ActiveSupport::MessageEncryptor.new(@env[@id]).encrypt_and_sign password
|
56
|
+
end
|
57
|
+
|
58
|
+
def decrypt(password)
|
59
|
+
ActiveSupport::MessageEncryptor.new(@env[@id]).decrypt_and_verify password
|
60
|
+
end
|
61
|
+
|
62
|
+
def specified?
|
63
|
+
@env.key?(@id) && !@env[@id].blank?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# No cryptography salt defined within environment variables.
|
69
|
+
#
|
70
|
+
class NoSalt
|
71
|
+
def id
|
72
|
+
"No salt"
|
73
|
+
end
|
74
|
+
|
75
|
+
def encrypt(_)
|
76
|
+
raise "ll-003: Unsupported operation: 'encrypt'"
|
77
|
+
end
|
78
|
+
|
79
|
+
def decrypt(_)
|
80
|
+
raise "ll-004: Unsupported operation: 'decrypt'"
|
81
|
+
end
|
82
|
+
|
83
|
+
def specified?
|
84
|
+
false
|
85
|
+
end
|
86
|
+
|
87
|
+
def key
|
88
|
+
raise "ll-005: Unsupported operation: 'key'"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The MIT License
|
4
|
+
#
|
5
|
+
# Copyright (c) 2019-2020 Yurii Dubinka
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
# of this software and associated documentation files (the "Software"),
|
9
|
+
# to deal in the Software without restriction, including without limitation
|
10
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
11
|
+
# and/or sell copies of the Software, and to permit persons to whom
|
12
|
+
# the Software is furnished to do so, subject to the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be included
|
15
|
+
# in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
22
|
+
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
23
|
+
# OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
|
25
|
+
require "json"
|
26
|
+
require "rufus-scheduler"
|
27
|
+
require_relative "log"
|
28
|
+
require_relative "model"
|
29
|
+
|
30
|
+
module Lazylead
|
31
|
+
# The tasks schedule
|
32
|
+
#
|
33
|
+
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
|
34
|
+
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
|
35
|
+
# License:: MIT
|
36
|
+
class Schedule
|
37
|
+
# @todo #/DEV New scheduling types like 'at', 'once' is required.
|
38
|
+
# The minimum time period for cron is 1 minute and it's not suitable for
|
39
|
+
# unit testing, thus its better to introduce new types which allows to
|
40
|
+
# schedule some task once or at particular time period like in next 200ms).
|
41
|
+
# For cron expressions we should define separate test suite which will test
|
42
|
+
# in parallel without blocking main CI process.
|
43
|
+
def initialize(log = Log::NOTHING, cling = true)
|
44
|
+
@log = log
|
45
|
+
@cling = cling
|
46
|
+
@trigger = Rufus::Scheduler.new
|
47
|
+
end
|
48
|
+
|
49
|
+
# @todo #/DEV error code is required for reach 'raise' statement within the
|
50
|
+
# application.
|
51
|
+
def register(task)
|
52
|
+
raise "ll-002: task can't be a null" if task.nil?
|
53
|
+
@trigger.cron task.cron do
|
54
|
+
task.exec @log
|
55
|
+
end
|
56
|
+
@log.debug "Task scheduled: #{task}"
|
57
|
+
end
|
58
|
+
|
59
|
+
# @todo #/DEV inspect the current execution status. This method should
|
60
|
+
# support several format for output, by default is `json`.
|
61
|
+
def ps; end
|
62
|
+
|
63
|
+
def join
|
64
|
+
@trigger.join if @cling
|
65
|
+
end
|
66
|
+
|
67
|
+
# @todo #/DEV stop the execution of current jobs (shutdown?).
|
68
|
+
# The test is required.
|
69
|
+
def stop
|
70
|
+
@trigger.shutdown(:kill)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Fake application schedule for unit testing purposes
|
75
|
+
class NoSchedule
|
76
|
+
def initialize(log = Log::NOTHING)
|
77
|
+
@log = log
|
78
|
+
end
|
79
|
+
|
80
|
+
def register(task)
|
81
|
+
@log.debug("Task registered: #{task}")
|
82
|
+
end
|
83
|
+
|
84
|
+
def ps; end
|
85
|
+
|
86
|
+
def join; end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The MIT License
|
4
|
+
#
|
5
|
+
# Copyright (c) 2019-2020 Yurii Dubinka
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
# of this software and associated documentation files (the "Software"),
|
9
|
+
# to deal in the Software without restriction, including without limitation
|
10
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
11
|
+
# and/or sell copies of the Software, and to permit persons to whom
|
12
|
+
# the Software is furnished to do so, subject to the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be included
|
15
|
+
# in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
22
|
+
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
23
|
+
# OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
|
25
|
+
require "mail"
|
26
|
+
require_relative "log"
|
27
|
+
require_relative "salt"
|
28
|
+
|
29
|
+
module Lazylead
|
30
|
+
#
|
31
|
+
# The emails configuration over SMTP protocol.
|
32
|
+
#
|
33
|
+
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
|
34
|
+
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
|
35
|
+
# License:: MIT
|
36
|
+
class Smtp
|
37
|
+
def initialize(log = Log::NOTHING, salt = NoSalt.new, opts = {})
|
38
|
+
@log = log
|
39
|
+
@salt = salt
|
40
|
+
@opts = opts
|
41
|
+
end
|
42
|
+
|
43
|
+
def enable
|
44
|
+
if @opts.empty? || @opts[:test_mode] || @opts[:smtp_host].blank?
|
45
|
+
Mail.defaults do
|
46
|
+
delivery_method :test
|
47
|
+
end
|
48
|
+
@log.warn "SMTP connection enabled in test mode."
|
49
|
+
else
|
50
|
+
setup_smtp
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def setup_smtp
|
57
|
+
host = @opts[:smtp_host]
|
58
|
+
port = @opts[:smtp_port]
|
59
|
+
user = decrypted(:smtp_user)
|
60
|
+
pass = decrypted(:smtp_pass)
|
61
|
+
Mail.defaults do
|
62
|
+
delivery_method :smtp,
|
63
|
+
address: host,
|
64
|
+
port: port,
|
65
|
+
user_name: user,
|
66
|
+
password: pass,
|
67
|
+
authentication: "plain",
|
68
|
+
enable_starttls_auto: true
|
69
|
+
end
|
70
|
+
@log.debug "SMTP connection established with #{host} as #{user}."
|
71
|
+
end
|
72
|
+
|
73
|
+
# Decrypt the value of configuration property using cryptography salt.
|
74
|
+
def decrypted(key)
|
75
|
+
if @salt.specified?
|
76
|
+
@salt.decrypt(@opts[key])
|
77
|
+
else
|
78
|
+
@opts[key]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The MIT License
|
4
|
+
#
|
5
|
+
# Copyright (c) 2019-2020 Yurii Dubinka
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
# of this software and associated documentation files (the "Software"),
|
9
|
+
# to deal in the Software without restriction, including without limitation
|
10
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
11
|
+
# and/or sell copies of the Software, and to permit persons to whom
|
12
|
+
# the Software is furnished to do so, subject to the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be included
|
15
|
+
# in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
22
|
+
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
23
|
+
# OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
module Lazylead
|
25
|
+
#
|
26
|
+
# A empty ticketing system
|
27
|
+
#
|
28
|
+
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
|
30
|
+
# License:: MIT
|
31
|
+
class Empty
|
32
|
+
def issues(_)
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The MIT License
|
4
|
+
#
|
5
|
+
# Copyright (c) 2019-2020 Yurii Dubinka
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
# of this software and associated documentation files (the "Software"),
|
9
|
+
# to deal in the Software without restriction, including without limitation
|
10
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
11
|
+
# and/or sell copies of the Software, and to permit persons to whom
|
12
|
+
# the Software is furnished to do so, subject to the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be included
|
15
|
+
# in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
22
|
+
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
23
|
+
# OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
|
25
|
+
module Lazylead
|
26
|
+
#
|
27
|
+
# A fake ticketing system
|
28
|
+
#
|
29
|
+
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
|
30
|
+
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
|
31
|
+
# License:: MIT
|
32
|
+
class Fake
|
33
|
+
def initialize(issues = [])
|
34
|
+
@issues = issues
|
35
|
+
end
|
36
|
+
|
37
|
+
def issues(_)
|
38
|
+
@issues
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,249 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The MIT License
|
4
|
+
#
|
5
|
+
# Copyright (c) 2019-2020 Yurii Dubinka
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
# of this software and associated documentation files (the "Software"),
|
9
|
+
# to deal in the Software without restriction, including without limitation
|
10
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
11
|
+
# and/or sell copies of the Software, and to permit persons to whom
|
12
|
+
# the Software is furnished to do so, subject to the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be included
|
15
|
+
# in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
22
|
+
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
23
|
+
# OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
|
25
|
+
require "jira-ruby"
|
26
|
+
require_relative "../salt"
|
27
|
+
|
28
|
+
module Lazylead
|
29
|
+
# Jira system for manipulation with issues.
|
30
|
+
#
|
31
|
+
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
|
32
|
+
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
|
33
|
+
# License:: MIT
|
34
|
+
class Jira
|
35
|
+
# @todo #57/DEV The debug method should be moved outside of ctor.
|
36
|
+
# This was moved here from 'client' method because Rubocop failed the build
|
37
|
+
# due to 'Metrics/AbcSize' violation.
|
38
|
+
def initialize(opts, salt = NoSalt.new, log = Log::NOTHING)
|
39
|
+
@opts = opts
|
40
|
+
@salt = salt
|
41
|
+
@log = log
|
42
|
+
@log.debug "Initiate a Jira client using following opts: " \
|
43
|
+
"#{@opts.except 'password', :password} " \
|
44
|
+
" and salt #{@salt.id} (found=#{@salt.specified?})"
|
45
|
+
end
|
46
|
+
|
47
|
+
def issues(jql, opts = {})
|
48
|
+
raw do |jira|
|
49
|
+
jira.Issue.jql(jql, opts).map { |i| Lazylead::Issue.new(i) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Execute request to the ticketing system using raw client.
|
54
|
+
# For Jira the raw client is 'jira-ruby' gem.
|
55
|
+
def raw
|
56
|
+
raise "ll-06: No block given to method" unless block_given?
|
57
|
+
yield client
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def client
|
63
|
+
return @client if defined? @client
|
64
|
+
@opts[:auth_type] = :basic if @opts[:auth_type].nil?
|
65
|
+
@opts["username"] = @salt.decrypt(@opts["username"]) if @salt.specified?
|
66
|
+
@opts["password"] = @salt.decrypt(@opts["password"]) if @salt.specified?
|
67
|
+
cp("site", :site)
|
68
|
+
cp("username", :username)
|
69
|
+
cp("password", :password)
|
70
|
+
cp("context_path", :context_path)
|
71
|
+
@client = JIRA::Client.new(@opts)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Copy the required/mandatory parameter(s) for Jira client which can't
|
75
|
+
# be specified/defined at database level.
|
76
|
+
#
|
77
|
+
# @todo #/DEV Jira.cp - find a way how to avoid this method.
|
78
|
+
# Potentially, hash with indifferent access might be used.
|
79
|
+
# http://jocellyn.cz/2014/05/03/hash-with-indifferent-access.html
|
80
|
+
# key.kind_of?(Symbol) ? key.to_s : key
|
81
|
+
def cp(act, exp)
|
82
|
+
@opts[exp] = @opts[act] if @opts.key? act
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# An user from Jira which might be reporter, assignee, etc.
|
88
|
+
#
|
89
|
+
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
|
90
|
+
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
|
91
|
+
# License:: MIT
|
92
|
+
class User
|
93
|
+
def initialize(usr)
|
94
|
+
@usr = usr
|
95
|
+
end
|
96
|
+
|
97
|
+
def id
|
98
|
+
@usr["name"]
|
99
|
+
end
|
100
|
+
|
101
|
+
def name
|
102
|
+
@usr["displayName"]
|
103
|
+
end
|
104
|
+
|
105
|
+
def email
|
106
|
+
@usr["emailAddress"]
|
107
|
+
end
|
108
|
+
|
109
|
+
def ==(other)
|
110
|
+
if other.respond_to?(:id)
|
111
|
+
other.id == id
|
112
|
+
else
|
113
|
+
false
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
alias eql? ==
|
118
|
+
|
119
|
+
def hash
|
120
|
+
id.hash
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_s
|
124
|
+
inspect
|
125
|
+
end
|
126
|
+
|
127
|
+
def inspect
|
128
|
+
"#{@opts['site']} (#{@opts['username']})"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
# An issue from Jira
|
134
|
+
#
|
135
|
+
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
|
136
|
+
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
|
137
|
+
# License:: MIT
|
138
|
+
class Issue
|
139
|
+
def initialize(issue)
|
140
|
+
@issue = issue
|
141
|
+
end
|
142
|
+
|
143
|
+
def id
|
144
|
+
@issue.id
|
145
|
+
end
|
146
|
+
|
147
|
+
def key
|
148
|
+
@issue.key
|
149
|
+
end
|
150
|
+
|
151
|
+
def summary
|
152
|
+
fields["summary"]
|
153
|
+
end
|
154
|
+
|
155
|
+
def url
|
156
|
+
@issue.attrs["self"].split("/rest/api/").first + "/browse/" + key
|
157
|
+
end
|
158
|
+
|
159
|
+
def duedate
|
160
|
+
@issue.fields["duedate"]
|
161
|
+
end
|
162
|
+
|
163
|
+
def priority
|
164
|
+
fields["priority"]["name"]
|
165
|
+
end
|
166
|
+
|
167
|
+
def reporter
|
168
|
+
Lazylead::User.new(fields["reporter"])
|
169
|
+
end
|
170
|
+
|
171
|
+
def assignee
|
172
|
+
Lazylead::User.new(@issue.assignee.attrs)
|
173
|
+
end
|
174
|
+
|
175
|
+
def fields
|
176
|
+
@issue.fields
|
177
|
+
end
|
178
|
+
|
179
|
+
def history
|
180
|
+
return [] unless @issue.respond_to? :changelog
|
181
|
+
return [] if @issue.changelog == nil? || @issue.changelog.empty?
|
182
|
+
@issue.changelog["histories"]
|
183
|
+
end
|
184
|
+
|
185
|
+
def comments
|
186
|
+
@issue.comments
|
187
|
+
end
|
188
|
+
|
189
|
+
def to_s
|
190
|
+
"#{key} #{summary}"
|
191
|
+
end
|
192
|
+
|
193
|
+
def inspect
|
194
|
+
to_s
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# The jira issue comments
|
199
|
+
#
|
200
|
+
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
|
201
|
+
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
|
202
|
+
# License:: MIT
|
203
|
+
class Comments
|
204
|
+
attr_reader :issue
|
205
|
+
|
206
|
+
def initialize(issue, sys)
|
207
|
+
@issue = issue
|
208
|
+
@sys = sys
|
209
|
+
end
|
210
|
+
|
211
|
+
def body?(text)
|
212
|
+
comments.any? { |c| c.attrs["body"].include? text }
|
213
|
+
end
|
214
|
+
|
215
|
+
def comments
|
216
|
+
@comments ||= @sys.raw do |conn|
|
217
|
+
conn.Issue.find(@issue.id, expand: "comments,changelog", fields: "")
|
218
|
+
.comments
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def last(quantity)
|
223
|
+
comments.last(quantity).map { |c| c.attrs["body"] }
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# Jira instance without authentication in order to access public filters
|
228
|
+
# or dashboards.
|
229
|
+
class NoAuthJira
|
230
|
+
def initialize(url, log = Log::NOTHING)
|
231
|
+
@jira = Jira.new(
|
232
|
+
{ username: nil, password: nil, site: url, context_path: "" },
|
233
|
+
NoSalt.new,
|
234
|
+
log
|
235
|
+
)
|
236
|
+
end
|
237
|
+
|
238
|
+
def issues(jql, opts = {})
|
239
|
+
@jira.issues(jql, opts)
|
240
|
+
end
|
241
|
+
|
242
|
+
# Execute request to the ticketing system using raw client.
|
243
|
+
# For Jira the raw client is 'jira-ruby' gem.
|
244
|
+
def raw(&block)
|
245
|
+
raise "ll-07: No block given to method" unless block_given?
|
246
|
+
@jira.raw(&block)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|