lazylead 0.1.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +19 -7
  3. data/.circleci/release_image.sh +10 -7
  4. data/.docker/Dockerfile +10 -9
  5. data/.docker/docker-compose.yml +3 -3
  6. data/.docker/readme.md +24 -21
  7. data/.docker/vcs.dockerfile +10 -0
  8. data/.docs/duedate_expired.md +92 -0
  9. data/.docs/propagate_down.md +89 -0
  10. data/.rubocop.yml +1 -1
  11. data/.rultor.yml +13 -14
  12. data/.simplecov +0 -6
  13. data/CNAME +1 -0
  14. data/Rakefile +38 -1
  15. data/bin/lazylead +7 -2
  16. data/lazylead.gemspec +5 -17
  17. data/lib/lazylead/cc.rb +180 -0
  18. data/lib/lazylead/cli/app.rb +4 -3
  19. data/lib/lazylead/exchange.rb +14 -1
  20. data/lib/lazylead/home.rb +38 -0
  21. data/lib/lazylead/model.rb +29 -7
  22. data/lib/lazylead/postman.rb +14 -14
  23. data/lib/lazylead/schedule.rb +4 -2
  24. data/lib/lazylead/system/fake.rb +1 -1
  25. data/lib/lazylead/system/jira.rb +46 -5
  26. data/lib/lazylead/task/fix_version.rb +1 -1
  27. data/lib/lazylead/task/propagate_down.rb +118 -0
  28. data/lib/lazylead/task/savepoint.rb +58 -0
  29. data/lib/lazylead/version.rb +1 -1
  30. data/lib/messages/due_date_expired.erb +8 -7
  31. data/lib/messages/illegal_fixversion_change.erb +9 -8
  32. data/lib/messages/missing_comment.erb +10 -9
  33. data/lib/messages/savepoint.erb +43 -0
  34. data/readme.md +98 -82
  35. data/test/lazylead/cc_test.rb +153 -0
  36. data/test/lazylead/cli/app_test.rb +1 -2
  37. data/test/lazylead/exchange_test.rb +20 -0
  38. data/test/lazylead/model_test.rb +11 -0
  39. data/test/lazylead/postman_test.rb +57 -0
  40. data/test/lazylead/system/jira_test.rb +8 -0
  41. data/test/lazylead/task/assignee_alert_test.rb +47 -0
  42. data/test/lazylead/task/duedate_test.rb +20 -8
  43. data/test/lazylead/task/fix_version_test.rb +2 -4
  44. data/test/lazylead/task/missing_comment_test.rb +2 -4
  45. data/test/lazylead/task/propagate_down_test.rb +86 -0
  46. data/test/lazylead/task/savepoint_test.rb +51 -0
  47. data/test/test.rb +11 -0
  48. data/upgrades/sqlite/001-install-main-lazylead-tables.sql +3 -4
  49. data/upgrades/sqlite/999.testdata.sql +7 -2
  50. metadata +38 -175
  51. data/deploy.sh +0 -16
  52. data/todo.yml +0 -16
data/CNAME ADDED
@@ -0,0 +1 @@
1
+ lazylead.org
data/Rakefile CHANGED
@@ -26,6 +26,7 @@ require "rubygems"
26
26
  require "rake"
27
27
  require "date"
28
28
  require "rdoc"
29
+ require "rainbow"
29
30
  require "rake/clean"
30
31
 
31
32
  # @todo #/DEV Investigate the possibility of using migrations from active_record
@@ -44,7 +45,7 @@ def version
44
45
  Gem::Specification.load(Dir["*.gemspec"].first).version
45
46
  end
46
47
 
47
- task default: %i[clean test rubocop xcop copyright]
48
+ task default: %i[clean test rubocop sqlint xcop copyright docker]
48
49
 
49
50
  require "rake/testtask"
50
51
  desc "Run all unit tests"
@@ -88,6 +89,42 @@ Xcop::RakeTask.new :xcop do |task|
88
89
  task.excludes = %w[target/**/* coverage/**/* wp/**/*]
89
90
  end
90
91
 
92
+ # @todo #/DEV Enable rule "Checks SQL against the ANSI syntax" fully.
93
+ # Right now all violations related to PRAGMA https://www.sqlite.org/pragma.html
94
+ # are suppressed as PRAGMA is sqlite specific option.
95
+ # Potential fix is to move this option into vcs4sql lib and remove from our
96
+ # sql files.
97
+ task :sqlint do
98
+ puts "Running sqlint..."
99
+ require "sqlint"
100
+ src = Dir.glob("upgrades/**/*.sql")
101
+ puts "Inspecting #{src.size} files"
102
+ total = 0
103
+ src.each do |f|
104
+ violations = SQLint::Linter.new(f, File.open(f, "r"))
105
+ .run
106
+ .first(1000)
107
+ .reject { |v| v.message.include? '"PRAGMA"' }
108
+ violations.each do |v|
109
+ msg_lines = v.message.split("\n")
110
+ p [v.filename, v.line, v.column, "#{v.type} #{msg_lines.shift}"].join ":"
111
+ end
112
+ total += violations.count { |lint| lint.type == :error }
113
+ end
114
+ if total.positive?
115
+ abort "#{Rainbow(total).red} SQL violations found."
116
+ else
117
+ puts "#{src.size} files inspected, #{Rainbow('no offenses').green} detected"
118
+ end
119
+ end
120
+
91
121
  task :clean do
92
122
  Dir.glob("test/resources/**/*.db").each { |f| File.delete(f) }
93
123
  end
124
+
125
+ task :docker do
126
+ puts "Building docker image..."
127
+ system "docker-compose -f .docker/docker-compose.yml build "\
128
+ " --build-arg release_tags='latest 1.0'"\
129
+ " --build-arg version=1.0"
130
+ end
@@ -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,14 +52,17 @@ 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"
59
60
  o.string "--vcs4sql",
60
61
  "Home directory with database version control(vcs) scripts",
61
62
  default: "upgrades/sqlite"
63
+ o.integer "--max-connections",
64
+ "SQL connections pool size",
65
+ default: 5
62
66
  o.bool "--testdata",
63
67
  "Apply the database VCS migration with test data",
64
68
  default: false
@@ -70,6 +74,7 @@ Available options:"
70
74
  exit
71
75
  end
72
76
  end
77
+ log.debug("Version: #{Lazylead::VERSION}")
73
78
  log.debug("Memory footprint at start is #{Lazylead::Allocated.new}")
74
79
  cmd = lambda do
75
80
  Lazylead::CLI::App.new(
@@ -26,14 +26,13 @@ require "English"
26
26
 
27
27
  lib = File.expand_path("lib", __dir__)
28
28
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
29
- require "lazylead/version"
30
29
 
31
30
  Gem::Specification.new do |s|
32
31
  s.specification_version = 2 if s.respond_to? :specification_version=
33
32
  s.rubygems_version = "2.2"
34
33
  s.required_ruby_version = ">=2.6.5"
35
34
  s.name = "lazylead"
36
- s.version = Lazylead::VERSION
35
+ s.version = "0.3.1"
37
36
  s.license = "MIT"
38
37
  s.summary = "Eliminate the annoying work within bug-trackers."
39
38
  s.description = "Ticketing systems (Github, Jira, etc.) are strongly
@@ -46,7 +45,7 @@ tasks instead of solving technical problems."
46
45
  s.authors = ["Yurii Dubinka"]
47
46
  s.email = "yurii.dubinka@gmail.com"
48
47
  s.homepage = "http://github.com/dgroup/lazylead"
49
- s.post_install_message = "Thanks for installing Lazylead v0.0.0!
48
+ s.post_install_message = "Thanks for installing Lazylead v0.3.1!
50
49
  Read our blog posts: https://lazylead.org
51
50
  Stay in touch with the community in Telegram: https://t.me/lazylead
52
51
  Follow us on Twitter: https://twitter.com/lazylead
@@ -55,15 +54,11 @@ tasks instead of solving technical problems."
55
54
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
56
55
  s.test_files = s.files.grep(%r{^(test|features)/})
57
56
  s.rdoc_options = ["--charset=UTF-8"]
58
- s.extra_rdoc_files = ["readme.md", "license.txt"]
57
+ s.extra_rdoc_files = %w[readme.md license.txt]
59
58
  s.add_runtime_dependency "activerecord", "6.0.3"
60
59
  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
60
  s.add_runtime_dependency "faraday", "1.0.1"
64
- s.add_runtime_dependency "futex", "0.8.5"
65
61
  s.add_runtime_dependency "get_process_mem", "0.2.5"
66
- s.add_runtime_dependency "haml", "5.0.4"
67
62
  s.add_runtime_dependency "jira-ruby", "1.7.1"
68
63
  s.add_runtime_dependency "json", "2.2.0"
69
64
  s.add_runtime_dependency "logging", "2.2.2"
@@ -73,21 +68,13 @@ tasks instead of solving technical problems."
73
68
  s.add_runtime_dependency "rainbow", "3.0.0"
74
69
  s.add_runtime_dependency "require_all", "3.0.0"
75
70
  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
71
  s.add_runtime_dependency "slop", "4.4"
79
72
  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
73
  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
74
  s.add_runtime_dependency "tzinfo", "1.1"
86
75
  s.add_runtime_dependency "tzinfo-data", "1.2019.3"
87
- s.add_runtime_dependency "usagewatch_ext", "0.2.1"
88
76
  s.add_runtime_dependency "vcs4sql", "0.1.0"
89
77
  s.add_runtime_dependency "viewpoint", "1.1.0"
90
- s.add_runtime_dependency "zache", "0.12"
91
78
  s.add_development_dependency "codecov", "0.1.14"
92
79
  s.add_development_dependency "guard", "2.15.0"
93
80
  s.add_development_dependency "guard-minitest", "2.4.6"
@@ -95,12 +82,13 @@ tasks instead of solving technical problems."
95
82
  s.add_development_dependency "minitest-fail-fast", "0.1.0"
96
83
  s.add_development_dependency "minitest-hooks", "1.5.0"
97
84
  s.add_development_dependency "minitest-reporters", "1.3.6"
98
- s.add_development_dependency "rake", "12.3.2"
85
+ s.add_development_dependency "rake", "12.3.3"
99
86
  s.add_development_dependency "random-port", "0.3.1"
100
87
  s.add_development_dependency "rdoc", "6.1.1"
101
88
  s.add_development_dependency "rubocop", "0.82"
102
89
  s.add_development_dependency "rubocop-minitest", "0.5.1"
103
90
  s.add_development_dependency "rubocop-performance", "1.5.2"
104
91
  s.add_development_dependency "rubocop-rspec", "1.33.0"
92
+ s.add_development_dependency "sqlint", "0.1.10"
105
93
  s.add_development_dependency "xcop", "0.6"
106
94
  end
@@ -0,0 +1,180 @@
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 emails if recognized?(emails)
41
+ return PlainCC.new(emails) if plain?(emails)
42
+ return EmptyCC.new if undefined?(emails)
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
+ # Detect that raw CC is a string which may has plain email addresses
49
+ def plain?(text)
50
+ (text.is_a? String) && text.to_s.include?("@")
51
+ end
52
+
53
+ def recognized?(emails)
54
+ [EmptyCC, PlainCC, ComponentCC, PredefinedCC].member? emails.class
55
+ end
56
+
57
+ def undefined?(emails)
58
+ return true unless emails.key? "type"
59
+ emails["type"].nil? || emails["type"].blank?
60
+ end
61
+ end
62
+
63
+ # Array of CC addresses from text for email notification.
64
+ #
65
+ # PlainCC.new("a@f.com, , -,b@f.com").cc # ==> ["a@f.com", "b@f.com"]
66
+ #
67
+ # Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
68
+ # Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
69
+ # License:: MIT
70
+ class PlainCC
71
+ include Enumerable
72
+ extend Forwardable
73
+ def_delegators :@cc, :each
74
+
75
+ # The regexp expression for email notification is very simple, here is the
76
+ # reason why https://bit.ly/38iLKeo
77
+ def initialize(text, regxp = /[^\s]@[^\s]/)
78
+ @text = text
79
+ @regxp = regxp
80
+ end
81
+
82
+ def cc
83
+ @cc ||= begin
84
+ if @text.include? ","
85
+ @text.split(",").map(&:strip).select { |e| e[@regxp] }
86
+ elsif @text[@regxp]
87
+ [@text.strip]
88
+ end
89
+ end
90
+ end
91
+
92
+ def each(&block)
93
+ cc.each(&block)
94
+ end
95
+ end
96
+
97
+ # Empty CC email addresses.
98
+ class EmptyCC
99
+ def cc
100
+ []
101
+ end
102
+ end
103
+
104
+ # Predefined CC addresses for email notification.
105
+ # You may define a hash where
106
+ # - key is Jira ticket component
107
+ # - value is CC email address(es)
108
+ #
109
+ # Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
110
+ # Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
111
+ # License:: MIT
112
+ class PredefinedCC
113
+ def initialize(orig)
114
+ @orig = orig
115
+ end
116
+
117
+ def [](key)
118
+ to_h[key]
119
+ end
120
+
121
+ def cc(*names)
122
+ return to_h.values.flatten.uniq.compact if names.count.zero?
123
+ return self[names.first] if names.count == 1
124
+ to_h.values_at(names.first, *names.drop(1)).flatten.uniq.compact
125
+ end
126
+
127
+ def to_h
128
+ @to_h ||= begin
129
+ if @orig.is_a? Hash
130
+ @orig.each_with_object({}) do |i, o|
131
+ o[i.first] = Lazylead::PlainCC.new(i.last).cc
132
+ end
133
+ else
134
+ {}
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ # CC addresses based on Jira component owners for email notification.
141
+ # Allows to detect the CC for particular ticket based on its component.
142
+ #
143
+ # Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
144
+ # Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
145
+ # License:: MIT
146
+ class ComponentCC < Lazylead::PredefinedCC
147
+ def initialize(prj, jira)
148
+ @prj = prj
149
+ @jira = jira
150
+ end
151
+
152
+ def to_h
153
+ @to_h ||= begin
154
+ components.each_with_object({}) do |c, h|
155
+ email = lead(c.attrs["id"])
156
+ next if email.nil? || email.blank?
157
+ h[c.attrs["name"]] = email
158
+ end
159
+ end
160
+ end
161
+
162
+ private
163
+
164
+ def lead(component_id)
165
+ @jira.raw do |j|
166
+ lead = j.Component
167
+ .find(component_id, expand: "", fields: "")
168
+ .attrs["lead"]
169
+ next if lead.nil? || lead.empty?
170
+ j.User.find(lead["key"]).attrs["emailAddress"]
171
+ end
172
+ end
173
+
174
+ def components
175
+ @jira.raw do |j|
176
+ j.Project.find(@prj, expand: "components", fields: "").components
177
+ end
178
+ end
179
+ end
180
+ end
@@ -48,7 +48,7 @@ module Lazylead
48
48
 
49
49
  def run(opts)
50
50
  apply_vcs_migration opts
51
- enable_active_record
51
+ enable_active_record opts
52
52
  @smtp.enable
53
53
  schedule_tasks
54
54
  end
@@ -63,10 +63,11 @@ module Lazylead
63
63
  @log.debug "Migration applied to #{@db} from #{vcs}"
64
64
  end
65
65
 
66
- def enable_active_record
66
+ def enable_active_record(opts)
67
67
  ActiveRecord::Base.establish_connection(
68
68
  adapter: "sqlite3",
69
- database: @db
69
+ database: @db,
70
+ pool: opts[:max_connections]
70
71
  )
71
72
  @log.debug "Database connection established"
72
73
  end
@@ -61,12 +61,25 @@ module Lazylead
61
61
  body_type: "HTML",
62
62
  to_recipients: to
63
63
  }
64
- msg.update(cc_recipients: split("cc", opts)) if opts.key? "cc"
64
+ msg.update(cc_recipients: opts["cc"]) if opts.key? "cc"
65
+ add_attachments(msg, opts)
65
66
  cli.send_message msg
67
+ close_attachments msg
66
68
  @log.debug "Email was generated from #{opts} and send by #{__FILE__}. " \
67
69
  "Here is the body: #{html}"
68
70
  end
69
71
 
72
+ def add_attachments(msg, opts)
73
+ return unless opts.key? "attachments"
74
+ files = split("attachments", opts).map { |f| File.open(f, "r") }
75
+ msg[:file_attachments] = files
76
+ end
77
+
78
+ def close_attachments(msg)
79
+ return if msg[:file_attachments].nil? || msg[:file_attachments].empty?
80
+ msg[:file_attachments].each(&:close)
81
+ end
82
+
70
83
  private
71
84
 
72
85
  def cli
@@ -0,0 +1,38 @@
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 "logging"
26
+
27
+ module Lazylead
28
+ # Home directory for lazylead
29
+ #
30
+ # Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
31
+ # Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
32
+ # License:: MIT
33
+ class Home
34
+ def dir
35
+ ENV["LL_HOME"].nil? ? Dir.pwd : ENV["LL_HOME"]
36
+ end
37
+ end
38
+ end
@@ -26,6 +26,7 @@ require "active_record"
26
26
  require "require_all"
27
27
  require_rel "task"
28
28
  require_rel "system"
29
+ require_relative "cc"
29
30
  require_relative "log"
30
31
  require_relative "postman"
31
32
  require_relative "exchange"
@@ -64,7 +65,9 @@ module Lazylead
64
65
  opts.each_with_object({}) do |e, o|
65
66
  k = e[0]
66
67
  v = e[1]
67
- v = ENV[v.slice(2, v.length - 3)] if v.start_with? "${"
68
+ if v.respond_to? :start_with?
69
+ v = ENV[v.slice(2, v.length - 3)] if v.start_with? "${"
70
+ end
68
71
  o[k] = v
69
72
  end
70
73
  end
@@ -88,17 +91,36 @@ module Lazylead
88
91
  belongs_to :team, foreign_key: "team_id"
89
92
  belongs_to :system, foreign_key: "system"
90
93
 
94
+ # @todo #/DEV Add error handling for StandartError with support of
95
+ # verbose key from ARGV like in /bin/lazylead. That will make error
96
+ # messages more human readable. Maybe there is some integration between
97
+ # Slop and ARGV in order to avoid logic duplication.
91
98
  def exec(log = Log::NOTHING)
92
99
  log.debug("Task ##{id} '#{name}' is started")
93
- action.constantize
94
- .new(log)
95
- .run(system.connect(log), postman(log), props)
100
+ sys = system.connect(log)
101
+ pman = postman(log)
102
+ opts = props(log)
103
+ opts = detect_cc(sys) if opts.key? "cc"
104
+ action.constantize.new(log).run(sys, pman, opts)
96
105
  log.debug("Task ##{id} '#{name}' is completed")
97
106
  end
98
107
 
99
- def props
100
- return @prop if defined? @prop
101
- @prop = team.to_hash.merge(to_hash)
108
+ def detect_cc(sys)
109
+ opts = props
110
+ opts["cc"] = CC.new.detect(opts["cc"], sys)
111
+ return opts.except "cc" if opts["cc"].is_a? EmptyCC
112
+ opts
113
+ end
114
+
115
+ def props(log = Log::NOTHING)
116
+ @props ||= begin
117
+ if team.nil?
118
+ log.warn("Team for task #{id} isn't defined.")
119
+ env(to_hash)
120
+ else
121
+ env(team.to_hash.merge(to_hash))
122
+ end
123
+ end
102
124
  end
103
125
 
104
126
  def postman(log = Log::NOTHING)