git_toolbox 0.7.2 → 0.9.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.
@@ -17,24 +17,20 @@
17
17
 
18
18
  # frozen_string_literal: true
19
19
 
20
- require 'get/commons/common'
21
- require 'get/commons/git'
22
- require 'get/subcommand/command'
23
- require 'get/subcommand/describe/change'
24
- require 'get/subcommand/describe/prerelease'
25
- require 'get/subcommand/describe/metadata'
26
- require 'get/subcommand/describe/docker/docker'
20
+ require_relative '../../commons/common'
21
+ require_relative '../../commons/git'
22
+ require_relative '../command'
23
+ require_relative './change'
24
+ require_relative './prerelease'
25
+ require_relative './metadata'
26
+ require_relative './docker/docker'
27
27
 
28
28
  # Class length is disabled as most of its length is given by formatting.
29
29
  # rubocop:disable Metrics/ClassLength
30
30
  # Subcommand, it manages the description of the current git repository using semantic version.
31
+ # All its subcommands should have a method named "describe_current_commit" as it will be called.
31
32
  class Describe < Command
32
- def self.command
33
- @@command ||= new
34
- @@command
35
- end
36
-
37
- private_class_method :new
33
+ include Singleton
38
34
 
39
35
  private
40
36
 
@@ -42,105 +38,24 @@ class Describe < Command
42
38
  include PrereleaseHandler
43
39
  include MetadataHandler
44
40
 
45
- @@command = nil
46
-
47
- DEFAULT_RELEASE_VERSION = '0.1.0'
48
- FULL_SEMANTIC_VERSION_REGEX = /
49
- ^((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)) # Stable version, major, minor, patch
50
- (?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))? # prerelease
51
- (?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ # metadata
52
- /x
53
-
54
- @@usage = 'describe -h|(<subcommand> [<subcommand-options])'
55
- @@description = 'Describe the current git repository with semantic version.'
56
- @@subcommands = {
57
- docker: DescribeDocker.command,
58
- }
59
- # This block is Optimist configuration. It is as long as the number of options of the command.
60
- # rubocop:disable Metrics/BlockLength
61
- @@option_parser = Optimist::Parser.new do
62
- subcommand_max_length = @@subcommands.keys.map { |k| k.to_s.length }.max
63
- subcommand_section = <<~SUBCOMMANDS unless @@subcommands.empty?
64
- Subcommands:
65
- #{@@subcommands.keys.map { |k| " #{k.to_s.ljust(subcommand_max_length)} => #{@@subcommands[k].description}" }.join("\n")}
66
- SUBCOMMANDS
67
- usage @@usage
68
- synopsis @@description + (subcommand_section.nil? ? '' : "\n") + subcommand_section.to_s
69
- opt :prerelease,
70
- 'Describe a prerelease rather than a release',
71
- short: :none
72
- opt :exclude_metadata,
73
- 'Do not include metadata in version.'
74
- opt :metadata,
75
- 'Set which metadata to include in the string. ' \
76
- 'Multiple value can be specified by separating the with a comma \',\'.',
77
- { type: :string, default: 'sha' }
78
- opt :major_trigger,
79
- 'Set the trigger for a major release. ' \
80
- 'This must be a valid Ruby expression. ' \
81
- 'In this expression the string values "type" and "scope" ' \
82
- 'and the boolean value "is_breaking" can be used.',
83
- { short: :none, type: :string, default: 'is_breaking' }
84
- opt :minor_trigger,
85
- 'Set the trigger for a minor release. ' \
86
- 'This must be a valid Ruby expression. ' \
87
- 'In this expression the string values "type" and "scope" can be used.',
88
- { short: :none, type: :string, default: "type == 'feat'" }
89
- opt :patch_trigger,
90
- 'Set the trigger for a patch release. ' \
91
- 'This must be a valid Ruby expression. ' \
92
- 'In this expression the string values "type" and "scope" can be used.',
93
- { short: :none, type: :string, default: "type == 'fix'" }
94
- opt :prerelease_pattern,
95
- 'Set the pattern of the prerelease. This must contain the placeholder "(p)".',
96
- { short: :none, type: :string, default: 'dev(p)' }
97
- opt :old_prerelease_pattern,
98
- 'Set the pattern of the old prerelease. It is useful for changing prerelease pattern.',
99
- { short: :none, type: :string, default: 'prerelease-pattern value' }
100
- opt :diff,
101
- 'Print also the last version.'
102
- opt :create_tag,
103
- 'Create a signed tag with the computed version.',
104
- { short: :none }
105
- opt :tag_message,
106
- 'Add the given message to the tag. Requires "--create-tag".',
107
- { short: :none, type: :string }
108
- educate_on_error
109
- stop_on @@subcommands.keys.map(&:to_s)
110
- end
111
- # rubocop:enable Metrics/BlockLength
112
-
113
41
  def initialize
114
- super(@@usage, @@description) do
115
- @options = Common.with_subcommand_exception_handling @@option_parser do
116
- @@option_parser.parse
117
- end
118
- Common.error 'describe need to be run inside a git repository' unless Git.in_repo?
119
- set_options
120
-
121
- if ARGV.length.positive?
122
- subcommand = ARGV.shift.to_sym
123
- if @@subcommands.include?(subcommand)
124
- @@subcommands[subcommand].action.call(describe_current_commit)
125
- else
126
- # This error should not be disabled by -W0
127
- # rubocop:disable Style/StderrPuts
128
- $stderr.puts "Error: subcommand '#{subcommand}' unknown."
129
- # rubocop:enable Style/StderrPuts
130
- exit 1
131
- end
132
- else
133
- puts describe_current_commit
134
- end
42
+ super() do
43
+ @usage = 'describe -h|(<subcommand> [<subcommand-options])'
44
+ @description = 'Describe the current git repository with semantic version.'
45
+ @subcommands = {
46
+ docker: DescribeDocker.instance,
47
+ }
135
48
  end
136
49
  end
137
50
 
138
51
  def set_options
139
- @@major_trigger = @options[:major_trigger] if @options[:major_trigger_given]
140
- @@minor_trigger = @options[:minor_trigger] if @options[:minor_trigger_given]
141
- @@patch_trigger = @options[:patch_trigger] if @options[:patch_trigger_given]
142
- @@old_prerelease_pattern = @options[:old_prerelease_pattern] if @options[:old_prerelease_pattern_given]
143
- @@prerelease_pattern = @options[:prerelease_pattern] if @options[:prerelease_pattern_given]
52
+ ChangeHandler.major_trigger = @options[:major_trigger] if @options[:major_trigger_given]
53
+ ChangeHandler.minor_trigger = @options[:minor_trigger] if @options[:minor_trigger_given]
54
+ ChangeHandler.patch_trigger = @options[:patch_trigger] if @options[:patch_trigger_given]
55
+ if @options[:old_prerelease_pattern_given]
56
+ PrereleaseHandler.old_prerelease_pattern = @options[:old_prerelease_pattern]
57
+ end
58
+ PrereleaseHandler.prerelease_pattern = @options[:prerelease_pattern] if @options[:prerelease_pattern_given]
144
59
  end
145
60
 
146
61
  def describe_current_commit
@@ -162,68 +77,101 @@ class Describe < Command
162
77
 
163
78
  def next_release
164
79
  if @options[:prerelease]
165
- prepare_prerelease_tag(Git.last_release, Git.last_version)
80
+ updated_stable_version(Git.last_release)
81
+ .then { |stable| "#{stable}-#{updated_prerelease(Git.last_version, stable)}" }
166
82
  else
167
- prepare_release_tag(Git.last_release)
83
+ updated_stable_version(Git.last_release).to_s
168
84
  end + metadata
169
85
  end
170
86
 
171
- def prepare_release_tag(last_release)
172
- updated_stable_version(last_release).to_s
173
- end
87
+ def metadata
88
+ return '' if @options[:exclude_metadata] || @options[:metadata].empty?
174
89
 
175
- def prepare_prerelease_tag(last_release, last_version)
176
- new_stable_version = updated_stable_version(last_release)
177
- base_version_match_data = FULL_SEMANTIC_VERSION_REGEX.match(last_version)
178
- no_changes_from_last_release = base_version_match_data[1] == new_stable_version && base_version_match_data[5].nil?
179
- Common.error 'No changes from last release' if no_changes_from_last_release
180
- new_stable_version +
181
- "-#{updated_prerelease(base_version_match_data[5], need_reset: base_version_match_data[1] != new_stable_version)}"
90
+ "+#{compute_metadata(@options[:metadata])}"
182
91
  end
183
92
 
184
- def updated_stable_version(stable_version)
185
- return DEFAULT_RELEASE_VERSION if stable_version.nil?
186
-
187
- greatest_change_from_stable_version = Git.with_commit_list_from(stable_version) do |commits_from_version|
188
- greatest_change_in(commits_from_version)
189
- end
190
- split_version = stable_version.split('.')
191
- case greatest_change_from_stable_version
192
- when :MAJOR
193
- "#{split_version[0].to_i + 1}.0.0"
194
- when :MINOR
195
- "#{split_version[0].to_i}.#{split_version[1].to_i + 1}.0"
196
- when :PATCH
197
- "#{split_version[0].to_i}.#{split_version[1].to_i}.#{split_version[2].to_i + 1}"
198
- else
199
- "#{split_version[0].to_i}.#{split_version[1].to_i}.#{split_version[2].to_i}"
200
- end
93
+ def create_signed_tag(computed_version)
94
+ tag_message_cli = if @options[:tag_message_given]
95
+ "\"#{@options[:tag_message].gsub('"', '\"')}\""
96
+ else
97
+ '""'
98
+ end
99
+ CommandIssuer.run('git', 'tag', '-s', '-m', tag_message_cli, "'#{computed_version}'")
201
100
  end
202
101
 
203
- # Return the updated prerelease number
204
- def updated_prerelease(prerelease = nil, need_reset: false)
205
- compute_prerelease(prerelease, need_reset: prerelease.nil? || need_reset)
102
+ protected
103
+
104
+ def setup_option_parser
105
+ @option_parser = Optimist::Parser.new(
106
+ @usage,
107
+ full_description,
108
+ stop_condition
109
+ ) do |usage_header, description, stop_condition|
110
+ usage usage_header
111
+ synopsis description
112
+ opt :prerelease,
113
+ 'Describe a prerelease rather than a release',
114
+ short: :none
115
+ opt :exclude_metadata,
116
+ 'Do not include metadata in version.'
117
+ opt :metadata,
118
+ 'Set which metadata to include in the string. ' \
119
+ 'Multiple value can be specified by separating the with a comma \',\'.',
120
+ { type: :string, default: 'sha' }
121
+ opt :major_trigger,
122
+ 'Set the trigger for a major release. ' \
123
+ 'This must be a valid Ruby expression. ' \
124
+ 'In this expression the string values "type" and "scope" ' \
125
+ 'and the boolean value "is_breaking" can be used.',
126
+ { short: :none, type: :string, default: 'is_breaking' }
127
+ opt :minor_trigger,
128
+ 'Set the trigger for a minor release. ' \
129
+ 'This must be a valid Ruby expression. ' \
130
+ 'In this expression the string values "type" and "scope" can be used.',
131
+ { short: :none, type: :string, default: "type == 'feat'" }
132
+ opt :patch_trigger,
133
+ 'Set the trigger for a patch release. ' \
134
+ 'This must be a valid Ruby expression. ' \
135
+ 'In this expression the string values "type" and "scope" can be used.',
136
+ { short: :none, type: :string, default: "type == 'fix'" }
137
+ opt :prerelease_pattern,
138
+ 'Set the pattern of the prerelease. This must contain the placeholder "(p)".',
139
+ { short: :none, type: :string, default: 'dev(p)' }
140
+ opt :old_prerelease_pattern,
141
+ 'Set the pattern of the old prerelease. It is useful for changing prerelease pattern.',
142
+ { short: :none, type: :string, default: 'prerelease-pattern value' }
143
+ opt :diff,
144
+ 'Print also the last version.'
145
+ opt :create_tag,
146
+ 'Create a signed tag with the computed version.',
147
+ { short: :none }
148
+ opt :tag_message,
149
+ 'Add the given message to the tag. Requires "--create-tag".',
150
+ { short: :none, type: :string }
151
+ educate_on_error
152
+ stop_on stop_condition
153
+ end
206
154
  end
207
155
 
208
- # Compute the metadata string
209
- def metadata
210
- return '' if @options[:exclude_metadata] || @options[:metadata].empty?
211
-
212
- "+#{compute_metadata(@options[:metadata])}"
213
- end
156
+ def setup_action
157
+ @action = lambda do
158
+ @options = Common.with_subcommand_exception_handling @option_parser do
159
+ @option_parser.parse
160
+ end
161
+ Common.error 'describe need to be run inside a git repository' unless Git.in_repo?
162
+ set_options
214
163
 
215
- def create_signed_tag(computed_version)
216
- system(
217
- 'git tag -s ' \
218
- "#{
219
- if @options[:tag_message_given]
220
- "-m #{@options[:tag_message]}"
164
+ if ARGV.length.positive?
165
+ subcommand = ARGV.shift.to_sym
166
+ if @subcommands.include?(subcommand)
167
+ @subcommands[subcommand].action.call(describe_current_commit)
221
168
  else
222
- ''
169
+ Common.error "subcommand '#{subcommand}' unknown."
223
170
  end
224
- } " \
225
- "'#{computed_version}'"
226
- )
171
+ else
172
+ puts describe_current_commit
173
+ end
174
+ end
227
175
  end
228
176
  end
229
177
  # rubocop:enable Metrics/ClassLength
@@ -17,82 +17,43 @@
17
17
 
18
18
  # frozen_string_literal: true
19
19
 
20
- require 'get/commons/common'
21
- require 'get/commons/git'
22
- require 'get/subcommand/command'
20
+ require_relative '../../../commons/common'
21
+ require_relative '../../../commons/git'
22
+ require_relative '../../command'
23
23
 
24
24
  # Class length is disabled as most of its length is given by formatting.
25
25
  # rubocop:disable Metrics/ClassLength
26
26
  # Subcommand, it manages the description of the current git repository using semantic version.
27
27
  class DescribeDocker < Command
28
- def self.command
29
- @@command ||= new
30
- @@command
31
- end
32
-
33
- private_class_method :new
34
-
35
28
  private
36
29
 
37
30
  INCREMENTAL_VERSION_PATTERN = /(((\d+)\.\d+)\.\d+)/
38
31
 
39
- @@command = nil
40
-
41
- @@usage = 'describe docker -h|(<subcommand> [<subcommand-options])'
42
- @@description = 'Describe the current git repository with a list of version for docker'
43
- @@subcommands = {}
44
- # This block is Optimist configuration. It is as long as the number of options of the command.
45
- # rubocop:disable Metrics/BlockLength
46
- @@option_parser = Optimist::Parser.new do
47
- subcommand_max_length = @@subcommands.keys.map { |k| k.to_s.length }.max
48
- usage @@usage
49
- synopsis <<~SUBCOMMANDS unless @@subcommands.empty?
50
- Subcommands:
51
- #{@@subcommands.keys.map { |k| " #{k.to_s.ljust(subcommand_max_length)} => #{@@subcommands[k].description}" }.join("\n")}
52
- SUBCOMMANDS
53
- opt :separator,
54
- 'Use the given value as separator for versions',
55
- { type: :string, default: '\n' }
56
- opt :not_latest,
57
- 'Do not include "latest" in the version list.',
58
- short: :none
59
- opt :substitute_plus,
60
- 'Set which character will be used in place of "+".',
61
- { type: :string, short: :none }
62
- educate_on_error
63
- stop_on @@subcommands.keys.map(&:to_s)
64
- end
65
- # rubocop:enable Metrics/BlockLength
66
-
67
32
  def initialize
68
- super(@@usage, @@description) do |version|
69
- Common.error 'describe need to be run inside a git repository' unless Git.in_repo?
70
- @options = Common.with_subcommand_exception_handling @@option_parser do
71
- @@option_parser.parse
72
- end
73
- set_options
74
-
75
- puts version_list_from(version).join(@@separator)
33
+ super() do
34
+ @usage = 'describe docker -h|(<subcommand> [<subcommand-options])'
35
+ @description = 'Describe the current git repository with a list of version for docker'
36
+ @subcommands = {}
76
37
  end
77
38
  end
78
39
 
79
40
  def set_options
80
- @@separator = if @options[:separator_given]
81
- @options[:separator]
82
- else
83
- "\n"
84
- end
85
- @@not_latest = @options[:not_latest]
86
- @@plus_substitution = if @options[:substitute_plus_given]
87
- @options[:substitute_plus]
88
- else
89
- '+'
90
- end
41
+ @separator = if @options[:separator_given]
42
+ @options[:separator]
43
+ else
44
+ "\n"
45
+ end
46
+ @not_latest = @options[:not_latest]
47
+ @plus_substitution = if @options[:substitute_plus_given]
48
+ @options[:substitute_plus]
49
+ else
50
+ '+'
51
+ end
91
52
  end
92
53
 
93
54
  def version_list_from(full_version)
94
55
  [
95
- full_version.sub('+', @@plus_substitution),
56
+ full_version.sub('+', @plus_substitution),
96
57
  reduced_versions(full_version),
97
58
  latest
98
59
  ]
@@ -114,5 +75,41 @@ class DescribeDocker < Command
114
75
  ['latest']
115
76
  end
116
77
  end
78
+
79
+ protected
80
+
81
+ def setup_option_parser
82
+ @option_parser = Optimist::Parser.new(
83
+ @usage,
84
+ full_description,
85
+ stop_condition
86
+ ) do |usage_header, description, stop_condition|
87
+ usage usage_header
88
+ synopsis description
89
+ opt :separator,
90
+ 'Use the given value as separator for versions',
91
+ { type: :string, default: '\n' }
92
+ opt :not_latest,
93
+ 'Do not include "latest" in the version list.',
94
+ short: :none
95
+ opt :substitute_plus,
96
+ 'Set which character will be used in place of "+".',
97
+ { type: :string, short: :none }
98
+ educate_on_error
99
+ stop_on stop_condition
100
+ end
101
+ end
102
+
103
+ def setup_action
104
+ @action = lambda do |version|
105
+ Common.error 'describe need to be run inside a git repository' unless Git.in_repo?
106
+ @options = Common.with_subcommand_exception_handling @option_parser do
107
+ @option_parser.parse
108
+ end
109
+ set_options
110
+
111
+ puts version_list_from(version).join(@separator)
112
+ end
113
+ end
117
114
  end
118
115
  # rubocop:enable Metrics/ClassLength
@@ -17,37 +17,34 @@
17
17
 
18
18
  # frozen_string_literal: true
19
19
 
20
+ require_relative '../../commons/command_issuer'
21
+
20
22
  # Module with methods to handle tag metadata.
21
23
  #
22
24
  # To add a new metadata type, create a new method and link it to a symbol.
23
25
  module MetadataHandler
24
- @@metadata_computers = {}
26
+ def compute_metadata(metadata_specs)
27
+ requested_metadata = metadata_specs.split(',')
28
+ unless requested_metadata.all? { |element| metadata_computers.include?(element.to_sym) }
29
+ Common.error('Some of the metadata requested are not supported')
30
+ end
31
+ requested_metadata.map { |element| metadata_computers[element.to_sym].call }.join('-')
32
+ end
25
33
 
26
- module_function
34
+ private
27
35
 
28
36
  def last_commit_sha
29
- `git --no-pager log -n 1 --pretty=%h`.strip
37
+ CommandIssuer.run('git', '--no-pager', 'log', '-n', '1', '--pretty=%h').output.strip
30
38
  end
31
39
 
32
40
  def current_date
33
41
  Time.now.strftime('%0Y%0m%0d')
34
42
  end
35
43
 
36
- def init_computers
37
- @@metadata_computers[:sha] = proc { last_commit_sha }
38
- @@metadata_computers[:date] = proc { current_date }
39
- end
40
-
41
- public
42
-
43
- def compute_metadata(metadata_specs)
44
- metadata_specs
45
- .split(',')
46
- .map { |element| @@metadata_computers[element.to_sym].call }
47
- .join('-')
48
- end
49
-
50
- def self.included(_mod)
51
- init_computers
44
+ def metadata_computers
45
+ @metadata_computers ||= {
46
+ sha: proc { last_commit_sha },
47
+ date: proc { current_date },
48
+ }
52
49
  end
53
50
  end
@@ -22,19 +22,36 @@ module PrereleaseHandler
22
22
  FIRST_PRERELEASE = 1
23
23
  DEFAULT_PRERELEASE_STRING = 'dev'
24
24
  PRERELEASE_PLACEHOLDER = '(p)'
25
+ DEFAULT_PRERELEASE_PATTERN = "#{DEFAULT_PRERELEASE_STRING}#{PRERELEASE_PLACEHOLDER}".freeze
25
26
 
26
- @@prerelease_pattern = "#{DEFAULT_PRERELEASE_STRING}#{PRERELEASE_PLACEHOLDER}"
27
- @@old_prerelease_pattern = proc { @@prerelease_pattern }
27
+ Common.module_instance_attr(self, 'prerelease_pattern', :DEFAULT_PRERELEASE_PATTERN)
28
+ Common.module_instance_attr(self, 'old_prerelease_pattern', 'proc { prerelease_pattern }')
28
29
 
29
- module_function
30
+ def updated_prerelease(last_version, new_stable_version)
31
+ if last_version.nil?
32
+ compute_prerelease(nil, need_reset: true)
33
+ else
34
+ base_version_match_data = Git::FULL_SEMANTIC_VERSION_REGEX.match(last_version)
35
+ no_changes_from_last_release = base_version_match_data[1] == new_stable_version &&
36
+ base_version_match_data[5].nil?
37
+ Common.error 'No changes from last release' if no_changes_from_last_release
38
+ compute_prerelease(base_version_match_data[5], need_reset: base_version_match_data[1] != new_stable_version)
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def compute_prerelease(current_prerelease, need_reset: false)
45
+ pattern_changed = PrereleaseHandler.prerelease_pattern != actual_old_prerelease_pattern
46
+ new_prerelease = if need_reset || pattern_changed
47
+ FIRST_PRERELEASE
48
+ else
49
+ extract_prerelease_number(current_prerelease) + 1
50
+ end.to_s
51
+ PrereleaseHandler.prerelease_pattern.sub(PRERELEASE_PLACEHOLDER, new_prerelease)
52
+ end
30
53
 
31
54
  def extract_prerelease_number(current_prerelease)
32
- actual_old_prerelease_pattern =
33
- if @@old_prerelease_pattern.respond_to?('call')
34
- @@old_prerelease_pattern.call
35
- else
36
- @@old_prerelease_pattern
37
- end
38
55
  Common.error "The given old pattern does not contains the placeholder '(p)'" unless
39
56
  actual_old_prerelease_pattern.include?(PRERELEASE_PLACEHOLDER)
40
57
  old_prerelease_regex = actual_old_prerelease_pattern.sub(PRERELEASE_PLACEHOLDER, '(\\d+)')
@@ -46,10 +63,11 @@ module PrereleaseHandler
46
63
  end
47
64
  end
48
65
 
49
- public
50
-
51
- def compute_prerelease(current_prerelease, need_reset: false)
52
- new_prerelease = (need_reset ? FIRST_PRERELEASE : (extract_prerelease_number(current_prerelease) + 1)).to_s
53
- @@prerelease_pattern.sub(PRERELEASE_PLACEHOLDER, new_prerelease)
66
+ def actual_old_prerelease_pattern
67
+ if PrereleaseHandler.old_prerelease_pattern.respond_to?('call')
68
+ PrereleaseHandler.old_prerelease_pattern.call
69
+ else
70
+ PrereleaseHandler.old_prerelease_pattern
71
+ end
54
72
  end
55
73
  end
@@ -17,60 +17,28 @@
17
17
 
18
18
  # frozen_string_literal: true
19
19
 
20
- require 'English'
21
- require 'get/commons/common'
22
- require 'get/commons/git'
23
- require 'get/subcommand/command'
20
+ require_relative '../../commons/common'
21
+ require_relative '../../commons/git'
22
+ require_relative '../command'
24
23
 
25
24
  # Class length is disabled as most of its length is given by formatting.
26
25
  # rubocop:disable Metrics/ClassLength
27
26
  # Subcommand, it allow to create a new repository and add an initial, empty commit to it.
28
27
  class Init < Command
29
- def self.command
30
- @@command ||= new
31
- @@command
32
- end
33
-
34
- private_class_method :new
35
-
36
28
  private
37
29
 
38
- @@command = nil
39
-
40
- @@usage = 'init -h|(<subcommand> [<subcommand-options])'
41
- @@description = 'Initialize a new git repository with an initial empty commit.'
42
- @@subcommands = {}
43
- # This block is Optimist configuration. It is as long as the number of options of the command.
44
- # rubocop:disable Metrics/BlockLength
45
- @@option_parser = Optimist::Parser.new do
46
- subcommand_max_length = @@subcommands.keys.map { |k| k.to_s.length }.max
47
- subcommand_section = <<~SUBCOMMANDS unless @@subcommands.empty?
48
- Subcommands:
49
- #{@@subcommands.keys.map { |k| " #{k.to_s.ljust(subcommand_max_length)} => #{@@subcommands[k].description}" }.join("\n")}
50
- SUBCOMMANDS
51
- usage @@usage
52
- synopsis @@description + (subcommand_section.nil? ? '' : "\n") + subcommand_section.to_s
53
- opt :empty,
54
- 'Do not create the first, empty commit.'
55
- educate_on_error
56
- stop_on @@subcommands.keys.map(&:to_s)
57
- end
58
- # rubocop:enable Metrics/BlockLength
59
-
60
30
  def initialize
61
- super(@@usage, @@description) do
62
- @options = Common.with_subcommand_exception_handling @@option_parser do
63
- @@option_parser.parse
64
- end
65
- Common.error 'The current directory is already a git repository' if Git.in_repo?
66
-
67
- init_repository
31
+ super() do
32
+ @usage = 'init -h|(<subcommand> [<subcommand-options])'
33
+ @description = 'Initialize a new git repository with an initial empty commit.'
34
+ @subcommands = {}
68
35
  end
69
36
  end
70
37
 
71
38
  def init_repository
72
- `git init`
73
- Common.error 'Failed to init the repository' if $CHILD_STATUS.exitstatus.positive?
39
+ command_result = CommandIssuer.run('git', 'init')
40
+
41
+ Common.error 'Failed to init the repository' if command_result.exit_status.positive?
74
42
 
75
43
  create_first_commit unless @options[:empty]
76
44
 
@@ -78,8 +46,39 @@ class Init < Command
78
46
  end
79
47
 
80
48
  def create_first_commit
81
- `git commit --allow-empty -m "chore: initialize repository"`
82
- Common.error 'Failed to create first commit' if $CHILD_STATUS.exitstatus.positive?
49
+ command_result = CommandIssuer.run('git', 'commit', '--allow-empty', '-m', '"chore: initialize repository"')
50
+ Common.error "Failed to create first commit: #{command_result.error}" if command_result.exit_status.positive?
51
+ end
52
+
53
+ protected
54
+
55
+ def setup_option_parser
56
+ # This block is Optimist configuration. It is as long as the number of options of the command.
57
+ # rubocop:disable Metrics/BlockLength
58
+ @option_parser = Optimist::Parser.new(
59
+ @usage,
60
+ full_description,
61
+ stop_condition
62
+ ) do |usage_header, description, stop_condition|
63
+ usage usage_header
64
+ synopsis description
65
+ opt :empty,
66
+ 'Do not create the first, empty commit.'
67
+ educate_on_error
68
+ stop_on stop_condition
69
+ end
70
+ # rubocop:enable Metrics/BlockLength
71
+ end
72
+
73
+ def setup_action
74
+ @action = lambda do
75
+ @options = Common.with_subcommand_exception_handling @option_parser do
76
+ @option_parser.parse
77
+ end
78
+ Common.error 'The current directory is already a git repository' if Git.in_repo?
79
+
80
+ init_repository
81
+ end
83
82
  end
84
83
  end
85
84
  # rubocop:enable Metrics/ClassLength