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
data/build.sh
ADDED
data/deploy.sh
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
set -e
|
3
|
+
set -x
|
4
|
+
|
5
|
+
cd $(dirname $0)
|
6
|
+
bundle update
|
7
|
+
# rake
|
8
|
+
trap 'git reset HEAD~1 && rm bonus.key && git checkout -- .gitignore' EXIT
|
9
|
+
cp /code/home/assets/lazylead/bonus.key .
|
10
|
+
sed -i -s 's|Gemfile.lock||g' .gitignore
|
11
|
+
git add bonus.key
|
12
|
+
git add Gemfile.lock
|
13
|
+
git add .gitignore
|
14
|
+
git commit -m 'configs for heroku'
|
15
|
+
git push heroku master -f
|
16
|
+
|
data/lazylead.gemspec
ADDED
@@ -0,0 +1,106 @@
|
|
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 "English"
|
26
|
+
|
27
|
+
lib = File.expand_path("lib", __dir__)
|
28
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
29
|
+
require "lazylead/version"
|
30
|
+
|
31
|
+
Gem::Specification.new do |s|
|
32
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
33
|
+
s.rubygems_version = "2.2"
|
34
|
+
s.required_ruby_version = ">=2.6.5"
|
35
|
+
s.name = "lazylead"
|
36
|
+
s.version = Lazylead::VERSION
|
37
|
+
s.license = "MIT"
|
38
|
+
s.summary = "Eliminate the annoying work within bug-trackers."
|
39
|
+
s.description = "Ticketing systems (Github, Jira, etc.) are strongly
|
40
|
+
integrated into our processes and everyone understands their necessity. As soon
|
41
|
+
as a developer becomes a lead/technical manager, he or she faces a set of
|
42
|
+
routine tasks that are related to ticketing work. On large projects this becomes
|
43
|
+
a problem, more and more you spend time running around on dashboards and
|
44
|
+
tickets, looking for incorrect deviations in tickets and performing routine
|
45
|
+
tasks instead of solving technical problems."
|
46
|
+
s.authors = ["Yurii Dubinka"]
|
47
|
+
s.email = "yurii.dubinka@gmail.com"
|
48
|
+
s.homepage = "http://github.com/dgroup/lazylead"
|
49
|
+
s.post_install_message = "Thanks for installing Lazylead v0.0.0!
|
50
|
+
Read our blog posts: https://lazylead.org
|
51
|
+
Stay in touch with the community in Telegram: https://t.me/lazylead
|
52
|
+
Follow us on Twitter: https://twitter.com/lazylead
|
53
|
+
If you have any issues, report to our GitHub repo: https://github.com/dgroup/lazylead"
|
54
|
+
s.files = `git ls-files`.split($RS)
|
55
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
56
|
+
s.test_files = s.files.grep(%r{^(test|features)/})
|
57
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
58
|
+
s.extra_rdoc_files = ["readme.md", "license.txt"]
|
59
|
+
s.add_runtime_dependency "activerecord", "6.0.3"
|
60
|
+
s.add_runtime_dependency "backtrace", "0.3"
|
61
|
+
s.add_runtime_dependency "concurrent-ruby", "1.1.5"
|
62
|
+
s.add_runtime_dependency "diffy", "3.3.0"
|
63
|
+
s.add_runtime_dependency "faraday", "1.0.1"
|
64
|
+
s.add_runtime_dependency "futex", "0.8.5"
|
65
|
+
s.add_runtime_dependency "get_process_mem", "0.2.5"
|
66
|
+
s.add_runtime_dependency "haml", "5.0.4"
|
67
|
+
s.add_runtime_dependency "jira-ruby", "1.7.1"
|
68
|
+
s.add_runtime_dependency "json", "2.2.0"
|
69
|
+
s.add_runtime_dependency "logging", "2.2.2"
|
70
|
+
s.add_runtime_dependency "mail", "2.7.1"
|
71
|
+
s.add_runtime_dependency "memory_profiler", "0.9.13"
|
72
|
+
s.add_runtime_dependency "openssl", "2.1.2"
|
73
|
+
s.add_runtime_dependency "rainbow", "3.0.0"
|
74
|
+
s.add_runtime_dependency "require_all", "3.0.0"
|
75
|
+
s.add_runtime_dependency "rufus-scheduler", "3.6.0"
|
76
|
+
s.add_runtime_dependency "semantic", "1.6.1"
|
77
|
+
s.add_runtime_dependency "sinatra", "2.0.5"
|
78
|
+
s.add_runtime_dependency "slop", "4.4"
|
79
|
+
s.add_runtime_dependency "sqlite3", "1.4.2"
|
80
|
+
s.add_runtime_dependency "sys-proctable", "1.2.1"
|
81
|
+
s.add_runtime_dependency "threads", "0.3"
|
82
|
+
s.add_runtime_dependency "tilt", "2.0.10"
|
83
|
+
s.add_runtime_dependency "total", "0.3"
|
84
|
+
s.add_runtime_dependency "typhoeus", "1.3.1"
|
85
|
+
s.add_runtime_dependency "tzinfo", "1.1"
|
86
|
+
s.add_runtime_dependency "tzinfo-data", "1.2019.3"
|
87
|
+
s.add_runtime_dependency "usagewatch_ext", "0.2.1"
|
88
|
+
s.add_runtime_dependency "vcs4sql", "0.1.0"
|
89
|
+
s.add_runtime_dependency "viewpoint", "1.1.0"
|
90
|
+
s.add_runtime_dependency "zache", "0.12"
|
91
|
+
s.add_development_dependency "codecov", "0.1.14"
|
92
|
+
s.add_development_dependency "guard", "2.15.0"
|
93
|
+
s.add_development_dependency "guard-minitest", "2.4.6"
|
94
|
+
s.add_development_dependency "minitest", "5.11.3"
|
95
|
+
s.add_development_dependency "minitest-fail-fast", "0.1.0"
|
96
|
+
s.add_development_dependency "minitest-hooks", "1.5.0"
|
97
|
+
s.add_development_dependency "minitest-reporters", "1.3.6"
|
98
|
+
s.add_development_dependency "rake", "12.3.2"
|
99
|
+
s.add_development_dependency "random-port", "0.3.1"
|
100
|
+
s.add_development_dependency "rdoc", "6.1.1"
|
101
|
+
s.add_development_dependency "rubocop", "0.82"
|
102
|
+
s.add_development_dependency "rubocop-minitest", "0.5.1"
|
103
|
+
s.add_development_dependency "rubocop-performance", "1.5.2"
|
104
|
+
s.add_development_dependency "rubocop-rspec", "1.33.0"
|
105
|
+
s.add_development_dependency "xcop", "0.6"
|
106
|
+
end
|
data/lib/lazylead.rb
ADDED
@@ -0,0 +1,52 @@
|
|
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_relative "lazylead/allocated"
|
26
|
+
require_relative "lazylead/confluence"
|
27
|
+
require_relative "lazylead/email"
|
28
|
+
require_relative "lazylead/exchange"
|
29
|
+
require_relative "lazylead/log"
|
30
|
+
require_relative "lazylead/model"
|
31
|
+
require_relative "lazylead/postman"
|
32
|
+
require_relative "lazylead/salt"
|
33
|
+
require_relative "lazylead/schedule"
|
34
|
+
require_relative "lazylead/smtp"
|
35
|
+
require_relative "lazylead/cli/app"
|
36
|
+
require_relative "lazylead/system/jira"
|
37
|
+
require_relative "lazylead/system/empty"
|
38
|
+
require_relative "lazylead/system/fake"
|
39
|
+
require_relative "lazylead/system/synced"
|
40
|
+
require_relative "lazylead/task/alert"
|
41
|
+
require_relative "lazylead/task/confluence_ref"
|
42
|
+
require_relative "lazylead/task/echo"
|
43
|
+
require_relative "lazylead/task/fix_version"
|
44
|
+
require_relative "lazylead/task/missing_comment"
|
45
|
+
require_relative "lazylead/version"
|
46
|
+
|
47
|
+
# Lazylead main module.
|
48
|
+
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
|
49
|
+
# Copyright:: Copyright (c) 2020 Yurii Dubinka
|
50
|
+
# License:: MIT
|
51
|
+
module Lazylead
|
52
|
+
end
|
@@ -0,0 +1,56 @@
|
|
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 "get_process_mem"
|
26
|
+
|
27
|
+
module Lazylead
|
28
|
+
# Human readable format of allocated bytes within current process.
|
29
|
+
#
|
30
|
+
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
|
31
|
+
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
|
32
|
+
# License:: MIT
|
33
|
+
class Allocated
|
34
|
+
def initialize(bytes = GetProcessMem.new.bytes.to_i)
|
35
|
+
@bytes = bytes
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
if @bytes.nil?
|
40
|
+
"?"
|
41
|
+
elsif @bytes < 1024
|
42
|
+
"#{@bytes}B"
|
43
|
+
elsif @bytes < 1024 * 1024
|
44
|
+
"#{(@bytes / 1024).round}KB"
|
45
|
+
elsif @bytes < 1024 * 1024 * 1024
|
46
|
+
"#{(@bytes / (1024 * 1024)).round}MB"
|
47
|
+
else
|
48
|
+
"#{(@bytes / (1024 * 1024 * 1024)).round}GB"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_i
|
53
|
+
@bytes
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,87 @@
|
|
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 "vcs4sql/sqlite/migration"
|
26
|
+
require_relative "../smtp"
|
27
|
+
require_relative "../schedule"
|
28
|
+
|
29
|
+
module Lazylead
|
30
|
+
# @todo #/DEV Lazylead::CLI::Args add a new class which extends hash
|
31
|
+
# in order to access command-line arguments in easy manner.
|
32
|
+
module CLI
|
33
|
+
#
|
34
|
+
# APP start command.
|
35
|
+
#
|
36
|
+
# By default, the app will check the version of the database structure and
|
37
|
+
# apply the missing change sets (more https://github.com/dgroup/vcs4sql).
|
38
|
+
#
|
39
|
+
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
|
40
|
+
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
|
41
|
+
# License:: MIT
|
42
|
+
class App
|
43
|
+
def initialize(log, schedule, smtp = Smtp.new)
|
44
|
+
@log = log
|
45
|
+
@schedule = schedule
|
46
|
+
@smtp = smtp
|
47
|
+
end
|
48
|
+
|
49
|
+
def run(opts)
|
50
|
+
apply_vcs_migration opts
|
51
|
+
enable_active_record
|
52
|
+
@smtp.enable
|
53
|
+
schedule_tasks
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def apply_vcs_migration(opts)
|
59
|
+
@db = File.expand_path(opts[:home]) + "/" + opts[:sqlite]
|
60
|
+
vcs = File.expand_path(opts[:home]) + "/" + opts[:vcs4sql]
|
61
|
+
@log.debug "Database: '#{@db}', sql migration dir: '#{vcs}'"
|
62
|
+
Vcs4sql::Sqlite::Migration.new(@db).upgrade vcs, opts[:testdata]
|
63
|
+
@log.debug "Migration applied to #{@db} from #{vcs}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def enable_active_record
|
67
|
+
ActiveRecord::Base.establish_connection(
|
68
|
+
adapter: "sqlite3",
|
69
|
+
database: @db
|
70
|
+
)
|
71
|
+
@log.debug "Database connection established"
|
72
|
+
end
|
73
|
+
|
74
|
+
def schedule_tasks
|
75
|
+
todo = ORM::Task.where(enabled: "true")
|
76
|
+
if todo.empty?
|
77
|
+
@log.warn "ll-001: No tasks found."
|
78
|
+
else
|
79
|
+
todo.find_each do |task|
|
80
|
+
@schedule.register task
|
81
|
+
end
|
82
|
+
@schedule.join
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,157 @@
|
|
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 "faraday"
|
26
|
+
require "jira-ruby"
|
27
|
+
|
28
|
+
module Lazylead
|
29
|
+
# Represents single Confluence instance.
|
30
|
+
#
|
31
|
+
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
|
32
|
+
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
|
33
|
+
# License:: MIT
|
34
|
+
class Confluence
|
35
|
+
def initialize(conf)
|
36
|
+
@conf = conf
|
37
|
+
@http = Faraday.new(url: @conf.url)
|
38
|
+
@http.basic_auth(@conf.user, @conf.pass)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Confluence instance url like
|
42
|
+
# http://confluence.com
|
43
|
+
# https://confluence.com
|
44
|
+
def url
|
45
|
+
@conf.url
|
46
|
+
end
|
47
|
+
|
48
|
+
# Construct the remote link from Jira ticket to Confluence page.
|
49
|
+
# Read more:
|
50
|
+
# - https://bit.ly/2zkfTwB
|
51
|
+
# - https://bit.ly/2zk8iOB
|
52
|
+
# - https://bit.ly/3bkGkiU
|
53
|
+
def make_link(url, type = "Wiki Page")
|
54
|
+
{
|
55
|
+
globalId: "appId=#{@conf.app}&pageId=#{url[/pageId=(?<id>\d+)/, 1]}",
|
56
|
+
application: { type: @conf.type, name: @conf.name },
|
57
|
+
relationship: type,
|
58
|
+
object: { url: url, title: type }
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
# Fetch the page url with pageId (Atlassian global id)
|
63
|
+
# using confluence space name and page title.
|
64
|
+
#
|
65
|
+
# @return url with following format
|
66
|
+
# http://host/pages/viewpage.action?pageId=xxxxx or blank string in case of
|
67
|
+
# errors
|
68
|
+
#
|
69
|
+
# @todo #/DEV Unable to find confluence pages where title has ":" symbol.
|
70
|
+
# The symbol ":" might be replaced by "%3A". The search needs to consider
|
71
|
+
# this case as well.
|
72
|
+
def fetch_page_id(space, title)
|
73
|
+
resp = @http.get(
|
74
|
+
"/rest/api/content", limit: 1, spaceKey: space, title: title
|
75
|
+
).body
|
76
|
+
return "" if resp.blank?
|
77
|
+
pages = JSON.parse(resp)
|
78
|
+
return "" if pages["results"].empty?
|
79
|
+
"#{@conf.url}/pages/viewpage.action?"\
|
80
|
+
"pageId=#{pages['results'].first['id']}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# The reference from Jira issue to Confluence system.
|
85
|
+
class Link
|
86
|
+
# :issue :: The issue from external system
|
87
|
+
# :sys :: The jira ticketing system
|
88
|
+
# :cnfl :: The Confluence instances details (host, appId)
|
89
|
+
# which expected within the comments
|
90
|
+
def initialize(issue, sys, cnfl)
|
91
|
+
@issue = issue
|
92
|
+
@sys = sys
|
93
|
+
@confl = cnfl
|
94
|
+
end
|
95
|
+
|
96
|
+
# Fetch ticket links from comments
|
97
|
+
def fetch_links
|
98
|
+
ticket = @sys.raw do |conn|
|
99
|
+
conn.Issue.find(@issue.id, expand: "comments,changelog", fields: "")
|
100
|
+
end
|
101
|
+
@mentioned = mentioned_links(ticket)
|
102
|
+
@existing = existing_links(ticket)
|
103
|
+
@diff = @mentioned.reject { |url| @existing.include? url }
|
104
|
+
end
|
105
|
+
|
106
|
+
# Detect links mentioned in ticket comments
|
107
|
+
def mentioned_links(ticket)
|
108
|
+
ticket.comments
|
109
|
+
.map { |cmnt| cmnt.attrs["body"] }
|
110
|
+
.select { |cmnt| @confl.any? { |c| cmnt.include? c.url } }
|
111
|
+
.flat_map { |cmnt| cmnt.split " " }
|
112
|
+
.select { |cmnt| @confl.any? { |c| cmnt.start_with? c.url } }
|
113
|
+
.map(&method(:to_page_id))
|
114
|
+
.reject(&:blank?)
|
115
|
+
.uniq
|
116
|
+
end
|
117
|
+
|
118
|
+
# Convert confluence page url to the following format:
|
119
|
+
# http://confluence.com/pages/viewpage.action?pageId=xxxxx
|
120
|
+
#
|
121
|
+
# Sometimes links to confluence pages have the following formats:
|
122
|
+
# http://confluence.com/pages/spaceKey=THESPACE&title=THETITLE
|
123
|
+
# http://confluence.com/display/THESPACE/THETITLE
|
124
|
+
# and can't be linked though the "remote link" Jira functionality.
|
125
|
+
def to_page_id(url)
|
126
|
+
return url if url.include? "pageId="
|
127
|
+
if url.include? "&title="
|
128
|
+
space = url[/spaceKey=(?<space>[A-Z0-9+.]+)/, 1]
|
129
|
+
title = url[/&title=(?<title>[A-Za-z0-9+.]+)/, 1]
|
130
|
+
else
|
131
|
+
space, title = url.split("/").last(2)
|
132
|
+
end
|
133
|
+
@confl.find { |c| url.start_with? c.url }
|
134
|
+
.fetch_page_id(space, title.tr("+", " "))
|
135
|
+
end
|
136
|
+
|
137
|
+
# Detect existing links from the ticket
|
138
|
+
def existing_links(ticket, type = "Wiki Page")
|
139
|
+
ticket.remotelink
|
140
|
+
.all
|
141
|
+
.select { |l| l.attrs["relationship"] == type }
|
142
|
+
.map { |e| e.attrs["object"]["url"] }
|
143
|
+
end
|
144
|
+
|
145
|
+
def need_link?
|
146
|
+
!@diff.empty?
|
147
|
+
end
|
148
|
+
|
149
|
+
# Add reference to Confluence page from current issue
|
150
|
+
def add_link
|
151
|
+
@diff.each do |url|
|
152
|
+
cnf = @confl.find { |c| url.start_with? c.url }
|
153
|
+
@issue.remotelink.build.save cnf.make_link(url)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|