git_toolbox 0.8.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 500f22d2000495865a5671476122c580ea0e5fdb6ebf2804ce42d209828a1841
4
- data.tar.gz: 70a3c312974ce5ee382a8c6793325bf676dba7fb40206ed828f56c2019ce9d64
3
+ metadata.gz: d18e02ebf90eb2595af4735f88043d1fdea653a03d8500dec75a7cf9a510bc51
4
+ data.tar.gz: c0344b2969623ab61aa94c6960fa88bdad522057541ece00052bfdf9f4cbf636
5
5
  SHA512:
6
- metadata.gz: ce3a643b6a110c7b70e7ddc33649548b15f064e61dbe35c13fa5eba3fa70b7c71a5118185ee88b89aab83f74602b605d9175b4633e58c933ae30ebfae97c2dab
7
- data.tar.gz: 5125a3a0af8ab4a6590af9166c95d442c1dae5f89648f1d94224ff5a4d3e18fcaf21ec5e9d52b1f50939340d17d60ddd5cd37fa7bd6bd16b4e7ce88f2ac868da
6
+ metadata.gz: a9cbe2abd8b068d78436841419dddd776f72e97b57a5575f8447ae31e7744d8a7e54de9eaa55a242ff0c177b52a1f81b74309b044970c12ccaf98f4dc7d431d4
7
+ data.tar.gz: 9248e4bcce0371b73542e336591bc6844ac8a66f6d93334702fa0e7fbb2b13556c6d914682d9e8f62e964f5eb8aee6462bd4ebe739c4881effe69241c141ca1a
@@ -23,6 +23,15 @@ require_relative './command_issuer'
23
23
  module Git
24
24
  # Groups: 1 = type, 2 = scope with (), 3 = scope, 4 = breaking change, 5 = summary
25
25
  CONVENTIONAL_COMMIT_REGEX = %r{^(\w+)(\(([\w/-]+)\))?(!)?:(.*)}
26
+ DEFAULT_RELEASE_VERSION = '0.1.0'
27
+ # Groups:
28
+ # 1 = full stable version ; 2,3,4 = major,minor,patch
29
+ # 5 = prerelease ; 6 = metadata
30
+ FULL_SEMANTIC_VERSION_REGEX = /
31
+ ^((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)) # Stable version, major, minor, patch
32
+ (?:-((?: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
33
+ (?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ # metadata
34
+ /x
26
35
 
27
36
  # Check if the command is called while in a git repository.
28
37
  # If the command fails, it is assumed to not be in a git repository.
@@ -61,11 +70,12 @@ module Git
61
70
  # Returns the last release and caches it for the next calls.
62
71
  def self.last_release
63
72
  @last_release ||=
64
- CommandIssuer.run('git', '--no-pager', 'tag', '--list')
73
+ CommandIssuer.run('git', '--no-pager', 'tag', '--list', '--merged')
65
74
  .then do |value|
66
75
  unless value.output.empty?
67
76
  value.output
68
77
  .split("\n")
78
+ .select { |str| str.match(FULL_SEMANTIC_VERSION_REGEX)[5].nil? }
69
79
  .map { |str| str.sub('+', '_') }
70
80
  .sort
71
81
  .map { |str| str.sub('_', '+') }
@@ -28,6 +28,10 @@ module BashCompletion
28
28
  private
29
29
 
30
30
  INITIAL_LEVEL = 1
31
+ NOT_NEGABLE_OPTIONS = [
32
+ 'help',
33
+ 'version',
34
+ ].freeze
31
35
 
32
36
  HEADER = <<~HEADER
33
37
  #!/usr/bin/env bash
@@ -77,6 +81,7 @@ module BashCompletion
77
81
 
78
82
  command_class.instance.option_parser.specs.each_value do |option|
79
83
  long_options.push("--#{option.long}")
84
+ long_options.push("--no-#{option.long}") if option.flag? && !NOT_NEGABLE_OPTIONS.include?(option.long)
80
85
  short_options.push("-#{option.short.nil? ? option.long[0] : option.short}") if option.short != :none
81
86
  end
82
87
 
@@ -33,8 +33,18 @@ class Complete < Command
33
33
  def initialize
34
34
  super() do
35
35
  @usage = 'complete -h|(<subcommand> [<subcommand-options])'
36
- @description = 'Print the shell completion script.'
36
+ @description = 'Print the shell completion script. ' \
37
+ 'Run \'get complete --info\' to learn how to install the completion.'
37
38
  @subcommands = {}
39
+ @completions = {
40
+ bash: {
41
+ generator: proc { bash_completion(Get, 'get') },
42
+ info: <<~INFO
43
+ Add the following line to your .bashrc (or a sourced script):
44
+ eval "$(get complete)" && complete -F _get_completion get
45
+ INFO
46
+ }
47
+ }
38
48
  end
39
49
  end
40
50
 
@@ -51,6 +61,9 @@ class Complete < Command
51
61
  opt :shell,
52
62
  'Select the type of shell of which the completion will be generated.',
53
63
  { type: :string, default: 'bash' }
64
+ opt :info,
65
+ 'Print the instructions to install the completion for the selected shell.',
66
+ { short: :none }
54
67
  educate_on_error
55
68
  stop_on stop_condition
56
69
  end
@@ -62,16 +75,19 @@ class Complete < Command
62
75
  @option_parser.parse
63
76
  end
64
77
 
65
- @completions = {
66
- bash: proc { bash_completion(Get, 'get') }
67
- }
68
-
69
78
  selected_shell = @options[:shell].to_sym
70
79
 
80
+ print_info_and_exit(selected_shell) if @options[:info]
81
+
71
82
  Common.error "Completion for shell '#{selected_shell}' not available." unless @completions.key?(selected_shell)
72
83
 
73
- puts @completions[selected_shell].call
84
+ puts @completions[selected_shell][:generator].call
74
85
  end
75
86
  end
87
+
88
+ def print_info_and_exit(selected_shell)
89
+ puts @completions[selected_shell][:info]
90
+ exit 0
91
+ end
76
92
  end
77
93
  # rubocop:enable Metrics/ClassLength
@@ -30,6 +30,27 @@ module ChangeHandler
30
30
  Common.module_instance_attr(self, 'minor_trigger', :DEFAULT_MINOR_TRIGGER)
31
31
  Common.module_instance_attr(self, 'patch_trigger', :DEFAULT_PATCH_TRIGGER)
32
32
 
33
+ def updated_stable_version(stable_version)
34
+ return Git::DEFAULT_RELEASE_VERSION if stable_version.nil?
35
+
36
+ greatest_change_from_stable_version = Git.with_commit_list_from(stable_version) do |commits_from_version|
37
+ greatest_change_in(commits_from_version)
38
+ end
39
+ split_version = stable_version.split('.')
40
+ case greatest_change_from_stable_version
41
+ when :MAJOR
42
+ "#{split_version[0].to_i + 1}.0.0"
43
+ when :MINOR
44
+ "#{split_version[0].to_i}.#{split_version[1].to_i + 1}.0"
45
+ when :PATCH
46
+ "#{split_version[0].to_i}.#{split_version[1].to_i}.#{split_version[2].to_i + 1}"
47
+ else
48
+ "#{split_version[0].to_i}.#{split_version[1].to_i}.#{split_version[2].to_i}"
49
+ end
50
+ end
51
+
52
+ private
53
+
33
54
  def greatest_change_in(commit_list)
34
55
  commit_list
35
56
  .grep(Git::CONVENTIONAL_COMMIT_REGEX)
@@ -37,8 +58,6 @@ module ChangeHandler
37
58
  .max { |a, b| CHANGE_TYPE.index(a) <=> CHANGE_TYPE.index(b) }
38
59
  end
39
60
 
40
- private
41
-
42
61
  # In this block method arguments can be used by user.
43
62
  # Also `eval` is needed to allow users to define their custom triggers.
44
63
  # rubocop:disable Lint/UnusedMethodArgument
@@ -61,8 +80,8 @@ module ChangeHandler
61
80
  def to_change(commit_message)
62
81
  groups = Git::CONVENTIONAL_COMMIT_REGEX.match(commit_message)
63
82
  return :MAJOR if triggers_major?(groups[1], groups[3], !groups[4].nil?)
64
- return :MINOR if triggers_minor?(groups[1], groups[2])
65
- return :PATCH if triggers_patch?(groups[1], groups[2])
83
+ return :MINOR if triggers_minor?(groups[1], groups[3])
84
+ return :PATCH if triggers_patch?(groups[1], groups[3])
66
85
 
67
86
  :NONE
68
87
  end
@@ -38,13 +38,6 @@ class Describe < Command
38
38
  include PrereleaseHandler
39
39
  include MetadataHandler
40
40
 
41
- DEFAULT_RELEASE_VERSION = '0.1.0'
42
- FULL_SEMANTIC_VERSION_REGEX = /
43
- ^((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)) # Stable version, major, minor, patch
44
- (?:-((?: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
45
- (?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ # metadata
46
- /x
47
-
48
41
  def initialize
49
42
  super() do
50
43
  @usage = 'describe -h|(<subcommand> [<subcommand-options])'
@@ -84,50 +77,13 @@ class Describe < Command
84
77
 
85
78
  def next_release
86
79
  if @options[:prerelease]
87
- 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)}" }
88
82
  else
89
- prepare_release_tag(Git.last_release)
83
+ updated_stable_version(Git.last_release).to_s
90
84
  end + metadata
91
85
  end
92
86
 
93
- def prepare_release_tag(last_release)
94
- updated_stable_version(last_release).to_s
95
- end
96
-
97
- def prepare_prerelease_tag(last_release, last_version)
98
- new_stable_version = updated_stable_version(last_release)
99
- base_version_match_data = FULL_SEMANTIC_VERSION_REGEX.match(last_version)
100
- no_changes_from_last_release = base_version_match_data[1] == new_stable_version && base_version_match_data[5].nil?
101
- Common.error 'No changes from last release' if no_changes_from_last_release
102
- new_stable_version +
103
- "-#{updated_prerelease(base_version_match_data[5], need_reset: base_version_match_data[1] != new_stable_version)}"
104
- end
105
-
106
- def updated_stable_version(stable_version)
107
- return DEFAULT_RELEASE_VERSION if stable_version.nil?
108
-
109
- greatest_change_from_stable_version = Git.with_commit_list_from(stable_version) do |commits_from_version|
110
- greatest_change_in(commits_from_version)
111
- end
112
- split_version = stable_version.split('.')
113
- case greatest_change_from_stable_version
114
- when :MAJOR
115
- "#{split_version[0].to_i + 1}.0.0"
116
- when :MINOR
117
- "#{split_version[0].to_i}.#{split_version[1].to_i + 1}.0"
118
- when :PATCH
119
- "#{split_version[0].to_i}.#{split_version[1].to_i}.#{split_version[2].to_i + 1}"
120
- else
121
- "#{split_version[0].to_i}.#{split_version[1].to_i}.#{split_version[2].to_i}"
122
- end
123
- end
124
-
125
- # Return the updated prerelease number
126
- def updated_prerelease(prerelease = nil, need_reset: false)
127
- compute_prerelease(prerelease, need_reset: prerelease.nil? || need_reset)
128
- end
129
-
130
- # Compute the metadata string
131
87
  def metadata
132
88
  return '' if @options[:exclude_metadata] || @options[:metadata].empty?
133
89
 
@@ -27,20 +27,31 @@ module PrereleaseHandler
27
27
  Common.module_instance_attr(self, 'prerelease_pattern', :DEFAULT_PRERELEASE_PATTERN)
28
28
  Common.module_instance_attr(self, 'old_prerelease_pattern', 'proc { prerelease_pattern }')
29
29
 
30
- def compute_prerelease(current_prerelease, need_reset: false)
31
- new_prerelease = (need_reset ? FIRST_PRERELEASE : (extract_prerelease_number(current_prerelease) + 1)).to_s
32
- PrereleaseHandler.prerelease_pattern.sub(PRERELEASE_PLACEHOLDER, new_prerelease)
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
33
40
  end
34
41
 
35
42
  private
36
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
53
+
37
54
  def extract_prerelease_number(current_prerelease)
38
- actual_old_prerelease_pattern =
39
- if PrereleaseHandler.old_prerelease_pattern.respond_to?('call')
40
- PrereleaseHandler.old_prerelease_pattern.call
41
- else
42
- PrereleaseHandler.old_prerelease_pattern
43
- end
44
55
  Common.error "The given old pattern does not contains the placeholder '(p)'" unless
45
56
  actual_old_prerelease_pattern.include?(PRERELEASE_PLACEHOLDER)
46
57
  old_prerelease_regex = actual_old_prerelease_pattern.sub(PRERELEASE_PLACEHOLDER, '(\\d+)')
@@ -51,4 +62,12 @@ module PrereleaseHandler
51
62
  "does not match the analyzed prerelease: '#{current_prerelease}'."
52
63
  end
53
64
  end
65
+
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
72
+ end
54
73
  end
@@ -47,7 +47,7 @@ class Init < Command
47
47
 
48
48
  def create_first_commit
49
49
  command_result = CommandIssuer.run('git', 'commit', '--allow-empty', '-m', '"chore: initialize repository"')
50
- Common.error 'Failed to create first commit' if command_result.exit_status.positive?
50
+ Common.error "Failed to create first commit: #{command_result.error}" if command_result.exit_status.positive?
51
51
  end
52
52
 
53
53
  protected
@@ -70,21 +70,18 @@ class Tree < Command
70
70
  # calc color escape codes length
71
71
  time_color_length = first_line_time.length - first_line_time.match(TIME_REGEX)[1].length
72
72
 
73
- # calc max length of time references
74
- time_padding = 0
75
- split_lines.each { |element| time_padding = [time_padding, element[1].length - time_color_length].max }
73
+ time_padding = global_fitting_time_padding(split_lines, time_color_length)
76
74
 
77
- # format strings
78
75
  split_lines
79
76
  .map do |element|
80
77
  # Only lines with the date reference have the color escape codes,
81
78
  # the other lines do not need the additional padding
82
79
  left_padding = TIME_MINIMUM_PADDING + time_padding +
83
- (element[1].match?(TIME_REGEX) ? time_color_length : 0)
80
+ (!element[1].nil? && element[1].match?(TIME_REGEX) ? time_color_length : 0)
84
81
  format(
85
82
  '%<date>s %<tree_mark>s %<pointers>s %<commit_text>s',
86
83
  {
87
- date: element[1].rjust(left_padding),
84
+ date: (element[1].nil? ? '' : element[1]).rjust(left_padding),
88
85
  tree_mark: element[0],
89
86
  pointers: element[2],
90
87
  commit_text: element[3]
@@ -95,6 +92,16 @@ class Tree < Command
95
92
  end
96
93
  # rubocop:enable Metrics/MethodLength
97
94
 
95
+ def global_fitting_time_padding(lines, time_color_length)
96
+ time_padding = 0
97
+ lines
98
+ # If element[1].nil? then the line refers to a intersection between branch lines
99
+ # they do not have a time reference
100
+ .reject { |element| element[1].nil? }
101
+ .each { |element| time_padding = [time_padding, element[1].length - time_color_length].max }
102
+ time_padding
103
+ end
104
+
98
105
  protected
99
106
 
100
107
  def setup_option_parser
data/lib/get/version.rb CHANGED
@@ -17,4 +17,4 @@
17
17
 
18
18
  # frozen_string_literal: true
19
19
 
20
- GET_VERSION = '0.8.0'
20
+ GET_VERSION = '0.9.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git_toolbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Speranza
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-22 00:00:00.000000000 Z
11
+ date: 2023-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: highline
@@ -96,7 +96,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
96
96
  requirements:
97
97
  - - ">="
98
98
  - !ruby/object:Gem::Version
99
- version: 3.1.0
99
+ version: 3.0.0
100
100
  required_rubygems_version: !ruby/object:Gem::Requirement
101
101
  requirements:
102
102
  - - ">="