lazylead 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc28e9d71a966a27880ceac0418cf722b6994e57e60301dc53808cb6bb57e3f2
4
- data.tar.gz: 48724243edda1c24e01e75ea50a63a0775869493696f116485125a90097c7877
3
+ metadata.gz: 1515ec779095fe067759c774a8f81a7f563d55e7f7c9dc9f8cb96644688d1a7e
4
+ data.tar.gz: dfe37f6ed725f609ea1c685c85d17581a87dea40ff1bc3be7967cb15d5c81405
5
5
  SHA512:
6
- metadata.gz: 1748fbb1289cefc4f893d4353544bc635f8942a9df33a0375f57ea14bafa135197ff328e9af4ae7d38fe7fcbc8a9cec6398c10aebd5a1a96a65f6047742ca0f7
7
- data.tar.gz: 9646375b7bcfc1ae3e61ee6075c8eb26055953a423ab6b9c9ccd04311c672dcbcd4310cf9bd7b1a0b06bbdb57c8a186ac7352cdba894972204bb64cee3a7fdac
6
+ metadata.gz: 24246a8ef909f298256a358e6c59778b5e9440aeb8dadfd32dbae21a079832ef3ee6e8126949803784aa2543866626ee3e71a0ee1ef5a102d725b0269aef155c
7
+ data.tar.gz: 445720af7f02f9497b9baf42b2657ea4c428fd2f088d72b1db03b9679f617fc45f049ba6af22dc9e05669c41c0d262fc63d76be06df051ab7e0cbf7f79a03923
@@ -16,9 +16,8 @@ jobs:
16
16
  machine: true
17
17
  steps:
18
18
  - checkout
19
- # build the application image
20
19
  - run:
21
- name: "Build docker image"
20
+ name: "Build LL image"
22
21
  command: |
23
22
  set -e
24
23
  COMMIT_URL="https://github.com/dgroup/lazylead/commit/${CIRCLE_SHA1}"
@@ -32,12 +31,21 @@ jobs:
32
31
  expected="No tasks found"
33
32
  echo "Ensure that app prints the line '${expected}'."
34
33
  grep --color "${expected}" trace.log
35
- # publish the image
36
34
  - run:
37
- name: "Deploy docker image"
35
+ name: "Push LL image"
38
36
  command: |
39
37
  chmod +x .circleci/release_image.sh
40
38
  .circleci/release_image.sh
39
+ - run:
40
+ name: "Build & push LL VCS image"
41
+ command: |
42
+ sed -i "s/0\.0\.0/${DOCKER_RELEASE_TAGS}/g" .docker/vcs.dockerfile
43
+ docker build -t dgroup/lazylead:${DOCKER_RELEASE_TAGS}-vcs . -f .docker/vcs.dockerfile
44
+ docker push dgroup/lazylead:${DOCKER_RELEASE_TAGS}-vcs
45
+ - run:
46
+ name: "Reset tag to master"
47
+ command: |
48
+ curl -s -X POST -u ${CI_TOKEN}:"" --url "https://circleci.com/api/v2/project/gh/dgroup/lazylead/envvar" -H "accept: application/json" -H "content-type: application/json" -d "{ \"name\": \"DOCKER_RELEASE_TAGS\", \"value\": \"master\" }"
41
49
  workflows:
42
50
  version: 2
43
51
  build_and_test:
@@ -12,15 +12,16 @@ ENV APP_HOME=/lazylead
12
12
 
13
13
  WORKDIR $APP_HOME
14
14
 
15
- # @todo #/DEV The current image size is about 150MB.
15
+ # @todo #/DEV Original size of lazylead was 350 MB.
16
+ # After removing of unnecessary libraries it took 250 MB.
16
17
  # The original alpine image is ~20MB.
17
18
  # Image cleanup is required.
18
19
  RUN echo "Install 3rd-party libraries." \
19
- && apk add libc-dev gcc make git sqlite sqlite-dev sqlite-libs tree less vim man bash unzip
20
+ && apk add --no-cache libc-dev gcc git make sqlite sqlite-dev sqlite-libs tree
20
21
 
21
22
  COPY Gemfile lazylead.gemspec ./
22
23
 
23
- RUN bundler install
24
+ RUN bundler install --without development
24
25
 
25
26
  COPY bin/lazylead ./bin/lazylead
26
27
  COPY lib ./lib
@@ -28,4 +29,4 @@ COPY upgrades ./upgrades
28
29
 
29
30
  RUN sed -i "s/0\.0\.0/${version}/g" lib/lazylead/version.rb
30
31
 
31
- CMD ["bin/lazylead", "--trace", "--verbose", "--memory-dump"]
32
+ CMD ["bin/lazylead", "--trace", "--verbose"]
@@ -0,0 +1,10 @@
1
+ FROM dgroup/lazylead:0.0.0
2
+
3
+ LABEL about="https://github.com/dgroup/lazylead" \
4
+ ci.contact="yurii.dubinka@gmail.com" \
5
+ ci.release.tag="${release_tags}" \
6
+ ll.docker.issues="https://github.com/dgroup/lazylead/issues?utf8=✓&q=label%3Adocker"
7
+
8
+ RUN apk add --no-cache subversion git mercurial
9
+
10
+ CMD ["bin/lazylead", "--trace", "--verbose"]
@@ -0,0 +1,92 @@
1
+ ## Notify Jira ticket assignee about expired(ing) due date
2
+ #### Why?
3
+ Why do we need this if Jira has `Filter Subscription` feature:
4
+ - https://confluence.atlassian.com/jira064/receiving-search-results-via-email-720416706.html
5
+ - https://confluence.atlassian.com/jiracorecloud/advanced-searching-765593707.html
6
+
7
+ As far as I know, filter subscription feature doesn't allow(for now) to group tickets by assignee and send to each of them personal message with missing due dates.
8
+ Right now its just send whole list of tickets to you or specified group.
9
+ In worst cases, shared responsibility leads to irresponsibility each individual.
10
+
11
+ #### How to use lazylead for this
12
+ Let's assume that
13
+ 1. JQL for tickets with expired due dates: `project = PRJ and resolution = unresolved and duedate < startOfDay()`
14
+ 2. you've saved this JQL as jira filter with id `222`
15
+ 3. you want to sent an email notification to each assignee about his/her missing due dates over `MS Exchange server`
16
+
17
+ For simplicity, we are using [docker-compose](https://docs.docker.com/compose/):
18
+ 1. Define yml file with `docker-compose` configuration in `lazylead.yml`
19
+ ```yml
20
+ version: '2.3'
21
+ services:
22
+ lazylead:
23
+ image: dgroup/lazylead:latest
24
+ container_name: lazylead
25
+ mem_limit: 128m
26
+ environment:
27
+ # The jira server details.
28
+ # Please ensure that your jira filter(s) grants this user to see issues.
29
+ # Sometimes jira filter(s) may be created with restricted visibility, thus
30
+ # lazylead can't find the issues.
31
+ jira_url: https://your.jira.com
32
+ jira_user: theuser
33
+ jira_password: thepass
34
+ # The MS Exchange server details, please ensure that '/ews/Exchange.asm`
35
+ # will be after your server url. Just change the url to your server.
36
+ exchange_url: https://your.ms.exchange.server/ews/Exchange.asmx
37
+ exchange_user: theuser
38
+ exchange_password: the password
39
+ volumes:
40
+ - ./:/lazylead/db
41
+ # db/ll.db is sqlite file with jira related annoying tasks
42
+ entrypoint: bin/lazylead --sqlite db/ll.db --trace --verbose
43
+ ```
44
+
45
+ 2. Create a container, using `docker-compose -f lazylead.yml up`
46
+ The container will stop as there were no tasks provided:
47
+ ```bash
48
+ ll > docker-compose -f lazylead.yml up
49
+ Creating lazylead ... done
50
+ Attaching to lazylead
51
+ lazylead | [2020-06-06T10:35:13] DEBUG Memory footprint at start is 52MB
52
+ lazylead | [2020-06-06T10:35:13] DEBUG Database: '/lazylead/db/ll.db', sql migration dir: '/lazylead/upgrades/sqlite'
53
+ lazylead | [2020-06-06T10:35:13] DEBUG Migration applied to /lazylead/db/ll.db from /lazylead/upgrades/sqlite
54
+ lazylead | [2020-06-06T10:35:13] DEBUG Database connection established
55
+ lazylead | [2020-06-06T10:35:13] WARN SMTP connection enabled in test mode.
56
+ lazylead | [2020-06-06T10:35:13] WARN ll-001: No tasks found.
57
+ lazylead | [2020-06-06T10:35:13] DEBUG Memory footprint at the end is 66MB
58
+ lazylead exited with code 0
59
+ ll >
60
+ ```
61
+
62
+ 3. Define your team and tasks in database.
63
+ The tables structure defined [here](../upgrades/sqlite/001-install-main-lazylead-tables.sql).
64
+ Modify you [sqlite](https://sqlite.com/index.html) file(`ll.db`) using [DB Browser](https://sqlitebrowser.org/) or any similar tool.
65
+ You may add your email into tasks.properties `"cc":"your@email.com"` in order to be aware that developer got the message, but i don't recommend you as you'll get a dozen of messages in a few days :) .
66
+ ```sql
67
+ insert into teams (id, name, properties)
68
+ values (1, 'Dream team with lazylead', '{}');
69
+ insert into systems(id, properties)
70
+ values (1,'{"type":"Lazylead::Jira", "username":"${jira_user}", "password":"${jira_password}", "site":"${jira_url}", "context_path":""}');
71
+ insert into tasks (name, cron, enabled, id, system, team_id, action, properties)
72
+ values ('Expired due dates',
73
+ '0 8 * * 1-5',
74
+ 'true',
75
+ 1, 1, 1,
76
+ 'Lazylead::Task::AssigneeAlert',
77
+ '{"sql":"filter=222", "cc":"<youremail.com>", "subject":"[LL] Expired due dates", "template":"lib/messages/due_date_expired.erb", "postman":"Lazylead::Exchange"}');
78
+
79
+ ```
80
+ Yes, for task scheduling we are using [cron](https://crontab.guru).
81
+
82
+ 4. Once you changed `./ll.db`, please restart the container using `docker-compose -f .github/tasks.yml restart`
83
+ ```bash
84
+ ll > docker-compose -f .github/tasks.yml restart
85
+ Restarting lazylead ... done
86
+ ```
87
+
88
+
89
+ #### Where is the code?
90
+ | Logic | Tests | Email Template |
91
+ | :-----: | :------: | :-----: |
92
+ | AssigneeAlert in [alert.rb](../lib/lazylead/task/alert.rb)| [duedate_test.rb](../test/lazylead/task/duedate_test.rb) | [due_date_expired.erb](../lib/messages/due_date_expired.erb) |
@@ -0,0 +1,89 @@
1
+ ## Propagate fields from parent Jira ticket to sub-tasks
2
+ #### Why?
3
+ Why do we need this if Jira has automation already?
4
+
5
+ Could you able use this feature right now? Just right now, without requests to some admin/jira owner/submitting some tickets to someone/etc... I doubt.
6
+ In a huge company that's almost impossible to change something special for you in short terms.
7
+
8
+ #### How to use lazylead for this
9
+ Let's assume that
10
+ 1. JQL for parent tickets for the propagation: `issue in parentsOf("project='PRJ' and 'External ID' is empty") and "External ID" is not empty and updated >-1d`.
11
+ 2. you've saved this JQL as jira filter with id `222`.
12
+
13
+ For simplicity, we are using [docker-compose](https://docs.docker.com/compose/):
14
+ 1. Define yml file with `docker-compose` configuration in `lazylead.yml`
15
+ ```yml
16
+ version: '2.3'
17
+ services:
18
+ lazylead:
19
+ image: dgroup/lazylead:latest
20
+ container_name: lazylead
21
+ mem_limit: 128m
22
+ environment:
23
+ # The jira server details.
24
+ # Please ensure that your jira filter(s) grants this user to see issues.
25
+ # Sometimes jira filter(s) may be created with restricted visibility, thus
26
+ # lazylead can't find the issues.
27
+ jira_url: https://your.jira.com
28
+ jira_user: theuser
29
+ jira_password: thepass
30
+ volumes:
31
+ - ./:/lazylead/db
32
+ # db/ll.db is sqlite file with jira related annoying tasks
33
+ entrypoint: bin/lazylead --sqlite db/ll.db --trace --verbose
34
+ ```
35
+
36
+ 2. Create a container, using `docker-compose -f lazylead.yml up`
37
+ The container will stop as there were no tasks provided:
38
+ ```bash
39
+ ll > docker-compose -f lazylead.yml up
40
+ Creating lazylead ... done
41
+ Attaching to lazylead
42
+ lazylead | [2020-06-06T10:35:13] DEBUG Memory footprint at start is 52MB
43
+ lazylead | [2020-06-06T10:35:13] DEBUG Database: '/lazylead/db/ll.db', sql migration dir: '/lazylead/upgrades/sqlite'
44
+ lazylead | [2020-06-06T10:35:13] DEBUG Migration applied to /lazylead/db/ll.db from /lazylead/upgrades/sqlite
45
+ lazylead | [2020-06-06T10:35:13] DEBUG Database connection established
46
+ lazylead | [2020-06-06T10:35:13] WARN SMTP connection enabled in test mode.
47
+ lazylead | [2020-06-06T10:35:13] WARN ll-001: No tasks found.
48
+ lazylead | [2020-06-06T10:35:13] DEBUG Memory footprint at the end is 66MB
49
+ lazylead exited with code 0
50
+ ll >
51
+ ```
52
+
53
+ 3. Define your team and tasks in database.
54
+ The tables structure defined [here](../upgrades/sqlite/001-install-main-lazylead-tables.sql).
55
+ Modify you [sqlite](https://sqlite.com/index.html) file(`ll.db`) using [DB Browser](https://sqlitebrowser.org/) or any similar tool.
56
+ ```sql
57
+ insert into teams (id, name, properties)
58
+ values (1, 'Dream team with lazylead', '{}');
59
+ insert into systems(id, properties)
60
+ values (1,'{"type":"Lazylead::Jira", "username":"${jira_user}", "password":"${jira_password}", "site":"${jira_url}", "context_path":""}');
61
+ insert into tasks (name, cron, enabled, id, system, team_id, action, properties)
62
+ values ('Propagate customfield_1 (External ID) to sub-tasks',
63
+ '0 8 * * 1-5',
64
+ 'true',
65
+ 1, 1, 1,
66
+ 'Lazylead::Task::PropagateDown',
67
+ '{"jql":"filter=222", "fields":"customfield_1"}');
68
+
69
+ ```
70
+ Yes, for task scheduling we are using [cron](https://crontab.guru).
71
+
72
+ 4. Once you changed `./ll.db`, please restart the container using `docker-compose -f .github/tasks.yml restart`
73
+ ```bash
74
+ ll > docker-compose -f .github/tasks.yml restart
75
+ Restarting lazylead ... done
76
+ ```
77
+
78
+ 5. Once task completed, please check your sub-tasks, they should have `customfield_1` and comment like
79
+ ```text
80
+ The following fields were propagated from <parent-ticket-key>:
81
+ ||Field||Value||
82
+ |customfield_1|<parent-field-value>|
83
+ Posted by [lazylead v0.0.0|https://bit.ly/2NjdndS]]
84
+ ```
85
+
86
+ #### Where is the code?
87
+ | Logic | Tests |
88
+ | :-----: | :------: |
89
+ | [propagate_down.rb](../lib/lazylead/task/propagate_down.rb)| [propagate_down_test.rb](../test/lazylead/task/propagate_down_test.rb) |
@@ -25,7 +25,7 @@ Metrics/BlockLength:
25
25
  - "*.gemspec"
26
26
  - "Rakefile"
27
27
  - "bin/lazylead"
28
- - "test/lazylead/cli/start_test.rb"
28
+ - "test/**/*"
29
29
 
30
30
  Metrics/ClassLength:
31
31
  Exclude:
@@ -16,13 +16,13 @@ release:
16
16
  sed -i "s/0\.0\.0/${tag}/g" lib/lazylead/version.rb
17
17
  sed -i "s/0\.0\.0/${tag}/g" lazylead.gemspec
18
18
  bundle install --no-color
19
- bundle exec rake test rubocop sqlint xcop
19
+ bundle exec rake --trace test rubocop sqlint xcop
20
20
  git add lib/lazylead/version.rb lazylead.gemspec
21
21
  git commit -m "version set to ${tag}"
22
22
  gem build lazylead.gemspec
23
23
  chmod 0600 ../rubygems.yml
24
24
  gem push *.gem --config-file ../rubygems.yml
25
- curl -s -X POST --url "https://circleci.com/api/v2/project/gh/dgroup/lazylead/envvar" -H @../circleci.header -H "accept: application/json" -H "content-type: application/json" -d "{ \"name\": \"DOCKER_RELEASE_TAGS\", \"value\": \"latest ${tag}\" }" -o /dev/null
25
+ curl -s -X POST --url "https://circleci.com/api/v2/project/gh/dgroup/lazylead/envvar" -H @../circleci.header -H "accept: application/json" -H "content-type: application/json" -d "{ \"name\": \"DOCKER_RELEASE_TAGS\", \"value\": \"${tag}\" }" -o /dev/null
26
26
  curl -s -X POST --url https://circleci.com/api/v2/project/gh/dgroup/lazylead/pipeline -H @../circleci.header -H 'accept: application/json' -H 'content-type: application/json' -H 'x-attribution-login: dgroup' -o /dev/null
27
27
  merge:
28
28
  script: |-
data/.simplecov CHANGED
@@ -1,11 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
- # @todo #/DEV Increase code coverage from 75% to 80%+.
4
- # Right now it was decreased to 75% due to long manual setup of
5
- # dev. instances of Atlassian Jira and Confluence.
6
- # It was configured locally and there is no automation for now how
7
- # it can be included quickly into CI process. This need to be done later.
8
-
9
3
  SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
10
4
  [SimpleCov::Formatter::HTMLFormatter]
11
5
  )
@@ -34,6 +34,7 @@ require "logging"
34
34
  require "backtrace"
35
35
  require "memory_profiler"
36
36
  require_relative "../lib/lazylead/log"
37
+ require_relative "../lib/lazylead/home"
37
38
  require_relative "../lib/lazylead/schedule"
38
39
  require_relative "../lib/lazylead/allocated"
39
40
  require_relative "../lib/lazylead/cli/app"
@@ -51,8 +52,8 @@ Available options:"
51
52
  o.bool "--memory-dump", "Dump memory snapshot afterwards, to the console",
52
53
  default: false
53
54
  o.string "--home",
54
- "Home directory (default: #{Dir.pwd})",
55
- default: ENV["LL_HOME"].nil? ? Dir.pwd : ENV["LL_HOME"]
55
+ "Home directory (default #{Lazylead::Home.new.dir})",
56
+ default: Lazylead::Home.new.dir
56
57
  o.string "--sqlite",
57
58
  "SQLite database file name",
58
59
  default: "lazylead.db"
@@ -70,6 +71,7 @@ Available options:"
70
71
  exit
71
72
  end
72
73
  end
74
+ log.debug("Version: #{Lazylead::VERSION}")
73
75
  log.debug("Memory footprint at start is #{Lazylead::Allocated.new}")
74
76
  cmd = lambda do
75
77
  Lazylead::CLI::App.new(
@@ -32,7 +32,7 @@ Gem::Specification.new do |s|
32
32
  s.rubygems_version = "2.2"
33
33
  s.required_ruby_version = ">=2.6.5"
34
34
  s.name = "lazylead"
35
- s.version = "0.2.0"
35
+ s.version = "0.3.0"
36
36
  s.license = "MIT"
37
37
  s.summary = "Eliminate the annoying work within bug-trackers."
38
38
  s.description = "Ticketing systems (Github, Jira, etc.) are strongly
@@ -45,7 +45,7 @@ tasks instead of solving technical problems."
45
45
  s.authors = ["Yurii Dubinka"]
46
46
  s.email = "yurii.dubinka@gmail.com"
47
47
  s.homepage = "http://github.com/dgroup/lazylead"
48
- s.post_install_message = "Thanks for installing Lazylead v0.2.0!
48
+ s.post_install_message = "Thanks for installing Lazylead v0.3.0!
49
49
  Read our blog posts: https://lazylead.org
50
50
  Stay in touch with the community in Telegram: https://t.me/lazylead
51
51
  Follow us on Twitter: https://twitter.com/lazylead
@@ -57,12 +57,8 @@ tasks instead of solving technical problems."
57
57
  s.extra_rdoc_files = %w[readme.md license.txt]
58
58
  s.add_runtime_dependency "activerecord", "6.0.3"
59
59
  s.add_runtime_dependency "backtrace", "0.3"
60
- s.add_runtime_dependency "concurrent-ruby", "1.1.5"
61
- s.add_runtime_dependency "diffy", "3.3.0"
62
60
  s.add_runtime_dependency "faraday", "1.0.1"
63
- s.add_runtime_dependency "futex", "0.8.5"
64
61
  s.add_runtime_dependency "get_process_mem", "0.2.5"
65
- s.add_runtime_dependency "haml", "5.0.4"
66
62
  s.add_runtime_dependency "jira-ruby", "1.7.1"
67
63
  s.add_runtime_dependency "json", "2.2.0"
68
64
  s.add_runtime_dependency "logging", "2.2.2"
@@ -72,21 +68,13 @@ tasks instead of solving technical problems."
72
68
  s.add_runtime_dependency "rainbow", "3.0.0"
73
69
  s.add_runtime_dependency "require_all", "3.0.0"
74
70
  s.add_runtime_dependency "rufus-scheduler", "3.6.0"
75
- s.add_runtime_dependency "semantic", "1.6.1"
76
- s.add_runtime_dependency "sinatra", "2.0.5"
77
71
  s.add_runtime_dependency "slop", "4.4"
78
72
  s.add_runtime_dependency "sqlite3", "1.4.2"
79
- s.add_runtime_dependency "sys-proctable", "1.2.1"
80
- s.add_runtime_dependency "threads", "0.3"
81
73
  s.add_runtime_dependency "tilt", "2.0.10"
82
- s.add_runtime_dependency "total", "0.3"
83
- s.add_runtime_dependency "typhoeus", "1.3.1"
84
74
  s.add_runtime_dependency "tzinfo", "1.1"
85
75
  s.add_runtime_dependency "tzinfo-data", "1.2019.3"
86
- s.add_runtime_dependency "usagewatch_ext", "0.2.1"
87
76
  s.add_runtime_dependency "vcs4sql", "0.1.0"
88
77
  s.add_runtime_dependency "viewpoint", "1.1.0"
89
- s.add_runtime_dependency "zache", "0.12"
90
78
  s.add_development_dependency "codecov", "0.1.14"
91
79
  s.add_development_dependency "guard", "2.15.0"
92
80
  s.add_development_dependency "guard-minitest", "2.4.6"
@@ -0,0 +1,174 @@
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
+ require "forwardable"
25
+
26
+ module Lazylead
27
+ # Entry point for email CC detection.
28
+ # The email may need CC email addresses, thus, there are various strategies
29
+ # how it can be done.
30
+ class CC
31
+ # Build an CC in order to detect email addresses by different conditions.
32
+ #
33
+ # Supported conditions(types):
34
+ # - PlainCC
35
+ # - PredefinedCC
36
+ # - ComponentCC
37
+ # - Empty
38
+ #
39
+ def detect(emails, sys)
40
+ return PlainCC.new(emails) if plain?(emails)
41
+ return EmptyCC unless emails.key? "type"
42
+ return EmptyCC if emails["type"].blank? || emails["type"].nil?
43
+ type = emails["type"].constantize
44
+ return ComponentCC.new(emails["project"], sys) if type.is_a? ComponentCC
45
+ type.new(emails["opts"])
46
+ end
47
+
48
+ private
49
+
50
+ # Detect that raw CC is a string which may has plain email addresses
51
+ def plain?(text)
52
+ (text.is_a? String) &&
53
+ (text.to_s.include?(",") || text.to_s.include?("@"))
54
+ end
55
+ end
56
+
57
+ # Array of CC addresses from text for email notification.
58
+ #
59
+ # PlainCC.new("a@f.com, , -,b@f.com").cc # ==> ["a@f.com", "b@f.com"]
60
+ #
61
+ # Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
62
+ # Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
63
+ # License:: MIT
64
+ class PlainCC
65
+ include Enumerable
66
+ extend Forwardable
67
+ def_delegators :@cc, :each
68
+
69
+ # The regexp expression for email notification is very simple, here is the
70
+ # reason why https://bit.ly/38iLKeo
71
+ def initialize(text, regxp = /[^\s]@[^\s]/)
72
+ @text = text
73
+ @regxp = regxp
74
+ end
75
+
76
+ def cc
77
+ @cc ||= begin
78
+ if @text.include? ","
79
+ @text.split(",").map(&:strip).select { |e| e[@regxp] }
80
+ elsif @text[@regxp]
81
+ [@text.strip]
82
+ end
83
+ end
84
+ end
85
+
86
+ def each(&block)
87
+ cc.each(&block)
88
+ end
89
+ end
90
+
91
+ # Empty CC email addresses.
92
+ class EmptyCC
93
+ def cc
94
+ []
95
+ end
96
+ end
97
+
98
+ # Predefined CC addresses for email notification.
99
+ # You may define a hash where
100
+ # - key is Jira ticket component
101
+ # - value is CC email address(es)
102
+ #
103
+ # Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
104
+ # Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
105
+ # License:: MIT
106
+ class PredefinedCC
107
+ def initialize(orig)
108
+ @orig = orig
109
+ end
110
+
111
+ def [](key)
112
+ to_h[key]
113
+ end
114
+
115
+ def cc(*names)
116
+ return to_h.values.flatten.uniq.compact if names.count.zero?
117
+ return self[names.first] if names.count == 1
118
+ to_h.values_at(names.first, *names.drop(1)).flatten.uniq.compact
119
+ end
120
+
121
+ def to_h
122
+ @to_h ||= begin
123
+ if @orig.is_a? Hash
124
+ @orig.each_with_object({}) do |i, o|
125
+ o[i.first] = Lazylead::PlainCC.new(i.last).cc
126
+ end
127
+ else
128
+ {}
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ # CC addresses based on Jira component owners for email notification.
135
+ # Allows to detect the CC for particular ticket based on its component.
136
+ #
137
+ # Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
138
+ # Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
139
+ # License:: MIT
140
+ class ComponentCC < Lazylead::PredefinedCC
141
+ def initialize(prj, jira)
142
+ @prj = prj
143
+ @jira = jira
144
+ end
145
+
146
+ def to_h
147
+ @to_h ||= begin
148
+ components.each_with_object({}) do |c, h|
149
+ email = lead(c.attrs["id"])
150
+ next if email.nil? || email.blank?
151
+ h[c.attrs["name"]] = email
152
+ end
153
+ end
154
+ end
155
+
156
+ private
157
+
158
+ def lead(component_id)
159
+ @jira.raw do |j|
160
+ lead = j.Component
161
+ .find(component_id, expand: "", fields: "")
162
+ .attrs["lead"]
163
+ next if lead.nil? || lead.empty?
164
+ j.User.find(lead["key"]).attrs["emailAddress"]
165
+ end
166
+ end
167
+
168
+ def components
169
+ @jira.raw do |j|
170
+ j.Project.find(@prj, expand: "components", fields: "").components
171
+ end
172
+ end
173
+ end
174
+ end