tomo 0.18.0 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -2
  3. data/lib/tomo/cli.rb +1 -3
  4. data/lib/tomo/cli/common_options.rb +4 -12
  5. data/lib/tomo/cli/deploy_options.rb +2 -7
  6. data/lib/tomo/cli/parser.rb +1 -6
  7. data/lib/tomo/cli/project_options.rb +1 -3
  8. data/lib/tomo/cli/rules.rb +4 -22
  9. data/lib/tomo/cli/rules/switch.rb +1 -5
  10. data/lib/tomo/cli/rules/value_switch.rb +1 -2
  11. data/lib/tomo/cli/rules_evaluator.rb +3 -13
  12. data/lib/tomo/cli/usage.rb +1 -3
  13. data/lib/tomo/commands/default.rb +1 -5
  14. data/lib/tomo/commands/run.rb +1 -3
  15. data/lib/tomo/configuration.rb +5 -11
  16. data/lib/tomo/configuration/dsl/error_formatter.rb +0 -4
  17. data/lib/tomo/configuration/dsl/hosts_and_settings.rb +1 -2
  18. data/lib/tomo/configuration/plugins_registry.rb +1 -2
  19. data/lib/tomo/configuration/unknown_environment_error.rb +1 -4
  20. data/lib/tomo/console.rb +2 -8
  21. data/lib/tomo/console/menu.rb +1 -2
  22. data/lib/tomo/host.rb +1 -2
  23. data/lib/tomo/plugin/bundler/tasks.rb +8 -8
  24. data/lib/tomo/plugin/core/tasks.rb +3 -16
  25. data/lib/tomo/plugin/env/tasks.rb +2 -7
  26. data/lib/tomo/plugin/git.rb +0 -3
  27. data/lib/tomo/plugin/git/tasks.rb +4 -16
  28. data/lib/tomo/plugin/nodenv/tasks.rb +1 -3
  29. data/lib/tomo/plugin/puma.rb +0 -3
  30. data/lib/tomo/plugin/puma/systemd/service.erb +1 -1
  31. data/lib/tomo/plugin/puma/tasks.rb +6 -15
  32. data/lib/tomo/plugin/rails/helpers.rb +1 -1
  33. data/lib/tomo/plugin/rails/tasks.rb +2 -4
  34. data/lib/tomo/plugin/testing.rb +1 -3
  35. data/lib/tomo/remote.rb +1 -3
  36. data/lib/tomo/runtime.rb +3 -6
  37. data/lib/tomo/runtime/concurrent_ruby_thread_pool.rb +1 -4
  38. data/lib/tomo/runtime/execution_plan.rb +1 -4
  39. data/lib/tomo/runtime/explanation.rb +1 -7
  40. data/lib/tomo/runtime/settings_interpolation.rb +1 -3
  41. data/lib/tomo/runtime/settings_required_error.rb +1 -3
  42. data/lib/tomo/runtime/task_runner.rb +2 -7
  43. data/lib/tomo/runtime/unknown_task_error.rb +1 -4
  44. data/lib/tomo/script.rb +1 -5
  45. data/lib/tomo/shell_builder.rb +5 -10
  46. data/lib/tomo/ssh/child_process.rb +6 -13
  47. data/lib/tomo/ssh/connection.rb +3 -16
  48. data/lib/tomo/ssh/connection_validator.rb +1 -4
  49. data/lib/tomo/ssh/executable_error.rb +1 -2
  50. data/lib/tomo/ssh/options.rb +2 -5
  51. data/lib/tomo/task_api.rb +4 -15
  52. data/lib/tomo/testing.rb +0 -2
  53. data/lib/tomo/testing/Dockerfile +1 -3
  54. data/lib/tomo/testing/connection.rb +1 -6
  55. data/lib/tomo/testing/docker_image.rb +4 -17
  56. data/lib/tomo/testing/local.rb +1 -3
  57. data/lib/tomo/testing/mock_plugin_tester.rb +27 -4
  58. data/lib/tomo/testing/mocked_exit_error.rb +1 -1
  59. data/lib/tomo/testing/ubuntu_setup.sh +1 -2
  60. data/lib/tomo/version.rb +1 -1
  61. metadata +13 -29
  62. data/lib/tomo/testing/docker_plugin_tester.rb +0 -39
  63. data/lib/tomo/testing/plugin_tester.rb +0 -33
@@ -6,7 +6,6 @@ module Tomo::Plugin::Core
6
6
  RELEASE_REGEXP = /\d{14}/.freeze
7
7
  private_constant :RELEASE_REGEXP
8
8
 
9
- # rubocop:disable Metrics/AbcSize
10
9
  def setup_directories
11
10
  dirs = [
12
11
  paths.deploy_to,
@@ -18,7 +17,6 @@ module Tomo::Plugin::Core
18
17
 
19
18
  remote.mkdir_p(*dirs)
20
19
  end
21
- # rubocop:enable Metrics/AbcSize
22
20
 
23
21
  def symlink_shared
24
22
  return if linked_dirs.empty? && linked_files.empty?
@@ -36,8 +34,7 @@ module Tomo::Plugin::Core
36
34
  remote.run "mv", "-fT", tmp_link, paths.current
37
35
  end
38
36
 
39
- # rubocop:disable Metrics/AbcSize
40
- def clean_releases
37
+ def clean_releases # rubocop:disable Metrics/AbcSize
41
38
  desired_count = settings[:keep_releases].to_i
42
39
  return if desired_count < 1
43
40
 
@@ -51,15 +48,13 @@ module Tomo::Plugin::Core
51
48
  remote.rm_rf(*releases.take(releases.length - desired_count))
52
49
  end
53
50
  end
54
- # rubocop:enable Metrics/AbcSize
55
51
 
56
52
  def write_release_json
57
53
  json = JSON.pretty_generate(remote.release)
58
54
  remote.write(text: "#{json}\n", to: paths.release_json)
59
55
  end
60
56
 
61
- # rubocop:disable Metrics/AbcSize
62
- def log_revision
57
+ def log_revision # rubocop:disable Metrics/AbcSize
63
58
  ref = remote.release[:ref]
64
59
  revision = remote.release[:revision]
65
60
 
@@ -71,7 +66,6 @@ module Tomo::Plugin::Core
71
66
 
72
67
  remote.write(text: message, to: paths.revision_log, append: true)
73
68
  end
74
- # rubocop:enable Metrics/AbcSize
75
69
 
76
70
  private
77
71
 
@@ -83,7 +77,6 @@ module Tomo::Plugin::Core
83
77
  settings[:linked_files] || []
84
78
  end
85
79
 
86
- # rubocop:disable Metrics/AbcSize
87
80
  def shared_directories
88
81
  result = linked_dirs.map { |name| paths.shared.join(name) }
89
82
  linked_files.each do |name|
@@ -91,7 +84,6 @@ module Tomo::Plugin::Core
91
84
  end
92
85
  result.map(&:to_s).uniq - [paths.shared.to_s]
93
86
  end
94
- # rubocop:enable Metrics/AbcSize
95
87
 
96
88
  def symlink_shared_files
97
89
  return if linked_files.empty?
@@ -127,12 +119,7 @@ module Tomo::Plugin::Core
127
119
  end
128
120
 
129
121
  def read_current_release
130
- result = remote.run(
131
- "readlink",
132
- paths.current,
133
- raise_on_error: false,
134
- silent: true
135
- )
122
+ result = remote.run("readlink", paths.current, raise_on_error: false, silent: true)
136
123
  return nil if result.failure?
137
124
 
138
125
  result.stdout.strip[%r{/(#{RELEASE_REGEXP})$}, 1]
@@ -14,7 +14,6 @@ module Tomo::Plugin::Env
14
14
  modify_bashrc
15
15
  end
16
16
 
17
- # rubocop:disable Metrics/MethodLength
18
17
  def update
19
18
  return if settings[:env_vars].empty?
20
19
 
@@ -30,7 +29,6 @@ module Tomo::Plugin::Env
30
29
  end
31
30
  end
32
31
  end
33
- # rubocop:enable Metrics/MethodLength
34
32
 
35
33
  def set
36
34
  return if settings[:run_args].empty?
@@ -67,10 +65,7 @@ module Tomo::Plugin::Env
67
65
  end
68
66
 
69
67
  def read_existing
70
- remote.capture(
71
- "cat", paths.env,
72
- raise_on_error: false, echo: false, silent: true
73
- )
68
+ remote.capture("cat", paths.env, raise_on_error: false, echo: false, silent: true)
74
69
  end
75
70
 
76
71
  def replace_entry(text, name, value)
@@ -84,7 +79,7 @@ module Tomo::Plugin::Env
84
79
 
85
80
  def prepend_entry(text, name, value)
86
81
  text.prepend("\n") unless text.start_with?("\n")
87
- text.prepend("export #{name.to_s.shellescape}=#{value.shellescape}")
82
+ text.prepend("export #{name.to_s.shellescape}=#{value.to_s.shellescape}")
88
83
  end
89
84
 
90
85
  def contains_entry?(text, name)
@@ -7,14 +7,11 @@ module Tomo::Plugin
7
7
 
8
8
  helpers Tomo::Plugin::Git::Helpers
9
9
  tasks Tomo::Plugin::Git::Tasks
10
-
11
- # rubocop:disable Layout/LineLength
12
10
  defaults git_branch: "master",
13
11
  git_repo_path: "%{deploy_to}/git_repo",
14
12
  git_exclusions: [],
15
13
  git_env: { GIT_SSH_COMMAND: "ssh -o PasswordAuthentication=no -o StrictHostKeyChecking=no" },
16
14
  git_ref: nil,
17
15
  git_url: nil
18
- # rubocop:enable Layout/LineLength
19
16
  end
20
17
  end
@@ -3,7 +3,6 @@ require "time"
3
3
 
4
4
  module Tomo::Plugin::Git
5
5
  class Tasks < Tomo::TaskLibrary
6
- # rubocop:disable Metrics/AbcSize
7
6
  def clone
8
7
  require_setting :git_url
9
8
 
@@ -15,8 +14,7 @@ module Tomo::Plugin::Git
15
14
  end
16
15
  end
17
16
 
18
- # rubocop:disable Metrics/MethodLength
19
- def create_release
17
+ def create_release # rubocop:disable Metrics/AbcSize
20
18
  remote.chdir(paths.git_repo) do
21
19
  remote.git("remote update --prune")
22
20
  end
@@ -32,8 +30,6 @@ module Tomo::Plugin::Git
32
30
  )
33
31
  end
34
32
  end
35
- # rubocop:enable Metrics/MethodLength
36
- # rubocop:enable Metrics/AbcSize
37
33
 
38
34
  private
39
35
 
@@ -66,19 +62,13 @@ module Tomo::Plugin::Git
66
62
  exclusions = settings[:git_exclusions] || []
67
63
  attributes = exclusions.map { |excl| "#{excl} export-ignore" }.join("\n")
68
64
 
69
- remote.write(
70
- text: attributes,
71
- to: paths.git_repo.join("info/attributes")
72
- )
65
+ remote.write(text: attributes, to: paths.git_repo.join("info/attributes"))
73
66
  end
74
67
 
75
- # rubocop:disable Metrics/AbcSize
76
- # rubocop:disable Metrics/MethodLength
77
- def store_release_info
68
+ def store_release_info # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
78
69
  log = remote.chdir(paths.git_repo) do
79
70
  remote.git(
80
- 'log -n1 --date=iso --pretty=format:"%H/%cd/%ae" '\
81
- "#{ref.shellescape} --",
71
+ %Q(log -n1 --date=iso --pretty=format:"%H/%cd/%ae" #{ref.shellescape} --),
82
72
  silent: true
83
73
  ).stdout.strip
84
74
  end
@@ -92,7 +82,5 @@ module Tomo::Plugin::Git
92
82
  remote.release[:deploy_date] = Time.now.to_s
93
83
  remote.release[:deploy_user] = settings.fetch(:local_user)
94
84
  end
95
- # rubocop:enable Metrics/MethodLength
96
- # rubocop:enable Metrics/AbcSize
97
85
  end
98
86
  end
@@ -34,9 +34,7 @@ module Tomo::Plugin::Nodenv
34
34
  require_setting :nodenv_node_version
35
35
  node_version = settings[:nodenv_node_version]
36
36
 
37
- unless node_installed?(node_version)
38
- remote.run "nodenv install #{node_version.shellescape}"
39
- end
37
+ remote.run "nodenv install #{node_version.shellescape}" unless node_installed?(node_version)
40
38
  remote.run "nodenv global #{node_version.shellescape}"
41
39
  end
42
40
 
@@ -5,8 +5,6 @@ module Tomo::Plugin
5
5
  extend Tomo::PluginDSL
6
6
 
7
7
  tasks Tomo::Plugin::Puma::Tasks
8
-
9
- # rubocop:disable Layout/LineLength
10
8
  defaults puma_check_timeout: 15,
11
9
  puma_host: "0.0.0.0",
12
10
  puma_port: "3000",
@@ -16,6 +14,5 @@ module Tomo::Plugin
16
14
  puma_systemd_socket_path: ".config/systemd/user/%{puma_systemd_socket}",
17
15
  puma_systemd_service_template_path: File.expand_path("puma/systemd/service.erb", __dir__),
18
16
  puma_systemd_socket_template_path: File.expand_path("puma/systemd/socket.erb", __dir__)
19
- # rubocop:enable Layout/LineLength
20
17
  end
21
18
  end
@@ -19,4 +19,4 @@ WorkingDirectory=<%= paths.current %>
19
19
  # Environment=PUMA_DEBUG=1
20
20
 
21
21
  [Install]
22
- WantedBy=multi-user.target
22
+ WantedBy=default.target
@@ -2,8 +2,7 @@ module Tomo::Plugin::Puma
2
2
  class Tasks < Tomo::TaskLibrary
3
3
  SystemdUnit = Struct.new(:name, :template, :path)
4
4
 
5
- # rubocop:disable Metrics/AbcSize
6
- def setup_systemd
5
+ def setup_systemd # rubocop:disable Metrics/AbcSize
7
6
  linger_must_be_enabled!
8
7
 
9
8
  setup_directories
@@ -13,7 +12,6 @@ module Tomo::Plugin::Puma
13
12
  remote.run "systemctl --user daemon-reload"
14
13
  remote.run "systemctl", "--user", "enable", service.name, socket.name
15
14
  end
16
- # rubocop:enable Metrics/AbcSize
17
15
 
18
16
  %i[start stop status].each do |action|
19
17
  define_method(action) do
@@ -37,9 +35,7 @@ module Tomo::Plugin::Puma
37
35
  end
38
36
 
39
37
  def log
40
- remote.attach "journalctl", "-q",
41
- raw("--user-unit=#{service.name.shellescape}"),
42
- *settings[:run_args]
38
+ remote.attach "journalctl", "-q", raw("--user-unit=#{service.name.shellescape}"), *settings[:run_args]
43
39
  end
44
40
 
45
41
  private
@@ -102,22 +98,17 @@ module Tomo::Plugin::Puma
102
98
  end
103
99
 
104
100
  def assert_active!
105
- return true if remote.run? "systemctl", "--user", "is-active",
106
- service.name,
107
- silent: true, raise_on_error: false
101
+ return true if remote.run? "systemctl", "--user", "is-active", service.name, silent: true, raise_on_error: false
108
102
 
109
- remote.run "systemctl", "--user", "status", service.name,
110
- raise_on_error: false
111
- remote.run "journalctl -q -n 50 --user-unit=#{service.name.shellescape}",
112
- raise_on_error: false
103
+ remote.run "systemctl", "--user", "status", service.name, raise_on_error: false
104
+ remote.run "journalctl -q -n 50 --user-unit=#{service.name.shellescape}", raise_on_error: false
113
105
 
114
106
  die "puma failed to start (see previous systemctl and journalctl output)"
115
107
  end
116
108
 
117
109
  def listening?
118
110
  test_url = "http://localhost:#{port}"
119
- remote.run? "curl -sS --connect-timeout 1 --max-time 10 #{test_url}"\
120
- " > /dev/null"
111
+ remote.run? "curl -sS --connect-timeout 1 --max-time 10 #{test_url} > /dev/null"
121
112
  end
122
113
  end
123
114
  end
@@ -7,7 +7,7 @@ module Tomo::Plugin::Rails
7
7
  end
8
8
 
9
9
  def rake(*args, **opts)
10
- prepend("exec", "rails") do
10
+ prepend("exec", "rake") do
11
11
  bundle(*args, **opts)
12
12
  end
13
13
  end
@@ -40,11 +40,9 @@ module Tomo::Plugin::Rails
40
40
 
41
41
  def db_structure_load
42
42
  if !structure_sql_present?
43
- logger.warn "db/structure.sql is not present; "\
44
- "skipping db:structure:load."
43
+ logger.warn "db/structure.sql is not present; skipping db:structure:load."
45
44
  elsif database_schema_loaded?
46
- logger.info "Database structure already loaded; "\
47
- "skipping db:structure:load."
45
+ logger.info "Database structure already loaded; skipping db:structure:load."
48
46
  else
49
47
  remote.rake("db:structure:load")
50
48
  end
@@ -1,6 +1,4 @@
1
- unless defined?(Tomo::Testing)
2
- raise "The testing plugin cannot be used outside of unit tests"
3
- end
1
+ raise "The testing plugin cannot be used outside of unit tests" unless defined?(Tomo::Testing)
4
2
 
5
3
  module Tomo::Plugin
6
4
  class Testing < Tomo::TaskLibrary
@@ -21,9 +21,7 @@ module Tomo
21
21
 
22
22
  def attach(*command, default_chdir: nil, **command_opts)
23
23
  full_command = shell_builder.build(*command, default_chdir: default_chdir)
24
- ssh.ssh_exec(
25
- Script.new(full_command, **{ pty: true }.merge(command_opts))
26
- )
24
+ ssh.ssh_exec(Script.new(full_command, **{ pty: true }.merge(command_opts)))
27
25
  end
28
26
 
29
27
  def run(*command, attach: false, default_chdir: nil, **command_opts)
@@ -3,8 +3,7 @@ require "time"
3
3
  module Tomo
4
4
  class Runtime
5
5
  autoload :ConcurrentRubyLoadError, "tomo/runtime/concurrent_ruby_load_error"
6
- autoload :ConcurrentRubyThreadPool,
7
- "tomo/runtime/concurrent_ruby_thread_pool"
6
+ autoload :ConcurrentRubyThreadPool, "tomo/runtime/concurrent_ruby_thread_pool"
8
7
  autoload :Context, "tomo/runtime/context"
9
8
  autoload :Current, "tomo/runtime/current"
10
9
  autoload :ExecutionPlan, "tomo/runtime/execution_plan"
@@ -28,8 +27,7 @@ module Tomo
28
27
 
29
28
  attr_reader :tasks
30
29
 
31
- def initialize(deploy_tasks:, setup_tasks:, hosts:, task_filter:,
32
- settings:, plugins_registry:)
30
+ def initialize(deploy_tasks:, setup_tasks:, hosts:, task_filter:, settings:, plugins_registry:)
33
31
  @deploy_tasks = deploy_tasks.freeze
34
32
  @setup_tasks = setup_tasks.freeze
35
33
  @hosts = hosts.freeze
@@ -68,8 +66,7 @@ module Tomo
68
66
 
69
67
  private
70
68
 
71
- attr_reader :deploy_tasks, :setup_tasks, :hosts, :task_filter, :settings,
72
- :plugins_registry
69
+ attr_reader :deploy_tasks, :setup_tasks, :hosts, :task_filter, :settings, :plugins_registry
73
70
 
74
71
  def new_task_runner(release_type, args)
75
72
  run_settings = { release_path: release_path_for(release_type) }
@@ -4,10 +4,7 @@ begin
4
4
  gem "concurrent-ruby", concurrent_ver
5
5
  require "concurrent"
6
6
  rescue LoadError => e
7
- Tomo::Runtime::ConcurrentRubyLoadError.raise_with(
8
- e.message,
9
- version: concurrent_ver
10
- )
7
+ Tomo::Runtime::ConcurrentRubyLoadError.raise_with(e.message, version: concurrent_ver)
11
8
  end
12
9
 
13
10
  module Tomo
@@ -77,10 +77,7 @@ module Tomo
77
77
  def build_plan(tasks, task_filter)
78
78
  tasks.each_with_object([]) do |task, result|
79
79
  steps = hosts.map do |host|
80
- HostExecutionStep.new(
81
- tasks: task, host: host,
82
- task_filter: task_filter, task_runner: task_runner
83
- )
80
+ HostExecutionStep.new(tasks: task, host: host, task_filter: task_filter, task_runner: task_runner)
84
81
  end
85
82
  steps.reject!(&:empty?)
86
83
  result << steps unless steps.empty?
@@ -7,10 +7,7 @@ module Tomo
7
7
  @concurrency = concurrency
8
8
  end
9
9
 
10
- # rubocop:disable Metrics/MethodLength
11
- # rubocop:disable Metrics/AbcSize
12
- # rubocop:disable Metrics/CyclomaticComplexity
13
- def to_s
10
+ def to_s # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
14
11
  desc = []
15
12
  threads = [applicable_hosts.length, concurrency].min
16
13
  desc << "CONCURRENTLY (#{threads} THREADS):" if threads > 1
@@ -32,9 +29,6 @@ module Tomo
32
29
  end
33
30
  desc.join("\n")
34
31
  end
35
- # rubocop:enable Metrics/MethodLength
36
- # rubocop:enable Metrics/AbcSize
37
- # rubocop:enable Metrics/CyclomaticComplexity
38
32
 
39
33
  private
40
34
 
@@ -35,9 +35,7 @@ module Tomo
35
35
  end
36
36
 
37
37
  def symbolize(hash)
38
- hash.each_with_object({}) do |(key, value), symbolized|
39
- symbolized[key.to_sym] = value
40
- end
38
+ hash.transform_keys(&:to_sym)
41
39
  end
42
40
 
43
41
  def dump_settings(hash)
@@ -21,9 +21,7 @@ module Tomo
21
21
  private
22
22
 
23
23
  def settings_sentence
24
- if settings.length == 1
25
- return "a value for the #{yellow(settings.first.to_s)} setting."
26
- end
24
+ return "a value for the #{yellow(settings.first.to_s)} setting." if settings.length == 1
27
25
 
28
26
  sentence = "values for these settings:\n\n "
29
27
  sentence << settings.map { |s| yellow(s.to_s) }.join("\n ")
@@ -19,11 +19,7 @@ module Tomo
19
19
  def validate_task!(name)
20
20
  return if tasks_by_name.key?(name)
21
21
 
22
- UnknownTaskError.raise_with(
23
- name,
24
- unknown_task: name,
25
- known_tasks: tasks_by_name.keys
26
- )
22
+ UnknownTaskError.raise_with(name, unknown_task: name, known_tasks: tasks_by_name.keys)
27
23
  end
28
24
 
29
25
  def run(task:, remote:)
@@ -53,8 +49,7 @@ module Tomo
53
49
  attr_reader :helper_modules, :tasks_by_name
54
50
 
55
51
  def ssh_options
56
- # TODO: replace with Hash#slice after dropping Ruby 2.4 support
57
- settings.select { |key| SSH::Options::DEFAULTS.key?(key) }
52
+ settings.slice(*SSH::Options::DEFAULTS.keys)
58
53
  end
59
54
  end
60
55
  end
@@ -17,10 +17,7 @@ module Tomo
17
17
  private
18
18
 
19
19
  def spelling_suggestion
20
- sugg = Error::Suggestions.new(
21
- dictionary: known_tasks,
22
- word: unknown_task
23
- )
20
+ sugg = Error::Suggestions.new(dictionary: known_tasks, word: unknown_task)
24
21
  sugg.to_console if sugg.any?
25
22
  end
26
23