git_toolbox 0.7.2 → 0.9.0

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