sugarjar 3.0.1 → 4.0.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/CHANGELOG.md +10 -0
- data/README.md +127 -22
- data/bin/sj +41 -211
- data/examples/sample_config.yaml +11 -5
- data/examples/sample_repoconfig.yaml +8 -19
- data/extras/sugarjar_completion.bash +14 -11
- data/lib/sugarjar/commands/checks.rb +33 -11
- data/lib/sugarjar/commands/debuginfo.rb +3 -1
- data/lib/sugarjar/commands/modernize_config.rb +119 -0
- data/lib/sugarjar/commands/push.rb +1 -1
- data/lib/sugarjar/commands/smartclone.rb +39 -14
- data/lib/sugarjar/commands/smartpullrequest.rb +27 -19
- data/lib/sugarjar/commands.rb +106 -81
- data/lib/sugarjar/config.rb +53 -36
- data/lib/sugarjar/forge.rb +98 -0
- data/lib/sugarjar/git.rb +29 -0
- data/lib/sugarjar/help.rb +313 -0
- data/lib/sugarjar/repoconfig.rb +3 -3
- data/lib/sugarjar/util.rb +0 -65
- data/lib/sugarjar/version.rb +1 -1
- data/sugarjar.gemspec +1 -0
- metadata +20 -2
data/lib/sugarjar/commands.rb
CHANGED
|
@@ -6,14 +6,16 @@ require_relative 'commands/branch'
|
|
|
6
6
|
require_relative 'commands/checks'
|
|
7
7
|
require_relative 'commands/debuginfo'
|
|
8
8
|
require_relative 'commands/feature'
|
|
9
|
+
require_relative 'commands/modernize_config'
|
|
9
10
|
require_relative 'commands/pullsuggestions'
|
|
10
11
|
require_relative 'commands/push'
|
|
11
12
|
require_relative 'commands/smartclone'
|
|
12
13
|
require_relative 'commands/smartpullrequest'
|
|
13
14
|
require_relative 'commands/up'
|
|
15
|
+
require_relative 'forge'
|
|
16
|
+
require_relative 'git'
|
|
14
17
|
require_relative 'log'
|
|
15
18
|
require_relative 'repoconfig'
|
|
16
|
-
require_relative 'util'
|
|
17
19
|
require_relative 'version'
|
|
18
20
|
|
|
19
21
|
class SugarJar
|
|
@@ -25,39 +27,21 @@ class SugarJar
|
|
|
25
27
|
|
|
26
28
|
def initialize(options)
|
|
27
29
|
SugarJar::Log.debug("Commands.initialize options: #{options}")
|
|
28
|
-
@
|
|
29
|
-
@ignore_prerun_failure = options['ignore_prerun_failure']
|
|
30
|
+
@config = options
|
|
30
31
|
@repo_config = SugarJar::RepoConfig.config
|
|
31
32
|
SugarJar::Log.debug("Repoconfig: #{@repo_config}")
|
|
32
|
-
|
|
33
|
-
@pr_autofill = options['pr_autofill']
|
|
34
|
-
@pr_autostack = options['pr_autostack']
|
|
35
|
-
@feature_prefix = options['feature_prefix']
|
|
36
|
-
@use_forks = options['use_forks']
|
|
37
|
-
@fork_name = options['fork_name']
|
|
33
|
+
|
|
38
34
|
@checks = {}
|
|
39
35
|
@main_branch = nil
|
|
40
36
|
@main_remote_branches = {}
|
|
41
|
-
|
|
42
|
-
# to the method forge_host which will always return something
|
|
43
|
-
@_forge_host = @repo_config['forge_host'] || options['forge_host']
|
|
44
|
-
@repo_forge = @repo_config['forge_type'] || options['forge_type'] ||
|
|
45
|
-
_determine_forge_type
|
|
46
|
-
|
|
47
|
-
unless @repo_forge.nil?
|
|
48
|
-
cmd = _forge_cmd
|
|
49
|
-
unless SugarJar::Util.which_nofail(cmd)
|
|
50
|
-
die("No '#{cmd}' found, please install it'")
|
|
51
|
-
end
|
|
52
|
-
end
|
|
37
|
+
@host_config = nil
|
|
53
38
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
ENV['GL_HOST'] = @_forge_host
|
|
39
|
+
if SugarJar::Git.in_repo?
|
|
40
|
+
@host_config = gen_host_config
|
|
41
|
+
if @host_config['forge_type']
|
|
42
|
+
# initialize instance var here so checks run...
|
|
43
|
+
forge
|
|
44
|
+
end
|
|
61
45
|
end
|
|
62
46
|
|
|
63
47
|
return if options['no_change']
|
|
@@ -67,34 +51,72 @@ class SugarJar
|
|
|
67
51
|
|
|
68
52
|
private
|
|
69
53
|
|
|
54
|
+
def forge
|
|
55
|
+
return @forge if @forge
|
|
56
|
+
unless @host_config['forge_type']
|
|
57
|
+
raise 'Attempted to create Forge object before forge-type known!'
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
@forge = SugarJar::Forge.new(
|
|
61
|
+
@host_config['forge_type'], @host_config['forge_host']
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def gen_host_config(host = nil)
|
|
66
|
+
host ||= _determine_forge_host
|
|
67
|
+
_config_for_host(host) || {}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def _config_for_host(host)
|
|
71
|
+
SugarJar::Log.debug("config_for_host called for #{host}")
|
|
72
|
+
r = @config.dig('host_configs', 'default').dup || {}
|
|
73
|
+
r.merge!(@config.dig('host_configs', host) || {})
|
|
74
|
+
r['forge_host'] = host
|
|
75
|
+
# if people specified a forge_type, honor it
|
|
76
|
+
r['forge_type'] ||= _determine_forge_type(host)
|
|
77
|
+
|
|
78
|
+
# there are a few things we allow the CLI to override
|
|
79
|
+
r.merge!(@config['_cli_overrides'] || {})
|
|
80
|
+
|
|
81
|
+
SugarJar::Log.debug("Determined config for host: #{r}")
|
|
82
|
+
r
|
|
83
|
+
end
|
|
84
|
+
|
|
70
85
|
def forked_repo(repo, username)
|
|
86
|
+
host = @host_config&.dig('forge_host') || extract_host(repo) ||
|
|
87
|
+
@config['default_forge_host']
|
|
88
|
+
raise 'Cannot determine host' unless host
|
|
89
|
+
|
|
71
90
|
repo = extract_repo(repo)
|
|
72
|
-
|
|
91
|
+
|
|
92
|
+
"git@#{host}:#{username}/#{repo}.git"
|
|
73
93
|
end
|
|
74
94
|
|
|
75
95
|
# gh utils will default to https, but we should always default to SSH
|
|
76
96
|
# unless otherwise specified since https will cause prompting.
|
|
77
97
|
def canonicalize_repo(repo)
|
|
78
98
|
# if they fully-qualified it, we're good
|
|
79
|
-
return repo if repo.start_with?('http', 'git@')
|
|
99
|
+
return repo if repo.start_with?('http', 'git@', 'ssh://')
|
|
80
100
|
|
|
101
|
+
host = @host_config&.dig('forge_host') || extract_host(repo) ||
|
|
102
|
+
@config['default_forge_host']
|
|
81
103
|
# otherwise, it's a shortname
|
|
82
|
-
cr = "git@#{
|
|
104
|
+
cr = "git@#{host}:#{repo}.git"
|
|
83
105
|
SugarJar::Log.debug("canonicalized #{repo} to #{cr}")
|
|
84
106
|
cr
|
|
85
107
|
end
|
|
86
108
|
|
|
87
|
-
def
|
|
88
|
-
#
|
|
89
|
-
|
|
109
|
+
def _determine_forge_host
|
|
110
|
+
# DO NOT USE in the general case - ONLY for filling in @host_config
|
|
111
|
+
# (doesn't consult host_config). Use @host_config['forge_host']
|
|
112
|
+
# in general.
|
|
90
113
|
|
|
91
|
-
#
|
|
92
|
-
if SugarJar::
|
|
114
|
+
# if we're in a repo, use the hostname of the remote
|
|
115
|
+
if SugarJar::Git.in_repo?
|
|
93
116
|
url = remote_url_map.values.first
|
|
94
117
|
return extract_host(url)
|
|
95
118
|
end
|
|
96
|
-
|
|
97
|
-
@repo_forge == 'gitlab' ? 'gitlab.com' : 'github.com'
|
|
119
|
+
@config['default_forge_host']
|
|
98
120
|
end
|
|
99
121
|
|
|
100
122
|
def repo_shortname(repo)
|
|
@@ -107,7 +129,7 @@ class SugarJar
|
|
|
107
129
|
end
|
|
108
130
|
|
|
109
131
|
def set_commit_template
|
|
110
|
-
unless SugarJar::
|
|
132
|
+
unless SugarJar::Git.in_repo?
|
|
111
133
|
SugarJar::Log.debug('Skipping set_commit_template: not in repo')
|
|
112
134
|
return
|
|
113
135
|
end
|
|
@@ -115,7 +137,10 @@ class SugarJar
|
|
|
115
137
|
realpath = if @repo_config['commit_template'].start_with?('/')
|
|
116
138
|
@repo_config['commit_template']
|
|
117
139
|
else
|
|
118
|
-
|
|
140
|
+
File.join(
|
|
141
|
+
SugarJar::Git.repo_root,
|
|
142
|
+
@repo_config['commit_template'],
|
|
143
|
+
)
|
|
119
144
|
end
|
|
120
145
|
unless File.exist?(realpath)
|
|
121
146
|
die(
|
|
@@ -148,7 +173,7 @@ class SugarJar
|
|
|
148
173
|
end
|
|
149
174
|
|
|
150
175
|
def assert_in_repo!
|
|
151
|
-
return if SugarJar::
|
|
176
|
+
return if SugarJar::Git.in_repo?
|
|
152
177
|
|
|
153
178
|
die('sugarjar must be run from inside a git repo')
|
|
154
179
|
end
|
|
@@ -156,7 +181,7 @@ class SugarJar
|
|
|
156
181
|
def dirty_check!
|
|
157
182
|
return unless dirty?
|
|
158
183
|
|
|
159
|
-
if @ignore_dirty
|
|
184
|
+
if @config['ignore_dirty']
|
|
160
185
|
SugarJar::Log.warn(
|
|
161
186
|
'Your repo is dirty, but --ignore-dirty was specified, so ' +
|
|
162
187
|
'carrying on anyway.',
|
|
@@ -171,7 +196,11 @@ class SugarJar
|
|
|
171
196
|
end
|
|
172
197
|
|
|
173
198
|
def determine_main_branch(branches)
|
|
174
|
-
branches.include?('
|
|
199
|
+
if branches.include?('main')
|
|
200
|
+
'main'
|
|
201
|
+
elsif branches.include?('master')
|
|
202
|
+
'master'
|
|
203
|
+
end
|
|
175
204
|
end
|
|
176
205
|
|
|
177
206
|
def main_branch
|
|
@@ -301,8 +330,14 @@ class SugarJar
|
|
|
301
330
|
extract_org(url)
|
|
302
331
|
end
|
|
303
332
|
|
|
333
|
+
def repo_name
|
|
334
|
+
# Take the url of the most-upstream remote, then pull the repo
|
|
335
|
+
# name from that
|
|
336
|
+
extract_repo(remote_url_map[upstream])
|
|
337
|
+
end
|
|
338
|
+
|
|
304
339
|
def color(string, *colors)
|
|
305
|
-
if @color
|
|
340
|
+
if @config['color']
|
|
306
341
|
pastel.decorate(string, *colors)
|
|
307
342
|
else
|
|
308
343
|
string
|
|
@@ -316,17 +351,13 @@ class SugarJar
|
|
|
316
351
|
end
|
|
317
352
|
end
|
|
318
353
|
|
|
319
|
-
def forge_cli_avail?
|
|
320
|
-
!!SugarJar::Util.which_nofail(_forge_cmd)
|
|
321
|
-
end
|
|
322
|
-
|
|
323
354
|
def fprefix(name)
|
|
324
|
-
return name unless @feature_prefix
|
|
355
|
+
return name unless @host_config['feature_prefix']
|
|
325
356
|
|
|
326
|
-
return name if name.start_with?(@feature_prefix)
|
|
357
|
+
return name if name.start_with?(@host_config['feature_prefix'])
|
|
327
358
|
return name if all_local_branches.include?(name)
|
|
328
359
|
|
|
329
|
-
newname = "#{@feature_prefix}#{name}"
|
|
360
|
+
newname = "#{@host_config['feature_prefix']}#{name}"
|
|
330
361
|
SugarJar::Log.debug(
|
|
331
362
|
"Munging feature name: #{name} -> #{newname} due to feature prefix",
|
|
332
363
|
)
|
|
@@ -338,8 +369,8 @@ class SugarJar
|
|
|
338
369
|
s.error?
|
|
339
370
|
end
|
|
340
371
|
|
|
341
|
-
def
|
|
342
|
-
SugarJar::
|
|
372
|
+
def repo_dir_name
|
|
373
|
+
SugarJar::Git.repo_root.split('/').last
|
|
343
374
|
end
|
|
344
375
|
|
|
345
376
|
def extract_org(repo)
|
|
@@ -360,6 +391,8 @@ class SugarJar
|
|
|
360
391
|
def extract_host(repo)
|
|
361
392
|
if repo.start_with?('git@')
|
|
362
393
|
repo.split(':').first.split('@').last
|
|
394
|
+
elsif repo.start_with?('ssh://')
|
|
395
|
+
repo.split('/')[2].split('@').last
|
|
363
396
|
elsif repo.start_with?('http')
|
|
364
397
|
repo.split('/')[2]
|
|
365
398
|
end
|
|
@@ -381,7 +414,7 @@ class SugarJar
|
|
|
381
414
|
end
|
|
382
415
|
|
|
383
416
|
def worktrees
|
|
384
|
-
root = SugarJar::
|
|
417
|
+
root = SugarJar::Git.repo_root
|
|
385
418
|
s = git('worktree', 'list', '--porcelain')
|
|
386
419
|
s.error!
|
|
387
420
|
worktrees = {}
|
|
@@ -412,41 +445,33 @@ class SugarJar
|
|
|
412
445
|
end
|
|
413
446
|
|
|
414
447
|
def git(*)
|
|
415
|
-
SugarJar::
|
|
448
|
+
SugarJar::Git.run(*, :color => @config['color'])
|
|
416
449
|
end
|
|
417
450
|
|
|
418
451
|
def git_nofail(*)
|
|
419
|
-
SugarJar::
|
|
420
|
-
end
|
|
452
|
+
SugarJar::Git.run_nofail(*, :color => @config['color'])
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def _determine_forge_type(host = nil)
|
|
456
|
+
if host
|
|
457
|
+
case host
|
|
458
|
+
when /gitlab/
|
|
459
|
+
return 'gitlab'
|
|
460
|
+
when /github/
|
|
461
|
+
return 'github'
|
|
462
|
+
when /forgejo|codeberg/
|
|
463
|
+
return 'forgejo'
|
|
464
|
+
end
|
|
465
|
+
end
|
|
421
466
|
|
|
422
|
-
|
|
423
|
-
if SugarJar::Util.in_repo?
|
|
467
|
+
if SugarJar::Git.in_repo?
|
|
424
468
|
gl = remote_url_map.values.any? { |x| x.include?('gitlab') }
|
|
425
469
|
return gl ? 'gitlab' : 'github'
|
|
426
470
|
end
|
|
427
471
|
|
|
428
|
-
#
|
|
429
|
-
'
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
def _forge_cmd
|
|
433
|
-
@repo_forge == 'gitlab' ? 'glab' : 'gh'
|
|
434
|
-
end
|
|
435
|
-
|
|
436
|
-
def forge(*)
|
|
437
|
-
if @repo_forge == 'gitlab'
|
|
438
|
-
SugarJar::Util.glcli(*)
|
|
439
|
-
else
|
|
440
|
-
SugarJar::Util.ghcli(*)
|
|
441
|
-
end
|
|
442
|
-
end
|
|
443
|
-
|
|
444
|
-
def forge_nofail(*)
|
|
445
|
-
if @repo_forge == 'gitlab'
|
|
446
|
-
SugarJar::Util.glcli_nofail(*)
|
|
447
|
-
else
|
|
448
|
-
SugarJar::Util.ghcli_nofail(*)
|
|
449
|
-
end
|
|
472
|
+
# in smartclone mode, when creating the object, we will in fact
|
|
473
|
+
# be unable to determine this, that's expacted
|
|
474
|
+
SugarJar::Log.debug('Unable to determine forge_type!')
|
|
450
475
|
end
|
|
451
476
|
end
|
|
452
477
|
end
|
data/lib/sugarjar/config.rb
CHANGED
|
@@ -1,25 +1,52 @@
|
|
|
1
1
|
require 'yaml'
|
|
2
2
|
require_relative 'log'
|
|
3
|
+
require 'deep_merge'
|
|
3
4
|
|
|
4
5
|
class SugarJar
|
|
5
6
|
# This parses SugarJar configs (not to be confused with repoconfigs).
|
|
6
7
|
# This is stuff like log level, github-user, etc.
|
|
7
8
|
class Config
|
|
8
9
|
DEFAULTS = {
|
|
9
|
-
'
|
|
10
|
-
'gitlab_user' => ENV.fetch('USER'),
|
|
10
|
+
'default_forge_host' => nil,
|
|
11
11
|
'pr_autofill' => true,
|
|
12
12
|
'pr_autostack' => nil,
|
|
13
13
|
'color' => true,
|
|
14
|
-
'use_forks' => true,
|
|
15
14
|
'ignore_deprecated_options' => [],
|
|
15
|
+
'host_configs' => {
|
|
16
|
+
'default' => {
|
|
17
|
+
'user' => ENV.fetch('USER'),
|
|
18
|
+
'use_forks' => true,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
}.freeze
|
|
22
|
+
|
|
23
|
+
# things we have a command-line option for, but doesn't make sense
|
|
24
|
+
# in a config file.
|
|
25
|
+
EXTRA_CONFIGS = %w{fork_name force_forge_type}.freeze
|
|
26
|
+
|
|
27
|
+
TOP_LEVEL_CONFIGS = (DEFAULTS.keys + EXTRA_CONFIGS).freeze
|
|
28
|
+
|
|
29
|
+
DEPRECATED_OPTIONS = %w{
|
|
30
|
+
fallthru
|
|
31
|
+
gh_cli
|
|
32
|
+
github_user
|
|
33
|
+
gitlab_user
|
|
34
|
+
github_host
|
|
35
|
+
gitlab_host
|
|
16
36
|
}.freeze
|
|
17
37
|
|
|
18
38
|
def self._find_ordered_files
|
|
39
|
+
real_files = []
|
|
19
40
|
[
|
|
20
|
-
'/etc/sugarjar
|
|
21
|
-
"#{Dir.home}/.config/sugarjar
|
|
22
|
-
].
|
|
41
|
+
'/etc/sugarjar',
|
|
42
|
+
"#{Dir.home}/.config/sugarjar",
|
|
43
|
+
].each do |dir|
|
|
44
|
+
%w{yaml yml}.each do |ext|
|
|
45
|
+
f = File.join(dir, "config.#{ext}")
|
|
46
|
+
real_files << f if File.exist?(f)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
real_files
|
|
23
50
|
end
|
|
24
51
|
|
|
25
52
|
def self.config
|
|
@@ -28,21 +55,34 @@ class SugarJar
|
|
|
28
55
|
_find_ordered_files.each do |f|
|
|
29
56
|
SugarJar::Log.debug("Loading config #{f}")
|
|
30
57
|
data = YAML.safe_load_file(f)
|
|
58
|
+
next unless data
|
|
59
|
+
|
|
31
60
|
warn_on_deprecated_configs(data, f)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
data.delete('github_host')
|
|
35
|
-
end
|
|
36
|
-
# an empty file is a `nil` which you can't merge
|
|
37
|
-
c.merge!(YAML.safe_load_file(f)) if data
|
|
61
|
+
data = data.slice(*TOP_LEVEL_CONFIGS)
|
|
62
|
+
c.deep_merge!(data)
|
|
38
63
|
SugarJar::Log.debug("Modified config: #{c}")
|
|
39
64
|
end
|
|
40
65
|
c
|
|
41
66
|
end
|
|
42
67
|
|
|
43
68
|
def self.warn_on_deprecated_configs(data, fname)
|
|
69
|
+
# if it doesn't have host_configs **and** it has one of the
|
|
70
|
+
# previous user options, that were effectively required before
|
|
71
|
+
# and have now moved to host_configs, then we treat it as an
|
|
72
|
+
# old config
|
|
73
|
+
if %w{github_user gitlab_user}.any? { |useropt| data.key?(useropt) } &&
|
|
74
|
+
!data['host_configs']
|
|
75
|
+
SugarJar::Log.warn(
|
|
76
|
+
"#{fname} appears to be an old-style config.\nIt likely will " +
|
|
77
|
+
'not result in the behavior you want. You should run' +
|
|
78
|
+
"\n\n\tsj modernizeconfig #{fname}\n\n" +
|
|
79
|
+
"To automatically convert it.\n",
|
|
80
|
+
)
|
|
81
|
+
return
|
|
82
|
+
end
|
|
83
|
+
|
|
44
84
|
ignore_deprecated_options = data['ignore_deprecated_options'] || []
|
|
45
|
-
|
|
85
|
+
DEPRECATED_OPTIONS.each do |opt|
|
|
46
86
|
next unless data.key?(opt)
|
|
47
87
|
|
|
48
88
|
if ignore_deprecated_options.include?(opt)
|
|
@@ -57,29 +97,6 @@ class SugarJar
|
|
|
57
97
|
'suppress this warning with `ignore_deprecated_options`.',
|
|
58
98
|
)
|
|
59
99
|
end
|
|
60
|
-
|
|
61
|
-
# github_host has special handling
|
|
62
|
-
return unless data['github_host']
|
|
63
|
-
|
|
64
|
-
if ignore_deprecated_options.include?('github_host')
|
|
65
|
-
SugarJar::Log.debug(
|
|
66
|
-
"#{fname}: Deprecated option `github_host` found, but not " +
|
|
67
|
-
'warning due to `ignore_deprecated_options` in that file.',
|
|
68
|
-
)
|
|
69
|
-
elsif data.key?('forge_host')
|
|
70
|
-
SugarJar::Log.warn(
|
|
71
|
-
"#{fname}: Deprecated option `github_host` found. " +
|
|
72
|
-
'Ignoring in favor of newer `force_host` option. You can ' +
|
|
73
|
-
'suppress this warning with `ignore_deprecated_options`.',
|
|
74
|
-
)
|
|
75
|
-
else
|
|
76
|
-
SugarJar::Log.warn(
|
|
77
|
-
"#{fname}: Deprecated option `github_host` found. " +
|
|
78
|
-
'Treating it as if it was `forge_host` for now. Please update ' +
|
|
79
|
-
'your config file to use this new option. You can suppress ' +
|
|
80
|
-
'this warning with `ignore_deprecated_options`.',
|
|
81
|
-
)
|
|
82
|
-
end
|
|
83
100
|
end
|
|
84
101
|
end
|
|
85
102
|
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require 'mixlib/shellout'
|
|
2
|
+
require_relative 'util'
|
|
3
|
+
require_relative 'log'
|
|
4
|
+
|
|
5
|
+
class SugarJar
|
|
6
|
+
class Forge
|
|
7
|
+
attr_reader :type
|
|
8
|
+
|
|
9
|
+
CMD_MAP = {
|
|
10
|
+
'github' => 'gh',
|
|
11
|
+
'gitlab' => 'glab',
|
|
12
|
+
'forgejo' => 'fj',
|
|
13
|
+
}.freeze
|
|
14
|
+
|
|
15
|
+
def initialize(type, host)
|
|
16
|
+
@type = type
|
|
17
|
+
@host = host
|
|
18
|
+
assert_cli_avail!
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def cmd
|
|
22
|
+
@cmd ||= CMD_MAP[@type]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def all_versions
|
|
26
|
+
CMD_MAP.values.map do |cli|
|
|
27
|
+
bin = SugarJar::Util.which_nofail(cli)
|
|
28
|
+
_forge_nofail(cli, 'version').stdout if bin
|
|
29
|
+
end.compact
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def run_nofail(*)
|
|
33
|
+
_forge_nofail(cmd, *)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def run(*)
|
|
37
|
+
s = _forge_nofail(cmd, *)
|
|
38
|
+
s.error!
|
|
39
|
+
s
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def run_with_system(*args)
|
|
43
|
+
SugarJar::Log.trace("Running: #{cmd} #{args.join(' ')}")
|
|
44
|
+
system(cmd, *args)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def _forge_nofail(cli, *args)
|
|
50
|
+
SugarJar::Log.trace("Running: #{cli} #{args.join(' ')}")
|
|
51
|
+
bin = SugarJar::Util.which_nofail(cli)
|
|
52
|
+
s = Mixlib::ShellOut.new([bin] + args).run_command
|
|
53
|
+
if s.error? && ["#{cli} auth", 'Unauthorized'].any? do |err|
|
|
54
|
+
s.stderr.include?(err)
|
|
55
|
+
end
|
|
56
|
+
SugarJar::Log.info(
|
|
57
|
+
"#{cli} was run but no gitlab token exists. Will run " +
|
|
58
|
+
"'#{cli} auth login' to force\n#{cli} to authenticate...",
|
|
59
|
+
)
|
|
60
|
+
args = if cli == 'fj'
|
|
61
|
+
[bin, '-H', @host, 'auth', 'login']
|
|
62
|
+
else
|
|
63
|
+
[bin, 'auth', 'login', '-p', 'ssh']
|
|
64
|
+
end
|
|
65
|
+
unless system(*args)
|
|
66
|
+
SugarJar::Log.fatal(
|
|
67
|
+
"That failed, I will bail out. #{cli} needs to get a " +
|
|
68
|
+
"token. Try running '#{cli} auth login' (will list info about " +
|
|
69
|
+
'your account) and try this again when that works.',
|
|
70
|
+
)
|
|
71
|
+
exit(1)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
if cli == 'fj'
|
|
75
|
+
fj = Mixlib::ShellOut.new([bin, 'auth', 'list']).run_command
|
|
76
|
+
unless fj.stdout.include?(@host)
|
|
77
|
+
SugarJar::Log.fatal(
|
|
78
|
+
'Logging in for you failed - this usually means you need to ' +
|
|
79
|
+
'create a token manually - the instructions should have been ' +
|
|
80
|
+
'printed above. Setup the token and then try again.',
|
|
81
|
+
)
|
|
82
|
+
exit(1)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
s
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def assert_cli_avail!
|
|
90
|
+
return if SugarJar::Util.which_nofail(cmd)
|
|
91
|
+
|
|
92
|
+
SugarJar::Log.error(
|
|
93
|
+
"Forge CLI #{cmd} is unavailable, please install",
|
|
94
|
+
)
|
|
95
|
+
exit 1
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
data/lib/sugarjar/git.rb
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require_relative 'util'
|
|
2
|
+
|
|
3
|
+
class SugarJar
|
|
4
|
+
module Git
|
|
5
|
+
def self.run_nofail(*args, color: true)
|
|
6
|
+
if %w{diff log grep branch}.include?(args[0]) &&
|
|
7
|
+
args.none? { |x| x.include?('color') }
|
|
8
|
+
args << (color ? '--color' : '--no-color')
|
|
9
|
+
end
|
|
10
|
+
SugarJar::Log.trace("Running: git #{args.join(' ')}")
|
|
11
|
+
Mixlib::ShellOut.new([SugarJar::Util.which('git')] + args).run_command
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.run(*, color: true)
|
|
15
|
+
s = run_nofail(*, :color => color)
|
|
16
|
+
s.error!
|
|
17
|
+
s
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.in_repo?
|
|
21
|
+
s = run_nofail('rev-parse', '--is-inside-work-tree')
|
|
22
|
+
!s.error? && s.stdout.strip == 'true'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.repo_root
|
|
26
|
+
run('rev-parse', '--show-toplevel').stdout.strip
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|