lazylead 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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