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.
- checksums.yaml +4 -4
- data/bin/get +1 -1
- data/lib/get/commons/command_issuer.rb +60 -0
- data/lib/get/commons/common.rb +70 -0
- data/lib/get/commons/git.rb +41 -21
- data/lib/get/commons/http_client.rb +79 -0
- data/lib/get/subcommand/changelog/changelog.rb +55 -60
- data/lib/get/subcommand/command.rb +58 -6
- data/lib/get/subcommand/commit/commit.rb +58 -61
- data/lib/get/subcommand/commit/prompt.rb +25 -23
- data/lib/get/subcommand/complete/bash_completion.rb +12 -6
- data/lib/get/subcommand/complete/complete.rb +53 -42
- data/lib/get/subcommand/describe/change.rb +44 -27
- data/lib/get/subcommand/describe/describe.rb +103 -155
- data/lib/get/subcommand/describe/docker/docker.rb +55 -58
- data/lib/get/subcommand/describe/metadata.rb +16 -19
- data/lib/get/subcommand/describe/prerelease.rb +32 -14
- data/lib/get/subcommand/init/init.rb +43 -44
- data/lib/get/subcommand/license/license.rb +78 -56
- data/lib/get/subcommand/license/license_retriever.rb +38 -23
- data/lib/get/subcommand/tree/tree.rb +57 -48
- data/lib/get/version.rb +1 -3
- data/lib/get.rb +47 -34
- metadata +17 -15
@@ -18,15 +18,14 @@
|
|
18
18
|
# frozen_string_literal: true
|
19
19
|
|
20
20
|
require 'highline'
|
21
|
-
|
21
|
+
require_relative '../../commons/git'
|
22
22
|
|
23
|
-
# Module for asking to the user
|
23
|
+
# Module for asking to the user information about a commit message.
|
24
24
|
module PromptHandler
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@@custom_scopes = []
|
25
|
+
Common.module_instance_value(self, 'cli', 'HighLine.new')
|
26
|
+
Common.module_instance_attr(self, 'custom_values_initialized', false)
|
27
|
+
Common.module_instance_value(self, 'custom_types', [])
|
28
|
+
Common.module_instance_value(self, 'custom_scopes', [])
|
30
29
|
|
31
30
|
STRING_VALUE_VALIDATOR = /\s*\S+\s*/
|
32
31
|
BODY_END_DELIMITER = "\n\n\n"
|
@@ -46,14 +45,15 @@ module PromptHandler
|
|
46
45
|
|
47
46
|
def ask_for_type
|
48
47
|
extract_types_and_scopes
|
49
|
-
|
48
|
+
|
49
|
+
MOD_REF.cli.choose do |menu|
|
50
50
|
menu.flow = :columns_down
|
51
51
|
menu.prompt = 'Choose the type of your commit: '
|
52
|
-
DEFAULT_TYPES.union(
|
52
|
+
DEFAULT_TYPES.union(MOD_REF.custom_types).each do |type|
|
53
53
|
menu.choice(type.to_sym)
|
54
54
|
end
|
55
55
|
menu.choice('Create a new type (rarely needed)') do |_|
|
56
|
-
|
56
|
+
MOD_REF.cli.ask('Write the new type to use', String) do |question|
|
57
57
|
question.verify_match = true
|
58
58
|
question.validate = STRING_VALUE_VALIDATOR
|
59
59
|
end
|
@@ -63,14 +63,14 @@ module PromptHandler
|
|
63
63
|
|
64
64
|
def ask_for_scope
|
65
65
|
extract_types_and_scopes
|
66
|
-
|
66
|
+
MOD_REF.cli.choose do |menu|
|
67
67
|
menu.flow = :columns_down
|
68
68
|
menu.prompt = 'Choose the scope of your commit: '
|
69
|
-
|
69
|
+
MOD_REF.custom_scopes.each do |scope|
|
70
70
|
menu.choice(scope.to_sym)
|
71
71
|
end
|
72
72
|
menu.choice('Create a new scope') do |_|
|
73
|
-
|
73
|
+
MOD_REF.cli.ask('Write the new scope to use', String) do |question|
|
74
74
|
question.verify_match = true
|
75
75
|
question.validate = STRING_VALUE_VALIDATOR
|
76
76
|
end
|
@@ -80,13 +80,13 @@ module PromptHandler
|
|
80
80
|
end
|
81
81
|
|
82
82
|
def ask_for_breaking
|
83
|
-
|
83
|
+
MOD_REF.cli.agree('Does the commit contain a breaking change? (yes/no) ') do |question|
|
84
84
|
question.default = false
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
88
|
def ask_for_summary
|
89
|
-
|
89
|
+
MOD_REF.cli.ask('The summary of the commit:') do |question|
|
90
90
|
question.verify_match = true
|
91
91
|
question.validate = STRING_VALUE_VALIDATOR
|
92
92
|
end
|
@@ -94,31 +94,33 @@ module PromptHandler
|
|
94
94
|
|
95
95
|
def ask_for_message
|
96
96
|
# This method needs a special implementation as the body message can span multiple lines.
|
97
|
-
|
98
|
-
|
97
|
+
MOD_REF.cli.puts('The body of the commit (ends after 3 new lines):')
|
98
|
+
MOD_REF.cli.input.gets(BODY_END_DELIMITER)
|
99
99
|
end
|
100
100
|
|
101
101
|
private
|
102
102
|
|
103
103
|
FIRST_COMMIT = nil
|
104
104
|
|
105
|
+
Common.add_module_self_reference(self)
|
106
|
+
|
105
107
|
# This method tries to optimize input parsing by performing multiple operations in one go.
|
106
108
|
# So its complexity is a bit higher as it needs to make multiple checks.
|
107
109
|
# rubocop:disable Metrics/CyclomaticComplexity
|
108
110
|
def extract_types_and_scopes
|
109
|
-
return
|
111
|
+
return if MOD_REF.custom_values_initialized
|
110
112
|
|
111
113
|
Git.with_commit_list_from(FIRST_COMMIT) do |commit_list|
|
112
|
-
commit_list.map do |element|
|
114
|
+
commit_list.reverse.map do |element|
|
113
115
|
match = Git::CONVENTIONAL_COMMIT_REGEX.match(element)
|
114
116
|
next if match.nil?
|
115
117
|
|
116
|
-
type_already_added = DEFAULT_TYPES.include?(match[1].to_sym) ||
|
117
|
-
|
118
|
-
|
118
|
+
type_already_added = DEFAULT_TYPES.include?(match[1].to_sym) || MOD_REF.custom_types.include?(match[1])
|
119
|
+
MOD_REF.custom_types.append(match[1]) unless type_already_added
|
120
|
+
MOD_REF.custom_scopes.append(match[3]) unless match[3].nil? || MOD_REF.custom_scopes.include?(match[3])
|
119
121
|
end
|
120
122
|
end
|
121
|
-
|
123
|
+
MOD_REF.custom_values_initialized = true
|
122
124
|
end
|
123
125
|
# rubocop:enable Metrics/CyclomaticComplexity
|
124
126
|
end
|
@@ -22,12 +22,16 @@ module BashCompletion
|
|
22
22
|
def bash_completion(main_module, command_name)
|
23
23
|
generate_functions(main_module, command_name, INITIAL_LEVEL)
|
24
24
|
|
25
|
-
"#{HEADER}\n#{
|
25
|
+
"#{HEADER}\n#{MOD_REF.function_stack.reverse.join("\n")}"
|
26
26
|
end
|
27
27
|
|
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
|
@@ -37,7 +41,8 @@ module BashCompletion
|
|
37
41
|
#
|
38
42
|
HEADER
|
39
43
|
|
40
|
-
|
44
|
+
Common.add_module_self_reference(self)
|
45
|
+
Common.module_instance_value(self, 'function_stack', [])
|
41
46
|
|
42
47
|
def full_subcommand_name(base, name)
|
43
48
|
"#{base}_#{name}"
|
@@ -74,18 +79,19 @@ module BashCompletion
|
|
74
79
|
short_options = []
|
75
80
|
subcommands = []
|
76
81
|
|
77
|
-
command_class.
|
82
|
+
command_class.instance.option_parser.specs.each_value do |option|
|
78
83
|
long_options.push("--#{option.long}")
|
84
|
+
long_options.push("--no-#{option.long}") if option.flag? && !NOT_NEGABLE_OPTIONS.include?(option.long)
|
79
85
|
short_options.push("-#{option.short.nil? ? option.long[0] : option.short}") if option.short != :none
|
80
86
|
end
|
81
87
|
|
82
|
-
command_class.
|
88
|
+
command_class.instance.subcommands.each_key do |subcommand|
|
83
89
|
subcommands.push(subcommand.to_s)
|
84
90
|
end
|
85
91
|
|
86
|
-
|
92
|
+
MOD_REF.function_stack.push(completion_function_definition(name, level, long_options, short_options, subcommands))
|
87
93
|
|
88
|
-
command_class.
|
94
|
+
command_class.instance.subcommands.each do |element|
|
89
95
|
generate_functions(element[1].class, full_subcommand_name(name, element[0].to_s), level + 1)
|
90
96
|
end
|
91
97
|
end
|
@@ -17,66 +17,77 @@
|
|
17
17
|
|
18
18
|
# frozen_string_literal: true
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
require 'get'
|
20
|
+
require_relative '../../commons/common'
|
21
|
+
require_relative '../command'
|
22
|
+
require_relative './bash_completion'
|
23
|
+
require_relative '../../../get'
|
25
24
|
|
26
25
|
# Class length is disabled as most of its length is given by formatting.
|
27
26
|
# rubocop:disable Metrics/ClassLength
|
28
27
|
# Subcommand, prints the bash completion script.
|
29
28
|
class Complete < Command
|
30
|
-
def self.command
|
31
|
-
@@command ||= new
|
32
|
-
@@command
|
33
|
-
end
|
34
|
-
|
35
|
-
private_class_method :new
|
36
|
-
|
37
29
|
private
|
38
30
|
|
39
31
|
include BashCompletion
|
40
32
|
|
41
|
-
@@command = nil
|
42
|
-
|
43
|
-
@@usage = 'complete -h|(<subcommand> [<subcommand-options])'
|
44
|
-
@@description = 'Print the shell completion script.'
|
45
|
-
@@subcommands = {}
|
46
|
-
# This block is Optimist configuration. It is as long as the number of options of the command.
|
47
|
-
# rubocop:disable Metrics/BlockLength
|
48
|
-
@@option_parser = Optimist::Parser.new do
|
49
|
-
subcommand_max_length = @@subcommands.keys.map { |k| k.to_s.length }.max
|
50
|
-
subcommand_section = <<~SUBCOMMANDS unless @@subcommands.empty?
|
51
|
-
Subcommands:
|
52
|
-
#{@@subcommands.keys.map { |k| " #{k.to_s.ljust(subcommand_max_length)} => #{@@subcommands[k].description}" }.join("\n")}
|
53
|
-
SUBCOMMANDS
|
54
|
-
usage @@usage
|
55
|
-
synopsis @@description + (subcommand_section.nil? ? '' : "\n") + subcommand_section.to_s
|
56
|
-
opt :shell,
|
57
|
-
'Select the type of shell of which the completion will be generated.',
|
58
|
-
{ type: :string, default: 'bash' }
|
59
|
-
educate_on_error
|
60
|
-
stop_on @@subcommands.keys.map(&:to_s)
|
61
|
-
end
|
62
|
-
# rubocop:enable Metrics/BlockLength
|
63
|
-
|
64
33
|
def initialize
|
65
|
-
super(
|
66
|
-
@
|
67
|
-
|
68
|
-
|
69
|
-
|
34
|
+
super() do
|
35
|
+
@usage = 'complete -h|(<subcommand> [<subcommand-options])'
|
36
|
+
@description = 'Print the shell completion script. ' \
|
37
|
+
'Run \'get complete --info\' to learn how to install the completion.'
|
38
|
+
@subcommands = {}
|
70
39
|
@completions = {
|
71
|
-
bash:
|
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
|
+
}
|
72
47
|
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def setup_option_parser
|
54
|
+
@option_parser = Optimist::Parser.new(
|
55
|
+
@usage,
|
56
|
+
full_description,
|
57
|
+
stop_condition
|
58
|
+
) do |usage_header, description, stop_condition|
|
59
|
+
usage usage_header
|
60
|
+
synopsis description
|
61
|
+
opt :shell,
|
62
|
+
'Select the type of shell of which the completion will be generated.',
|
63
|
+
{ type: :string, default: 'bash' }
|
64
|
+
opt :info,
|
65
|
+
'Print the instructions to install the completion for the selected shell.',
|
66
|
+
{ short: :none }
|
67
|
+
educate_on_error
|
68
|
+
stop_on stop_condition
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def setup_action
|
73
|
+
@action = lambda do
|
74
|
+
@options = Common.with_subcommand_exception_handling @option_parser do
|
75
|
+
@option_parser.parse
|
76
|
+
end
|
73
77
|
|
74
78
|
selected_shell = @options[:shell].to_sym
|
75
79
|
|
80
|
+
print_info_and_exit(selected_shell) if @options[:info]
|
81
|
+
|
76
82
|
Common.error "Completion for shell '#{selected_shell}' not available." unless @completions.key?(selected_shell)
|
77
83
|
|
78
|
-
puts @completions[selected_shell].call
|
84
|
+
puts @completions[selected_shell][:generator].call
|
79
85
|
end
|
80
86
|
end
|
87
|
+
|
88
|
+
def print_info_and_exit(selected_shell)
|
89
|
+
puts @completions[selected_shell][:info]
|
90
|
+
exit 0
|
91
|
+
end
|
81
92
|
end
|
82
93
|
# rubocop:enable Metrics/ClassLength
|
@@ -22,50 +22,67 @@ module ChangeHandler
|
|
22
22
|
# Array with change types in ascending order of importance.
|
23
23
|
CHANGE_TYPE = %i[NONE PATCH MINOR MAJOR].freeze
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
DEFAULT_MAJOR_TRIGGER = 'is_breaking'
|
26
|
+
DEFAULT_MINOR_TRIGGER = "type == 'feat'"
|
27
|
+
DEFAULT_PATCH_TRIGGER = "type == 'fix'"
|
28
28
|
|
29
|
-
|
29
|
+
Common.module_instance_attr(self, 'major_trigger', :DEFAULT_MAJOR_TRIGGER)
|
30
|
+
Common.module_instance_attr(self, 'minor_trigger', :DEFAULT_MINOR_TRIGGER)
|
31
|
+
Common.module_instance_attr(self, 'patch_trigger', :DEFAULT_PATCH_TRIGGER)
|
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
|
+
|
54
|
+
def greatest_change_in(commit_list)
|
55
|
+
commit_list
|
56
|
+
.grep(Git::CONVENTIONAL_COMMIT_REGEX)
|
57
|
+
.map { |commit| to_change(commit) }
|
58
|
+
.max { |a, b| CHANGE_TYPE.index(a) <=> CHANGE_TYPE.index(b) }
|
59
|
+
end
|
30
60
|
|
31
61
|
# In this block method arguments can be used by user.
|
32
62
|
# Also `eval` is needed to allow users to define their custom triggers.
|
33
63
|
# rubocop:disable Lint/UnusedMethodArgument
|
34
64
|
# rubocop:disable Security/Eval
|
35
65
|
def triggers_major?(type, scope, is_breaking)
|
36
|
-
eval(
|
66
|
+
eval(ChangeHandler.major_trigger)
|
37
67
|
end
|
38
68
|
|
39
69
|
def triggers_minor?(type, scope)
|
40
|
-
eval(
|
70
|
+
eval(ChangeHandler.minor_trigger)
|
41
71
|
end
|
42
72
|
|
43
73
|
def triggers_patch?(type, scope)
|
44
|
-
eval(
|
74
|
+
eval(ChangeHandler.patch_trigger)
|
45
75
|
end
|
46
76
|
# rubocop:enable Lint/UnusedMethodArgument
|
47
77
|
# rubocop:enable Security/Eval
|
48
78
|
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
return :MAJOR if ChangeHandler.triggers_major?(groups[1], groups[3], !groups[4].nil?)
|
56
|
-
return :MINOR if ChangeHandler.triggers_minor?(groups[1], groups[2])
|
57
|
-
return :PATCH if ChangeHandler.triggers_patch?(groups[1], groups[2])
|
58
|
-
|
59
|
-
:NONE
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
public
|
79
|
+
# Convert the string (as a conventional commit string) into a change type.
|
80
|
+
def to_change(commit_message)
|
81
|
+
groups = Git::CONVENTIONAL_COMMIT_REGEX.match(commit_message)
|
82
|
+
return :MAJOR if triggers_major?(groups[1], groups[3], !groups[4].nil?)
|
83
|
+
return :MINOR if triggers_minor?(groups[1], groups[3])
|
84
|
+
return :PATCH if triggers_patch?(groups[1], groups[3])
|
64
85
|
|
65
|
-
|
66
|
-
commit_list
|
67
|
-
.grep(Git::CONVENTIONAL_COMMIT_REGEX)
|
68
|
-
.map(&:to_change)
|
69
|
-
.max { |a, b| CHANGE_TYPE.index(a) <=> CHANGE_TYPE.index(b) }
|
86
|
+
:NONE
|
70
87
|
end
|
71
88
|
end
|