avm-tools 0.45.0 → 0.50.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/lib/avm/git/issue/complete.rb +1 -1
  3. data/lib/avm/git/issue/complete/_test.rb +16 -2
  4. data/lib/avm/git/issue/complete/_validations.rb +9 -14
  5. data/lib/avm/git/issue/complete/validation.rb +31 -0
  6. data/lib/avm/git/revision_test.rb +2 -2
  7. data/lib/avm/instances/configuration/_tests.rb +14 -0
  8. data/lib/avm/rails.rb +9 -0
  9. data/lib/avm/rails/runners.rb +11 -0
  10. data/lib/avm/rails/runners/bundle.rb +35 -0
  11. data/lib/avm/rails/runners/runner.rb +48 -0
  12. data/lib/avm/ruby.rb +0 -20
  13. data/lib/avm/stereotypes/eac_redmine_base0/deploy.rb +2 -2
  14. data/lib/avm/stereotypes/eac_webapp_base0/instance.rb +3 -3
  15. data/lib/avm/tools/runner/eac_rails_base0/bundle.rb +14 -0
  16. data/lib/avm/tools/runner/eac_rails_base0/runner.rb +14 -0
  17. data/lib/avm/tools/runner/eac_redmine_base0/bundle.rb +2 -24
  18. data/lib/avm/tools/runner/eac_redmine_base0/runner.rb +14 -0
  19. data/lib/avm/tools/runner/files/format.rb +1 -1
  20. data/lib/avm/tools/runner/git.rb +1 -1
  21. data/lib/avm/tools/runner/launcher.rb +12 -0
  22. data/lib/avm/tools/version.rb +1 -1
  23. data/lib/eac_launcher.rb +17 -0
  24. data/lib/eac_launcher/context.rb +81 -0
  25. data/lib/eac_launcher/context/instance_discovery.rb +54 -0
  26. data/lib/eac_launcher/context/instance_manager.rb +94 -0
  27. data/lib/eac_launcher/context/settings.rb +51 -0
  28. data/lib/eac_launcher/git.rb +7 -0
  29. data/lib/eac_launcher/git/base.rb +100 -0
  30. data/lib/eac_launcher/git/base/class_methods.rb +26 -0
  31. data/lib/eac_launcher/git/base/dirty_files.rb +30 -0
  32. data/lib/eac_launcher/git/base/remotes.rb +38 -0
  33. data/lib/eac_launcher/git/base/subrepo.rb +42 -0
  34. data/lib/eac_launcher/git/base/underlying.rb +59 -0
  35. data/lib/eac_launcher/git/error.rb +11 -0
  36. data/lib/eac_launcher/git/mirror_update.rb +36 -0
  37. data/lib/eac_launcher/git/publish_base.rb +118 -0
  38. data/lib/eac_launcher/git/remote.rb +53 -0
  39. data/lib/eac_launcher/git/sub_warp_base.rb +30 -0
  40. data/lib/eac_launcher/git/warp_base.rb +54 -0
  41. data/lib/eac_launcher/instances.rb +6 -0
  42. data/lib/eac_launcher/instances/base.rb +91 -0
  43. data/lib/eac_launcher/instances/base/cache.rb +41 -0
  44. data/lib/eac_launcher/instances/error.rb +8 -0
  45. data/lib/eac_launcher/instances/runner_helper.rb +42 -0
  46. data/lib/eac_launcher/instances/settings.rb +23 -0
  47. data/lib/eac_launcher/paths.rb +4 -0
  48. data/lib/eac_launcher/paths/logical.rb +80 -0
  49. data/lib/eac_launcher/paths/real.rb +42 -0
  50. data/lib/eac_launcher/project.rb +16 -0
  51. data/lib/eac_launcher/publish.rb +4 -0
  52. data/lib/eac_launcher/publish/base.rb +45 -0
  53. data/lib/eac_launcher/publish/check_result.rb +65 -0
  54. data/lib/eac_launcher/ruby.rb +3 -0
  55. data/lib/eac_launcher/ruby/gem.rb +4 -0
  56. data/lib/eac_launcher/ruby/gem/build.rb +123 -0
  57. data/lib/eac_launcher/ruby/gem/specification.rb +61 -0
  58. data/lib/eac_launcher/runner.rb +21 -0
  59. data/lib/eac_launcher/runner/instances.rb +41 -0
  60. data/lib/eac_launcher/runner/projects.rb +46 -0
  61. data/lib/eac_launcher/runner/publish.rb +59 -0
  62. data/lib/eac_launcher/stereotype.rb +52 -0
  63. data/lib/eac_launcher/stereotypes.rb +14 -0
  64. data/lib/eac_launcher/stereotypes/git.rb +21 -0
  65. data/lib/eac_launcher/stereotypes/git/publish.rb +13 -0
  66. data/lib/eac_launcher/stereotypes/git/warp.rb +25 -0
  67. data/lib/eac_launcher/stereotypes/git_subrepo.rb +30 -0
  68. data/lib/eac_launcher/stereotypes/git_subrepo/publish.rb +12 -0
  69. data/lib/eac_launcher/stereotypes/git_subrepo/warp.rb +85 -0
  70. data/lib/eac_launcher/stereotypes/git_subtree.rb +47 -0
  71. data/lib/eac_launcher/stereotypes/git_subtree/publish.rb +10 -0
  72. data/lib/eac_launcher/stereotypes/git_subtree/warp.rb +27 -0
  73. data/lib/eac_launcher/stereotypes/rails.rb +21 -0
  74. data/lib/eac_launcher/stereotypes/redmine_plugin.rb +21 -0
  75. data/lib/eac_launcher/stereotypes/ruby_gem.rb +27 -0
  76. data/lib/eac_launcher/stereotypes/ruby_gem/publish.rb +127 -0
  77. data/lib/eac_launcher/vendor.rb +3 -0
  78. data/lib/eac_launcher/vendor/github.rb +18 -0
  79. data/lib/eac_launcher/version.rb +5 -0
  80. metadata +122 -9
  81. data/lib/avm/patches/eac_launcher_git_base.rb +0 -77
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'eac_ruby_utils/console/docopt_runner'
4
4
  require 'eac_ruby_utils/require_sub'
5
- require 'avm/patches/eac_launcher_git_base'
5
+ require 'eac_launcher/git/base'
6
6
  ::EacRubyUtils.require_sub(__FILE__)
7
7
 
8
8
  module Avm
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_launcher/runner'
4
+
5
+ module Avm
6
+ module Tools
7
+ class Runner < ::EacRubyUtils::Console::DocoptRunner
8
+ class Launcher < ::EacLauncher::Runner
9
+ end
10
+ end
11
+ end
12
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Avm
4
4
  module Tools
5
- VERSION = '0.45.0'
5
+ VERSION = '0.50.0'
6
6
  end
7
7
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ GIT_SUBREPO_LIB = ::File.join(::File.dirname(__dir__), 'vendor', 'git-subrepo', 'lib')
4
+ ENV['PATH'] = "#{GIT_SUBREPO_LIB}#{::File::PATH_SEPARATOR}#{ENV['PATH']}"
5
+
6
+ module EacLauncher
7
+ require 'eac_launcher/context'
8
+ require 'eac_launcher/paths'
9
+ require 'eac_launcher/project'
10
+ require 'eac_launcher/stereotype'
11
+ require 'eac_launcher/git'
12
+ require 'eac_launcher/instances'
13
+ require 'eac_launcher/publish'
14
+ require 'eac_launcher/ruby'
15
+ require 'eac_launcher/stereotypes'
16
+ require 'eac_launcher/vendor'
17
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/hash/indifferent_access'
4
+ require 'eac_ruby_utils/simple_cache'
5
+ require 'eac_ruby_utils/console/speaker'
6
+ require 'eac_launcher/context/instance_discovery'
7
+ require 'eac_launcher/context/instance_manager'
8
+ require 'eac_launcher/context/settings'
9
+ require 'eac_launcher/paths/logical'
10
+ require 'eac_launcher/project'
11
+
12
+ module EacLauncher
13
+ class Context
14
+ include ::EacRubyUtils::SimpleCache
15
+ include ::EacRubyUtils::Console::Speaker
16
+
17
+ DEFAULT_PROJECTS_ROOT = '.'
18
+ DEFAULT_SETTINGS_FILE = ::File.join(ENV['HOME'], '.config', 'eac_launcher', 'settings.yml')
19
+ DEFAULT_CACHE_ROOT = ::File.join(ENV['HOME'], '.cache', 'eac_launcher')
20
+
21
+ class << self
22
+ attr_writer :current
23
+
24
+ def current
25
+ @current ||= default
26
+ end
27
+
28
+ def default
29
+ @default ||= Context.new
30
+ end
31
+ end
32
+
33
+ attr_reader :root, :settings, :cache_root
34
+ attr_accessor :publish_options, :recache, :instance_manager
35
+
36
+ def initialize(options = {})
37
+ @options = options.with_indifferent_access
38
+ @root = ::EacLauncher::Paths::Logical.new(self, nil, build_option(:projects_root), '/')
39
+ @settings = ::EacLauncher::Context::Settings.new(build_option(:settings_file))
40
+ @cache_root = build_option(:cache_root)
41
+ @publish_options = { new: false, confirm: false, stereotype: nil }
42
+ @instance_manager = ::EacLauncher::Context::InstanceManager.new(self)
43
+ @recache = false
44
+ end
45
+
46
+ def instance(name)
47
+ instances.find { |i| i.name == name }
48
+ end
49
+
50
+ def instances
51
+ @instance_manager.instances
52
+ end
53
+
54
+ def pending_instances
55
+ @instance_manager.pending_instances
56
+ end
57
+
58
+ private
59
+
60
+ def build_option(key)
61
+ @options[key] || env_option(key) || default_option(key)
62
+ end
63
+
64
+ def env_option(key)
65
+ ENV["EAC_LAUNCHER_#{key}".underscore.upcase]
66
+ end
67
+
68
+ def default_option(key)
69
+ self.class.const_get("DEFAULT_#{key}".underscore.upcase)
70
+ end
71
+
72
+ def projects_uncached
73
+ r = {}
74
+ instances.each do |i|
75
+ r[i.project_name] ||= []
76
+ r[i.project_name] << i
77
+ end
78
+ r.map { |name, instances| ::EacLauncher::Project.new(name, instances) }
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ruby-progressbar'
4
+ require 'eac_launcher/instances/base'
5
+
6
+ module EacLauncher
7
+ class Context
8
+ class InstanceDiscovery
9
+ attr_reader :instances
10
+
11
+ def initialize(context)
12
+ @context = context
13
+ @progress = ::ProgressBar.create(title: 'Instance discovery', total: 1)
14
+ @instances = path_instances(@context.root, nil)
15
+ ensure
16
+ @progress&.finish
17
+ end
18
+
19
+ private
20
+
21
+ def path_instances(path, parent_instance)
22
+ update_progress_format(path)
23
+ on_rescued_path_instances(path) do |r|
24
+ if path.project?
25
+ parent_instance = ::EacLauncher::Instances::Base.instanciate(path, parent_instance)
26
+ r << path
27
+ end
28
+ children = path.children
29
+ update_progress_count(children)
30
+ r.concat(children.flat_map { |c| path_instances(c, parent_instance) })
31
+ end
32
+ end
33
+
34
+ def on_rescued_path_instances(path)
35
+ r = []
36
+ begin
37
+ yield(r) if path.included?
38
+ rescue StandardError => e
39
+ warn("#{path}: #{e}")
40
+ end
41
+ r
42
+ end
43
+
44
+ def update_progress_format(path)
45
+ @progress.format = "%t (Paths: %c/%C, Current: #{path.logical}) |%B| %a"
46
+ end
47
+
48
+ def update_progress_count(children)
49
+ @progress.total += children.count
50
+ @progress.increment
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('yaml')
4
+
5
+ module EacLauncher
6
+ class Context
7
+ class InstanceManager
8
+ include ::EacRubyUtils::SimpleCache
9
+
10
+ def initialize(context)
11
+ @context = context
12
+ end
13
+
14
+ def publish_state_set(instance, stereotype_name, check_status)
15
+ data = cached_instances_file_content_uncached
16
+ data[instance.logical] ||= {}
17
+ data[instance.logical][:publish_state] ||= {}
18
+ data[instance.logical][:publish_state][stereotype_name] = check_status
19
+ write_cache_file(data)
20
+ end
21
+
22
+ def pending_instances
23
+ instances.select { |instance| pending_instance?(instance) }
24
+ end
25
+
26
+ private
27
+
28
+ def instances_uncached
29
+ (cached_instances || search_instances).select(&:included?)
30
+ end
31
+
32
+ def search_instances
33
+ cache_instances(::EacLauncher::Context::InstanceDiscovery.new(@context).instances)
34
+ end
35
+
36
+ def cached_instances
37
+ return nil if @context.recache
38
+ return nil unless cached_instances_file_content
39
+
40
+ CachedInstances.new(cached_instances_file_content).instances
41
+ end
42
+
43
+ def cached_instances_file_content_uncached
44
+ r = YAML.load_file(cache_file_path)
45
+ r.is_a?(::Hash) ? r : nil
46
+ rescue Errno::ENOENT
47
+ nil
48
+ end
49
+
50
+ def cache_instances(instances)
51
+ write_cache_file(Hash[instances.map { |i| [i.logical, i.to_h] }])
52
+ instances
53
+ end
54
+
55
+ def write_cache_file(data)
56
+ ::File.write(cache_file_path, data.to_yaml)
57
+ end
58
+
59
+ def cache_file_path
60
+ ::File.join(@context.cache_root, 'instances.yml')
61
+ end
62
+
63
+ def pending_instance?(instance)
64
+ data = cached_instances_file_content
65
+ return false unless data[instance.logical]
66
+ return false unless data[instance.logical][:publish_state].is_a?(Hash)
67
+
68
+ data[instance.logical][:publish_state].any? do |_k, v|
69
+ ::EacLauncher::Publish::CheckResult.pending_status?(v)
70
+ end
71
+ end
72
+
73
+ class CachedInstances
74
+ def initialize(content)
75
+ @content = content
76
+ @instances = {}
77
+ end
78
+
79
+ def instances
80
+ @content.keys.map { |k| by_logical_path(k) }
81
+ end
82
+
83
+ def by_logical_path(key)
84
+ return @instances[key] if @instances.key?(key)
85
+
86
+ h = @content[key]
87
+ parent_instance = h[:parent] ? by_logical_path(h[:parent]) : nil
88
+ path = ::EacLauncher::Paths::Logical.from_h(@context, h)
89
+ @instances[key] = ::EacLauncher::Instances::Base.instanciate(path, parent_instance)
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_ruby_utils/simple_cache'
4
+ require 'yaml'
5
+ require 'eac_launcher/instances/settings'
6
+
7
+ module EacLauncher
8
+ class Context
9
+ class Settings
10
+ include ::EacRubyUtils::SimpleCache
11
+
12
+ def initialize(file)
13
+ unless ::File.exist?(file)
14
+ ::FileUtils.mkdir_p(::File.dirname(file))
15
+ ::File.write(file, {}.to_yaml)
16
+ end
17
+ @data = YAML.load_file(file)
18
+ end
19
+
20
+ def instance_settings(instance)
21
+ ::EacLauncher::Instances::Settings.new(value(['Instances', instance.name]))
22
+ end
23
+
24
+ private
25
+
26
+ def excluded_projects_uncached
27
+ enum_value(%w[Projects Exclude])
28
+ end
29
+
30
+ def excluded_paths_uncached
31
+ enum_value(%w[Paths Exclude])
32
+ end
33
+
34
+ def enum_value(path)
35
+ r = value(path)
36
+ r.is_a?(Enumerable) ? r : []
37
+ end
38
+
39
+ def value(path)
40
+ node_value(@data, path)
41
+ end
42
+
43
+ def node_value(data, path)
44
+ return data if path.empty?
45
+ return nil unless data.is_a?(Hash)
46
+
47
+ node_value(data[path.first], path.drop(1))
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_launcher/git/base'
4
+ require 'eac_launcher/git/error'
5
+ require 'eac_launcher/git/mirror_update'
6
+ require 'eac_launcher/git/publish_base'
7
+ require 'eac_launcher/git/warp_base'
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_ruby_utils/core_ext'
4
+ require 'eac_ruby_utils/envs'
5
+ require 'eac_launcher/paths/real'
6
+ require 'eac_launcher/git/error'
7
+
8
+ module EacLauncher
9
+ module Git
10
+ class Base < ::EacLauncher::Paths::Real
11
+ require_sub __FILE__
12
+ enable_simple_cache
13
+ extend ::EacLauncher::Git::Base::ClassMethods
14
+ include ::EacLauncher::Git::Base::DirtyFiles
15
+ include ::EacLauncher::Git::Base::Remotes
16
+ include ::EacLauncher::Git::Base::Subrepo
17
+ include ::EacLauncher::Git::Base::Underlying
18
+
19
+ def init_bare
20
+ FileUtils.mkdir_p(self)
21
+ ::EacRubyUtils::Envs.local.command('git', 'init', '--bare', self).execute! unless
22
+ File.exist?(subpath('.git'))
23
+ end
24
+
25
+ def rev_parse(ref, required = false)
26
+ r = execute!('rev-parse', ref, exit_outputs: { 128 => nil, 32_768 => nil })
27
+ r.strip! if r.is_a?(String)
28
+ return r if r.present?
29
+ return nil unless required
30
+
31
+ raise "Reference \"#{ref}\" not found"
32
+ end
33
+
34
+ # @return [Pathname]
35
+ def root_path
36
+ @root_path ||= self.class.find_root(to_s)
37
+ end
38
+
39
+ def descendant?(descendant, ancestor)
40
+ base = merge_base(descendant, ancestor)
41
+ return false if base.blank?
42
+
43
+ revparse = execute!('rev-parse', '--verify', ancestor).strip
44
+ base == revparse
45
+ end
46
+
47
+ def merge_base(*commits)
48
+ refs = commits.dup
49
+ while refs.count > 1
50
+ refs[1] = merge_base_pair(refs[0], refs[1])
51
+ return nil if refs[1].blank?
52
+
53
+ refs.shift
54
+ end
55
+ refs.first
56
+ end
57
+
58
+ def subtree_split(prefix)
59
+ execute!('subtree', '-q', 'split', '-P', prefix).strip
60
+ end
61
+
62
+ def push(remote_name, refspecs, options = {})
63
+ refspecs = [refspecs] unless refspecs.is_a?(Array)
64
+ args = ['push']
65
+ args << '--dry-run' if options[:dryrun]
66
+ args << '--force' if options[:force]
67
+ system!(args + [remote_name] + refspecs)
68
+ end
69
+
70
+ def push_all(remote_name)
71
+ system!('push', '--all', remote_name)
72
+ system!('push', '--tags', remote_name)
73
+ end
74
+
75
+ def fetch(remote_name, options = {})
76
+ args = ['fetch', '-p', remote_name]
77
+ args += %w[--tags --prune-tags --force] if options[:tags]
78
+ execute!(*args)
79
+ end
80
+
81
+ def current_branch
82
+ execute!(%w[symbolic-ref -q HEAD]).gsub(%r{\Arefs/heads/}, '').strip
83
+ end
84
+
85
+ def reset_hard(ref)
86
+ execute!('reset', '--hard', ref)
87
+ end
88
+
89
+ def raise(message)
90
+ ::Kernel.raise EacLauncher::Git::Error.new(self, message)
91
+ end
92
+
93
+ private
94
+
95
+ def merge_base_pair(commit1, commit2)
96
+ execute!('merge-base', commit1, commit2, exit_outputs: { 256 => '' }).strip
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EacLauncher
4
+ module Git
5
+ class Base < ::EacLauncher::Paths::Real
6
+ module ClassMethods
7
+ # @return [EacLauncher::Git::Base]
8
+ def by_root(search_base_path)
9
+ new(find_root(search_base_path).to_path)
10
+ end
11
+
12
+ # Searches the root path for the Git repository which includes +search_base_path+.
13
+ # @return [Pathname]
14
+ def find_root(search_base_path)
15
+ path = search_base_path.to_pathname.expand_path
16
+ loop do
17
+ return path if path.join('.git').exist?
18
+ raise "\".git\" not found for \"#{search_base_path}\"" if path.parent.root?
19
+
20
+ path = path.parent
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end