git_toolbox 0.4.1 → 0.6.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/lib/get/{common.rb → commons/common.rb} +2 -20
- data/lib/get/commons/git.rb +59 -0
- data/lib/get/subcommand/changelog/changelog.rb +165 -0
- data/lib/get/subcommand/commit/commit.rb +10 -8
- data/lib/get/subcommand/commit/prompt.rb +3 -2
- data/lib/get/subcommand/complete/bash_completion.rb +92 -0
- data/lib/get/subcommand/complete/complete.rb +82 -0
- data/lib/get/subcommand/describe/change.rb +2 -2
- data/lib/get/subcommand/describe/describe.rb +15 -22
- data/lib/get/subcommand/describe/docker/docker.rb +6 -4
- data/lib/get/subcommand/init/init.rb +10 -10
- data/lib/get/subcommand/license/license.rb +107 -0
- data/lib/get/subcommand/license/license_retriever.rb +87 -0
- data/lib/get/subcommand/license/offline_licenses/Apache License 2.0/LICENSE +201 -0
- data/lib/get/subcommand/license/offline_licenses/GNU Affero General Public License v3.0/LICENSE +661 -0
- data/lib/get/subcommand/license/offline_licenses/GNU General Public License v3.0/LICENSE +674 -0
- data/lib/get/subcommand/license/offline_licenses/MIT License/LICENSE +21 -0
- data/lib/get/subcommand/license/offline_licenses/Mozilla Public License 2.0/LICENSE +373 -0
- data/lib/get/version.rb +1 -1
- data/lib/get.rb +7 -1
- metadata +14 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15a670824481b1eacf235aeb9fefced3bc5f6febb2674ff11d272013aad665d5
|
4
|
+
data.tar.gz: 54be78886d9fa0ec1a2650cbcfbcc6028c7cc0b2f54f85398aa8649d2061d22b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ac823eedff5a76c6808ff2615a2a1f1fce8ed1508a868e0f73fdb66616ac23dc2344412d842c775700850a2290d075a495a304beea99ceccc0e74236102d52b
|
7
|
+
data.tar.gz: bd690477114dbf9ccf127ebb89531ca8204ccca483a2fe2fa87a97ff841cac9ae99dbd78b6793f46b68a3bd384de5b51e7baec1b3ed7a54d14c7f67fffc4fc90
|
@@ -17,17 +17,10 @@
|
|
17
17
|
|
18
18
|
# frozen_string_literal: true
|
19
19
|
|
20
|
+
require 'English'
|
21
|
+
|
20
22
|
# Utility module
|
21
23
|
module Common
|
22
|
-
# Groups: 1 = type, 2 = scope with (), 3 = scope, 4 = breaking change
|
23
|
-
CONVENTIONAL_COMMIT_REGEX = /^(\w+)(\((\w+)\))?(!)?:.*/
|
24
|
-
|
25
|
-
# Check if the command is called while in a git repository.
|
26
|
-
# If the command fails, it is assumed to not be in a git repository.
|
27
|
-
def self.in_git_repo?
|
28
|
-
system('git rev-parse --is-inside-work-tree &>/dev/null')
|
29
|
-
end
|
30
|
-
|
31
24
|
# Print an error message and optionally run a block.
|
32
25
|
# Stdout becomes stderr, so every print is performed to stderr.
|
33
26
|
# This behavior is wanted as this method is called on errors.
|
@@ -48,17 +41,6 @@ module Common
|
|
48
41
|
# Version is not needed in this command
|
49
42
|
end
|
50
43
|
|
51
|
-
# Run a block of code with the list of commits from the given version as an argument.
|
52
|
-
# If the block is not given, this method is a nop.
|
53
|
-
def self.with_commit_list_from(version = nil, &block)
|
54
|
-
return unless block_given?
|
55
|
-
|
56
|
-
commits_from_version =
|
57
|
-
`git --no-pager log --oneline --pretty=format:%s #{version.nil? ? '' : "^#{version}"} HEAD`
|
58
|
-
.split("\n")
|
59
|
-
block.call(commits_from_version)
|
60
|
-
end
|
61
|
-
|
62
44
|
# Print the given message, execute a block if given,
|
63
45
|
# and exit the program with the given exit status.
|
64
46
|
# If exit_status is not 0, the stdout is redirected to stderr.
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Get is a toolbox based on git which simplifies the adoption of conventions and some git commands.
|
2
|
+
# Copyright (C) 2023 Alex Speranza
|
3
|
+
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program and the additional permissions granted by
|
16
|
+
# the Lesser GPL. If not, see <https://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# frozen_string_literal: true
|
19
|
+
|
20
|
+
require 'English'
|
21
|
+
require 'get/commons/common'
|
22
|
+
|
23
|
+
# Utility module
|
24
|
+
module Git
|
25
|
+
# Groups: 1 = type, 2 = scope with (), 3 = scope, 4 = breaking change, 5 = summary
|
26
|
+
CONVENTIONAL_COMMIT_REGEX = /^(\w+)(\((\w+)\))?(!)?:(.*)/
|
27
|
+
|
28
|
+
# Check if the command is called while in a git repository.
|
29
|
+
# If the command fails, it is assumed to not be in a git repository.
|
30
|
+
def self.in_repo?
|
31
|
+
system('git rev-parse --is-inside-work-tree &>/dev/null')
|
32
|
+
case $CHILD_STATUS.exitstatus
|
33
|
+
when 0 then true
|
34
|
+
when 127 then Common.error '"git" is not installed.'
|
35
|
+
else false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Run a block of code with the list of commits from the given version as an argument.
|
40
|
+
# If the block is not given, this method is a nop.
|
41
|
+
def self.with_commit_list_from(version = nil, &block)
|
42
|
+
return unless block_given?
|
43
|
+
|
44
|
+
commits_from_version =
|
45
|
+
`git --no-pager log --oneline --pretty=format:%s #{version.nil? ? '' : "^#{version}"} HEAD`
|
46
|
+
.split("\n")
|
47
|
+
block.call(commits_from_version)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the last version and caches it for the next calls.
|
51
|
+
def self.last_version
|
52
|
+
@@last_version ||= `git describe --tags --abbrev=0`.strip
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the last release and caches it for the next calls.
|
56
|
+
def self.last_release
|
57
|
+
@@last_release ||= `git --no-pager tag --list | sed 's/+/_/' | sort -V | sed 's/_/+/' | tail -n 1`.strip
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# Get is a toolbox based on git which simplifies the adoption of conventions and some git commands.
|
2
|
+
# Copyright (C) 2023 Alex Speranza
|
3
|
+
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program and the additional permissions granted by
|
16
|
+
# the Lesser GPL. If not, see <https://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# frozen_string_literal: true
|
19
|
+
|
20
|
+
require 'English'
|
21
|
+
require 'get/commons/common'
|
22
|
+
require 'get/commons/git'
|
23
|
+
require 'get/subcommand/command'
|
24
|
+
|
25
|
+
# Class length is disabled as most of its length is given by formatting.
|
26
|
+
# rubocop:disable Metrics/ClassLength
|
27
|
+
# Subcommand, generates a changelog.
|
28
|
+
class Changelog < Command
|
29
|
+
def self.command
|
30
|
+
@@command ||= new
|
31
|
+
@@command
|
32
|
+
end
|
33
|
+
|
34
|
+
private_class_method :new
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
UNDEFINED_SCOPE = 'other'
|
39
|
+
MARKDOWN_FORMAT = {
|
40
|
+
title: '# %s',
|
41
|
+
type: '## %s',
|
42
|
+
scope: '### %s',
|
43
|
+
list: '%s',
|
44
|
+
item: '- %s'
|
45
|
+
}.freeze
|
46
|
+
|
47
|
+
@@command = nil
|
48
|
+
|
49
|
+
@@usage = 'changelog -h|(<subcommand> [<subcommand-options])'
|
50
|
+
@@description = 'Generate a changelog. Format options require a "%s" where the content must be.'
|
51
|
+
@@subcommands = {}
|
52
|
+
# This block is Optimist configuration. It is as long as the number of options of the command.
|
53
|
+
# rubocop:disable Metrics/BlockLength
|
54
|
+
@@option_parser = Optimist::Parser.new do
|
55
|
+
subcommand_max_length = @@subcommands.keys.map { |k| k.to_s.length }.max
|
56
|
+
subcommand_section = <<~SUBCOMMANDS unless @@subcommands.empty?
|
57
|
+
Subcommands:
|
58
|
+
#{@@subcommands.keys.map { |k| " #{k.to_s.ljust(subcommand_max_length)} => #{@@subcommands[k].description}" }.join("\n")}
|
59
|
+
SUBCOMMANDS
|
60
|
+
usage @@usage
|
61
|
+
synopsis @@description + (subcommand_section.nil? ? '' : "\n") + subcommand_section.to_s
|
62
|
+
opt :latest,
|
63
|
+
'Generate the changelog from the latest version rather than the latest release'
|
64
|
+
opt :title_format,
|
65
|
+
'Set the symbol for the title.',
|
66
|
+
{ type: :string, short: 'T', default: '# %s' }
|
67
|
+
opt :type_format,
|
68
|
+
'Set the symbol for the commit types.',
|
69
|
+
{ type: :string, short: 't', default: '= %s' }
|
70
|
+
opt :scope_format,
|
71
|
+
'Set the symbol for the commit scopes.',
|
72
|
+
{ type: :string, short: 's', default: '- %s' }
|
73
|
+
opt :list_format,
|
74
|
+
'Set the symbol for lists.',
|
75
|
+
{ type: :string, short: 'l', default: '%s' }
|
76
|
+
opt :item_format,
|
77
|
+
'Set the symbol for list items.',
|
78
|
+
{ type: :string, short: 'i', default: '* %s' }
|
79
|
+
opt :markdown,
|
80
|
+
'Shortcut for `-T "# %s" -t "## %s" -s "### %s" -l "%s" -i "- %s"`. ' \
|
81
|
+
'Can be overwritten by the single options.'
|
82
|
+
educate_on_error
|
83
|
+
stop_on @@subcommands.keys.map(&:to_s)
|
84
|
+
end
|
85
|
+
# rubocop:enable Metrics/BlockLength
|
86
|
+
|
87
|
+
def initialize
|
88
|
+
super(@@usage, @@description) do
|
89
|
+
@options = Common.with_subcommand_exception_handling @@option_parser do
|
90
|
+
@@option_parser.parse
|
91
|
+
end
|
92
|
+
Common.error 'changelog need to be run inside a git repository' unless Git.in_repo?
|
93
|
+
@format = {}
|
94
|
+
set_format
|
95
|
+
|
96
|
+
puts changelog_from(@options[:latest] ? Git.last_version : Git.last_release)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def set_format
|
101
|
+
%w[title type scope list item].each do |element|
|
102
|
+
@format[element.to_sym] = if @options[:markdown] && !@options["#{element}_given".to_sym]
|
103
|
+
MARKDOWN_FORMAT[element.to_sym]
|
104
|
+
else
|
105
|
+
unless @options["#{element}_format".to_sym].include? '%s'
|
106
|
+
Common.error "The given format for '#{element}' must contain '%s'."
|
107
|
+
end
|
108
|
+
@options["#{element}_format".to_sym]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def changelog_from(version)
|
114
|
+
commit_map = {}
|
115
|
+
|
116
|
+
Git.with_commit_list_from(version) do |list|
|
117
|
+
list.each do |element|
|
118
|
+
match_result = Git::CONVENTIONAL_COMMIT_REGEX.match(element)
|
119
|
+
temp_hash = {
|
120
|
+
match_result[1] => {
|
121
|
+
(match_result[3] || UNDEFINED_SCOPE) => [match_result[5].strip.capitalize]
|
122
|
+
}
|
123
|
+
}
|
124
|
+
commit_map.merge!(temp_hash) do |_key, old_value, new_value|
|
125
|
+
old_value.merge(new_value) do |_inner_key, old_array, new_array|
|
126
|
+
old_array + new_array
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
format_changelog(version, commit_map)
|
133
|
+
end
|
134
|
+
|
135
|
+
def format_changelog(from_version, changelog)
|
136
|
+
formatted_features = changelog.key?('feat') ? [format_type('feat', changelog['feat'])] : []
|
137
|
+
formatted_fixes = changelog.key?('fix') ? [format_type('fix', changelog['fix'])] : []
|
138
|
+
|
139
|
+
formatted_types = []
|
140
|
+
changelog.except('feat', 'fix').each { |key, value| formatted_types.push(format_type(key, value)) }
|
141
|
+
<<~CHANGELOG
|
142
|
+
#{@format[:title].sub('%s', "Changelog from version #{from_version}")}
|
143
|
+
#{(formatted_features + formatted_fixes + formatted_types).join("\n").strip}
|
144
|
+
CHANGELOG
|
145
|
+
end
|
146
|
+
|
147
|
+
def format_type(type, scopes)
|
148
|
+
formatted_scopes = []
|
149
|
+
scopes.each { |key, value| formatted_scopes.push(format_scope(key, value)) }
|
150
|
+
<<~TYPE
|
151
|
+
#{@format[:type].sub('%s', type.to_s)}
|
152
|
+
#{formatted_scopes.join("\n").strip}
|
153
|
+
TYPE
|
154
|
+
end
|
155
|
+
|
156
|
+
def format_scope(scope, commits)
|
157
|
+
formatted_commits = []
|
158
|
+
commits.each { |element| formatted_commits.push(@format[:item].sub('%s', element)) }
|
159
|
+
<<~SCOPE
|
160
|
+
#{@format[:scope].sub('%s', scope.to_s)}
|
161
|
+
#{@format[:list].sub('%s', formatted_commits.join("\n"))}
|
162
|
+
SCOPE
|
163
|
+
end
|
164
|
+
end
|
165
|
+
# rubocop:enable Metrics/ClassLength
|
@@ -18,7 +18,8 @@
|
|
18
18
|
# frozen_string_literal: true
|
19
19
|
|
20
20
|
require 'English'
|
21
|
-
require 'get/common'
|
21
|
+
require 'get/commons/common'
|
22
|
+
require 'get/commons/git'
|
22
23
|
require 'get/subcommand/command'
|
23
24
|
require 'get/subcommand/commit/prompt'
|
24
25
|
|
@@ -40,17 +41,18 @@ class Commit < Command
|
|
40
41
|
@@command = nil
|
41
42
|
|
42
43
|
@@usage = 'commit -h|(<subcommand> [<subcommand-options])'
|
43
|
-
@@description = 'Create a new semantic commit'
|
44
|
+
@@description = 'Create a new semantic commit.'
|
44
45
|
@@subcommands = {}
|
45
46
|
# This block is Optimist configuration. It is as long as the number of options of the command.
|
46
47
|
# rubocop:disable Metrics/BlockLength
|
47
|
-
@@
|
48
|
+
@@option_parser = Optimist::Parser.new do
|
48
49
|
subcommand_max_length = @@subcommands.keys.map { |k| k.to_s.length }.max
|
49
|
-
|
50
|
-
synopsis <<~SUBCOMMANDS unless @@subcommands.empty?
|
50
|
+
subcommand_section = <<~SUBCOMMANDS unless @@subcommands.empty?
|
51
51
|
Subcommands:
|
52
52
|
#{@@subcommands.keys.map { |k| " #{k.to_s.ljust(subcommand_max_length)} => #{@@subcommands[k].description}" }.join("\n")}
|
53
53
|
SUBCOMMANDS
|
54
|
+
usage @@usage
|
55
|
+
synopsis @@description + (subcommand_section.nil? ? '' : "\n") + subcommand_section.to_s
|
54
56
|
opt :type,
|
55
57
|
'Define the type of the commit. Enabling this option skips the type selection.',
|
56
58
|
{ type: :string }
|
@@ -75,9 +77,9 @@ class Commit < Command
|
|
75
77
|
|
76
78
|
def initialize
|
77
79
|
super(@@usage, @@description) do
|
78
|
-
Common.error 'commit need to be run inside a git repository' unless
|
79
|
-
@options = Common.with_subcommand_exception_handling @@
|
80
|
-
@@
|
80
|
+
Common.error 'commit need to be run inside a git repository' unless Git.in_repo?
|
81
|
+
@options = Common.with_subcommand_exception_handling @@option_parser do
|
82
|
+
@@option_parser.parse
|
81
83
|
end
|
82
84
|
|
83
85
|
message = full_commit_message
|
@@ -18,6 +18,7 @@
|
|
18
18
|
# frozen_string_literal: true
|
19
19
|
|
20
20
|
require 'highline'
|
21
|
+
require 'get/commons/git'
|
21
22
|
|
22
23
|
# Module for asking to the user informations about a commit message.
|
23
24
|
module PromptHandler
|
@@ -107,9 +108,9 @@ module PromptHandler
|
|
107
108
|
def extract_types_and_scopes
|
108
109
|
return unless @@custom_values_initialized.nil?
|
109
110
|
|
110
|
-
|
111
|
+
Git.with_commit_list_from(FIRST_COMMIT) do |commit_list|
|
111
112
|
commit_list.map do |element|
|
112
|
-
match =
|
113
|
+
match = Git::CONVENTIONAL_COMMIT_REGEX.match(element)
|
113
114
|
next if match.nil?
|
114
115
|
|
115
116
|
type_already_added = DEFAULT_TYPES.include?(match[1].to_sym) || @@custom_types.include?(match[1])
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# Get is a toolbox based on git which simplifies the adoption of conventions and some git commands.
|
2
|
+
# Copyright (C) 2023 Alex Speranza
|
3
|
+
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program and the additional permissions granted by
|
16
|
+
# the Lesser GPL. If not, see <https://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# frozen_string_literal: true
|
19
|
+
|
20
|
+
# Module with bash completion generation functions
|
21
|
+
module BashCompletion
|
22
|
+
def bash_completion(main_module, command_name)
|
23
|
+
generate_functions(main_module, command_name, INITIAL_LEVEL)
|
24
|
+
|
25
|
+
"#{HEADER}\n#{@@function_stack.reverse.join("\n")}"
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
INITIAL_LEVEL = 1
|
31
|
+
|
32
|
+
HEADER = <<~HEADER
|
33
|
+
#!/usr/bin/env bash
|
34
|
+
#
|
35
|
+
# This file has been generated by `get complete`.
|
36
|
+
# The script structure was inspired by https://opensource.com/article/18/3/creating-bash-completion-script
|
37
|
+
#
|
38
|
+
HEADER
|
39
|
+
|
40
|
+
@@function_stack = []
|
41
|
+
|
42
|
+
def full_subcommand_name(base, name)
|
43
|
+
"#{base}_#{name}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def completion_function_definition(name, level, long_options, short_options, subcommands)
|
47
|
+
<<~FUNCTION
|
48
|
+
_#{name}_completion()
|
49
|
+
{
|
50
|
+
if [ "${COMP_CWORD}" -eq "#{level}" ] ; then
|
51
|
+
COMPREPLY=($(compgen -W "#{(long_options | short_options | subcommands).join(' ')}" -- "${COMP_WORDS[#{level}]}"))
|
52
|
+
else
|
53
|
+
case "${COMP_WORDS[#{level}]}" in
|
54
|
+
#{subcommands.map { |element| subcommand_case_completion(name, element) }.join("\n")}
|
55
|
+
*)
|
56
|
+
COMPREPLY=()
|
57
|
+
;;
|
58
|
+
esac
|
59
|
+
fi
|
60
|
+
}
|
61
|
+
FUNCTION
|
62
|
+
end
|
63
|
+
|
64
|
+
def subcommand_case_completion(base, name)
|
65
|
+
<<~CASE
|
66
|
+
"#{name}")
|
67
|
+
_#{full_subcommand_name(base, name)}_completion
|
68
|
+
;;
|
69
|
+
CASE
|
70
|
+
end
|
71
|
+
|
72
|
+
def generate_functions(command_class, name, level)
|
73
|
+
long_options = []
|
74
|
+
short_options = []
|
75
|
+
subcommands = []
|
76
|
+
|
77
|
+
command_class.class_variable_get(:@@option_parser).specs.each_value do |option|
|
78
|
+
long_options.push("--#{option.long}")
|
79
|
+
short_options.push("-#{option.short.nil? ? option.long[0] : option.short}") if option.short != :none
|
80
|
+
end
|
81
|
+
|
82
|
+
command_class.class_variable_get(:@@subcommands).each_key do |subcommand|
|
83
|
+
subcommands.push(subcommand.to_s)
|
84
|
+
end
|
85
|
+
|
86
|
+
@@function_stack.push(completion_function_definition(name, level, long_options, short_options, subcommands))
|
87
|
+
|
88
|
+
command_class.class_variable_get(:@@subcommands).each do |element|
|
89
|
+
generate_functions(element[1].class, full_subcommand_name(name, element[0].to_s), level + 1)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# Get is a toolbox based on git which simplifies the adoption of conventions and some git commands.
|
2
|
+
# Copyright (C) 2023 Alex Speranza
|
3
|
+
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program and the additional permissions granted by
|
16
|
+
# the Lesser GPL. If not, see <https://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# frozen_string_literal: true
|
19
|
+
|
20
|
+
require 'English'
|
21
|
+
require 'get/commons/common'
|
22
|
+
require 'get/subcommand/command'
|
23
|
+
require 'get/subcommand/complete/bash_completion'
|
24
|
+
require 'get'
|
25
|
+
|
26
|
+
# Class length is disabled as most of its length is given by formatting.
|
27
|
+
# rubocop:disable Metrics/ClassLength
|
28
|
+
# Subcommand, prints the bash completion script.
|
29
|
+
class Complete < Command
|
30
|
+
def self.command
|
31
|
+
@@command ||= new
|
32
|
+
@@command
|
33
|
+
end
|
34
|
+
|
35
|
+
private_class_method :new
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
include BashCompletion
|
40
|
+
|
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
|
+
def initialize
|
65
|
+
super(@@usage, @@description) do
|
66
|
+
@options = Common.with_subcommand_exception_handling @@option_parser do
|
67
|
+
@@option_parser.parse
|
68
|
+
end
|
69
|
+
|
70
|
+
@completions = {
|
71
|
+
bash: proc { bash_completion(Get, 'get') }
|
72
|
+
}
|
73
|
+
|
74
|
+
selected_shell = @options[:shell].to_sym
|
75
|
+
|
76
|
+
Common.error "Completion for shell '#{selected_shell}' not available." unless @completions.key?(selected_shell)
|
77
|
+
|
78
|
+
puts @completions[selected_shell].call
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
# rubocop:enable Metrics/ClassLength
|
@@ -51,7 +51,7 @@ module ChangeHandler
|
|
51
51
|
class ::String
|
52
52
|
# Convert the string (as a conventional commit string) into a change type.
|
53
53
|
def to_change
|
54
|
-
groups =
|
54
|
+
groups = Git::CONVENTIONAL_COMMIT_REGEX.match(self)
|
55
55
|
return :MAJOR if ChangeHandler.triggers_major?(groups[1], groups[3], !groups[4].nil?)
|
56
56
|
return :MINOR if ChangeHandler.triggers_minor?(groups[1], groups[2])
|
57
57
|
return :PATCH if ChangeHandler.triggers_patch?(groups[1], groups[2])
|
@@ -64,7 +64,7 @@ module ChangeHandler
|
|
64
64
|
|
65
65
|
def greatest_change_in(commit_list)
|
66
66
|
commit_list
|
67
|
-
.grep(
|
67
|
+
.grep(Git::CONVENTIONAL_COMMIT_REGEX)
|
68
68
|
.map(&:to_change)
|
69
69
|
.max { |a, b| CHANGE_TYPE.index(a) <=> CHANGE_TYPE.index(b) }
|
70
70
|
end
|
@@ -17,6 +17,8 @@
|
|
17
17
|
|
18
18
|
# frozen_string_literal: true
|
19
19
|
|
20
|
+
require 'get/commons/common'
|
21
|
+
require 'get/commons/git'
|
20
22
|
require 'get/subcommand/command'
|
21
23
|
require 'get/subcommand/describe/change'
|
22
24
|
require 'get/subcommand/describe/prerelease'
|
@@ -50,19 +52,20 @@ class Describe < Command
|
|
50
52
|
/x
|
51
53
|
|
52
54
|
@@usage = 'describe -h|(<subcommand> [<subcommand-options])'
|
53
|
-
@@description = 'Describe the current git repository with semantic version'
|
55
|
+
@@description = 'Describe the current git repository with semantic version.'
|
54
56
|
@@subcommands = {
|
55
57
|
docker: DescribeDocker.command,
|
56
58
|
}
|
57
59
|
# This block is Optimist configuration. It is as long as the number of options of the command.
|
58
60
|
# rubocop:disable Metrics/BlockLength
|
59
|
-
@@
|
61
|
+
@@option_parser = Optimist::Parser.new do
|
60
62
|
subcommand_max_length = @@subcommands.keys.map { |k| k.to_s.length }.max
|
61
|
-
|
62
|
-
synopsis <<~SUBCOMMANDS unless @@subcommands.empty?
|
63
|
+
subcommand_section = <<~SUBCOMMANDS unless @@subcommands.empty?
|
63
64
|
Subcommands:
|
64
65
|
#{@@subcommands.keys.map { |k| " #{k.to_s.ljust(subcommand_max_length)} => #{@@subcommands[k].description}" }.join("\n")}
|
65
66
|
SUBCOMMANDS
|
67
|
+
usage @@usage
|
68
|
+
synopsis @@description + (subcommand_section.nil? ? '' : "\n") + subcommand_section.to_s
|
66
69
|
opt :prerelease,
|
67
70
|
'Describe a prerelease rather than a release',
|
68
71
|
short: :none
|
@@ -109,9 +112,9 @@ class Describe < Command
|
|
109
112
|
|
110
113
|
def initialize
|
111
114
|
super(@@usage, @@description) do
|
112
|
-
Common.error 'describe need to be run inside a git repository' unless
|
113
|
-
@options = Common.with_subcommand_exception_handling @@
|
114
|
-
@@
|
115
|
+
Common.error 'describe need to be run inside a git repository' unless Git.in_repo?
|
116
|
+
@options = Common.with_subcommand_exception_handling @@option_parser do
|
117
|
+
@@option_parser.parse
|
115
118
|
end
|
116
119
|
set_options
|
117
120
|
|
@@ -141,9 +144,9 @@ class Describe < Command
|
|
141
144
|
end
|
142
145
|
|
143
146
|
def describe_current_commit
|
144
|
-
return last_version if
|
147
|
+
return Git.last_version if Git.with_commit_list_from(Git.last_version, &:empty?)
|
145
148
|
|
146
|
-
puts "Last version: #{last_version}" if @options[:diff]
|
149
|
+
puts "Last version: #{Git.last_version}" if @options[:diff]
|
147
150
|
|
148
151
|
current_commit_version = next_release
|
149
152
|
create_signed_tag(current_commit_version) if @options[:create_tag]
|
@@ -153,9 +156,9 @@ class Describe < Command
|
|
153
156
|
|
154
157
|
def next_release
|
155
158
|
if @options[:prerelease]
|
156
|
-
prepare_prerelease_tag(last_release, last_version)
|
159
|
+
prepare_prerelease_tag(Git.last_release, Git.last_version)
|
157
160
|
else
|
158
|
-
prepare_release_tag(last_release)
|
161
|
+
prepare_release_tag(Git.last_release)
|
159
162
|
end + metadata
|
160
163
|
end
|
161
164
|
|
@@ -172,20 +175,10 @@ class Describe < Command
|
|
172
175
|
"-#{updated_prerelease(base_version_match_data[5], need_reset: base_version_match_data[1] != new_stable_version)}"
|
173
176
|
end
|
174
177
|
|
175
|
-
# Returns the last version and caches it for the next calls.
|
176
|
-
def last_version
|
177
|
-
@last_version ||= `git describe --tags --abbrev=0`.strip
|
178
|
-
end
|
179
|
-
|
180
|
-
# Returns the last release and caches it for the next calls.
|
181
|
-
def last_release
|
182
|
-
@last_release ||= `git --no-pager tag --list | sed 's/+/_/' | sort -V | sed 's/_/+/' | tail -n 1`.strip
|
183
|
-
end
|
184
|
-
|
185
178
|
def updated_stable_version(stable_version)
|
186
179
|
return DEFAULT_RELEASE_VERSION if stable_version.nil?
|
187
180
|
|
188
|
-
greatest_change_from_stable_version =
|
181
|
+
greatest_change_from_stable_version = Git.with_commit_list_from(stable_version) do |commits_from_version|
|
189
182
|
greatest_change_in(commits_from_version)
|
190
183
|
end
|
191
184
|
split_version = stable_version.split('.')
|
@@ -17,6 +17,8 @@
|
|
17
17
|
|
18
18
|
# frozen_string_literal: true
|
19
19
|
|
20
|
+
require 'get/commons/common'
|
21
|
+
require 'get/commons/git'
|
20
22
|
require 'get/subcommand/command'
|
21
23
|
|
22
24
|
# Class length is disabled as most of its length is given by formatting.
|
@@ -41,7 +43,7 @@ class DescribeDocker < Command
|
|
41
43
|
@@subcommands = {}
|
42
44
|
# This block is Optimist configuration. It is as long as the number of options of the command.
|
43
45
|
# rubocop:disable Metrics/BlockLength
|
44
|
-
@@
|
46
|
+
@@option_parser = Optimist::Parser.new do
|
45
47
|
subcommand_max_length = @@subcommands.keys.map { |k| k.to_s.length }.max
|
46
48
|
usage @@usage
|
47
49
|
synopsis <<~SUBCOMMANDS unless @@subcommands.empty?
|
@@ -64,9 +66,9 @@ class DescribeDocker < Command
|
|
64
66
|
|
65
67
|
def initialize
|
66
68
|
super(@@usage, @@description) do |version|
|
67
|
-
Common.error 'describe need to be run inside a git repository' unless
|
68
|
-
@options = Common.with_subcommand_exception_handling @@
|
69
|
-
@@
|
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
|
70
72
|
end
|
71
73
|
set_options
|
72
74
|
|