sugarjar 3.0.0 → 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 +21 -0
- data/README.md +131 -22
- data/bin/sj +49 -178
- 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 +54 -16
- data/lib/sugarjar/commands/smartpullrequest.rb +31 -21
- data/lib/sugarjar/commands.rb +111 -97
- data/lib/sugarjar/config.rb +53 -35
- 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
|
@@ -37,8 +37,11 @@ release_branches:
|
|
|
37
37
|
# is assumed it is a relative path and `sj` will check that the file exists.
|
|
38
38
|
|
|
39
39
|
lint:
|
|
40
|
+
# can be a string which is just a command to run...
|
|
40
41
|
- scripts/run_rubocop.sh
|
|
41
|
-
|
|
42
|
+
# want it to have a pretty name? Entries can be a hash instead...
|
|
43
|
+
- name: mdl
|
|
44
|
+
command: scripts/run_mdl.sh
|
|
42
45
|
|
|
43
46
|
# `unit` is a list of scripts to run when `sj unit` is executed (or, if
|
|
44
47
|
# configured to run on `sj spush`/`sj fpush`- see `on_push` below). Regardless
|
|
@@ -47,8 +50,11 @@ lint:
|
|
|
47
50
|
# assumed it is a relative path and `sj` will check that the file exists.
|
|
48
51
|
|
|
49
52
|
unit:
|
|
53
|
+
# like lint, supports bare strings...
|
|
50
54
|
- bundle exec rspec
|
|
51
|
-
|
|
55
|
+
# or hashes...
|
|
56
|
+
- name: unittests
|
|
57
|
+
command: scripts/run_tests.sh
|
|
52
58
|
|
|
53
59
|
# `lint_list_cmd` is like `lint`, except it's a command to run which will
|
|
54
60
|
# determine the proper lints to run and return them, one per line. This is
|
|
@@ -74,20 +80,3 @@ on_push: [lint] # or [lint, unit]
|
|
|
74
80
|
# template configured.
|
|
75
81
|
|
|
76
82
|
commit_template: .git_commit_template.txt
|
|
77
|
-
|
|
78
|
-
# `github_user` is the user to use when talking to GitHub. Overrides any such
|
|
79
|
-
# setting in the regular SugarJar config. Most useful when in the
|
|
80
|
-
# `include_from` file.
|
|
81
|
-
|
|
82
|
-
github_user: myuser
|
|
83
|
-
|
|
84
|
-
# `gitlab_user` is the user to use when talking to GitLab. Overrides any such
|
|
85
|
-
# setting in the regular SugarJar config. Most useful when in the
|
|
86
|
-
# `include_from` file.
|
|
87
|
-
|
|
88
|
-
gitlab_user: myuser
|
|
89
|
-
|
|
90
|
-
# `forge_host` is the GitHub/GitLab host to use when talking to hosted versions
|
|
91
|
-
# of these services.
|
|
92
|
-
|
|
93
|
-
forge_host: github.sample.com
|
|
@@ -10,26 +10,29 @@ _sugarjar_completions()
|
|
|
10
10
|
|
|
11
11
|
local -a suggestions
|
|
12
12
|
|
|
13
|
-
# grap
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
# utils
|
|
18
|
-
local prefix=''
|
|
13
|
+
# grap any and all feature_prefixes so that we can let the user ignore that
|
|
14
|
+
# part. If we have `yq` we'll use it as that's going to be always 100%
|
|
15
|
+
# reliable, but if we don't, do our best with shell utils
|
|
16
|
+
local prefixes=''
|
|
19
17
|
if [ -e "$SJCONFIG" ]; then
|
|
20
18
|
if type yq &>/dev/null; then
|
|
21
|
-
|
|
19
|
+
# We don't use the '// empty' syntax here as thats only in
|
|
20
|
+
# very new yq, so use the more standard '| select(. != null)'
|
|
21
|
+
yq_search='[.host_configs[].feature_prefix | select(. != null)] | unique[]'
|
|
22
|
+
prefixes=$(yq -r "$yq_search" $SJCONFIG | xargs)
|
|
22
23
|
else
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
prefixes=$(
|
|
25
|
+
grep feature_prefix $SJCONFIG | cut -f2 -d: | sort -u | xargs
|
|
26
|
+
)
|
|
25
27
|
fi
|
|
26
28
|
fi
|
|
27
29
|
|
|
28
30
|
case "${COMP_WORDS[1]}" in
|
|
29
31
|
co|checkout|bclean)
|
|
30
32
|
local branches=$(git branch | sed -e 's/* //g' | xargs)
|
|
31
|
-
if [ -n "$
|
|
32
|
-
|
|
33
|
+
if [ -n "$prefixes" ]; then
|
|
34
|
+
regex=$(printf '%s\n' $prefixes | paste -sd'|')
|
|
35
|
+
local branches=$(echo $branches | sed -E "s!($regex)!!g")
|
|
33
36
|
fi
|
|
34
37
|
suggestions=($(compgen -W "$branches" -- "${COMP_WORDS[2]}"))
|
|
35
38
|
COMPREPLY=("${suggestions[@]}")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require_relative '../
|
|
1
|
+
require_relative '../git'
|
|
2
2
|
|
|
3
3
|
class SugarJar
|
|
4
4
|
class Commands
|
|
@@ -7,7 +7,7 @@ class SugarJar
|
|
|
7
7
|
|
|
8
8
|
# does not use dirty_check! as we want a custom message
|
|
9
9
|
if dirty?
|
|
10
|
-
if @ignore_dirty
|
|
10
|
+
if @config['ignore_dirty']
|
|
11
11
|
SugarJar::Log.warn(
|
|
12
12
|
'Your repo is dirty, but --ignore-dirty was specified, so ' +
|
|
13
13
|
'carrying on anyway. If the linter autocorrects, the displayed ' +
|
|
@@ -48,7 +48,21 @@ class SugarJar
|
|
|
48
48
|
)
|
|
49
49
|
return false
|
|
50
50
|
end
|
|
51
|
-
s.stdout
|
|
51
|
+
output = s.stdout
|
|
52
|
+
if output.start_with?("---\n")
|
|
53
|
+
begin
|
|
54
|
+
checks = YAML.safe_load(s.stdout)
|
|
55
|
+
return checks
|
|
56
|
+
rescue Psych::SyntaxError => e
|
|
57
|
+
SugarJar::Log.error(
|
|
58
|
+
"#{type}_list_cmd (#{cmd}) produced invalid YAML: #{e.message}",
|
|
59
|
+
)
|
|
60
|
+
return false
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# otherwise it's one line per command
|
|
65
|
+
output.split("\n")
|
|
52
66
|
end
|
|
53
67
|
|
|
54
68
|
# determine if we're using the _list_cmd and if so run it to get the
|
|
@@ -78,18 +92,26 @@ class SugarJar
|
|
|
78
92
|
# either the user amend, or bail out. If it's a manual run, then we
|
|
79
93
|
# allow them to just go on.
|
|
80
94
|
def run_check(type, autorun)
|
|
81
|
-
repo_root = SugarJar::
|
|
95
|
+
repo_root = SugarJar::Git.repo_root
|
|
82
96
|
Dir.chdir repo_root do
|
|
83
97
|
checks = get_checks(type)
|
|
84
|
-
# if we failed to determine the checks,
|
|
98
|
+
# if we failed to determine the checks, then the checks have effectively
|
|
85
99
|
# failed
|
|
86
100
|
return false unless checks
|
|
87
101
|
|
|
88
102
|
checks.each do |check|
|
|
89
|
-
|
|
103
|
+
if check.is_a?(Hash)
|
|
104
|
+
command = check['command']
|
|
105
|
+
name = check['name'] || command.split.first
|
|
106
|
+
else
|
|
107
|
+
command = check
|
|
108
|
+
name = check.split.first
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
SugarJar::Log.debug("Running #{type} #{name}: #{command}")
|
|
90
112
|
skip_redo = false
|
|
91
113
|
|
|
92
|
-
short =
|
|
114
|
+
short = command.split.first
|
|
93
115
|
if short.include?('/')
|
|
94
116
|
short = File.join(repo_root, short) unless short.start_with?('/')
|
|
95
117
|
unless File.exist?(short)
|
|
@@ -99,12 +121,12 @@ class SugarJar
|
|
|
99
121
|
SugarJar::Log.error("Configured #{type} #{short} does not exist!")
|
|
100
122
|
return false
|
|
101
123
|
end
|
|
102
|
-
s = Mixlib::ShellOut.new(
|
|
124
|
+
s = Mixlib::ShellOut.new(command).run_command
|
|
103
125
|
|
|
104
126
|
# Linters auto-correct, lets handle that gracefully
|
|
105
127
|
if type == 'lint' && dirty?
|
|
106
128
|
SugarJar::Log.info(
|
|
107
|
-
"[#{type}] #{
|
|
129
|
+
"[#{type}] #{name}: #{color('Corrected', :yellow)}",
|
|
108
130
|
)
|
|
109
131
|
SugarJar::Log.warn(
|
|
110
132
|
"The linter modified the repo. Here's the diff:\n",
|
|
@@ -142,14 +164,14 @@ class SugarJar
|
|
|
142
164
|
|
|
143
165
|
if s.error?
|
|
144
166
|
SugarJar::Log.info(
|
|
145
|
-
"[#{type}] #{
|
|
167
|
+
"[#{type}] #{name} #{color('failed', :red)}, output follows " +
|
|
146
168
|
"(see debug for more)\n#{s.stdout}",
|
|
147
169
|
)
|
|
148
170
|
SugarJar::Log.debug(s.format_for_exception)
|
|
149
171
|
return false
|
|
150
172
|
end
|
|
151
173
|
SugarJar::Log.info(
|
|
152
|
-
"[#{type}] #{
|
|
174
|
+
"[#{type}] #{name}: #{color('OK', :green)}",
|
|
153
175
|
)
|
|
154
176
|
end
|
|
155
177
|
end
|
|
@@ -4,7 +4,9 @@ class SugarJar
|
|
|
4
4
|
class Commands
|
|
5
5
|
def debuginfo(*args)
|
|
6
6
|
puts "sugarjar version #{SugarJar::VERSION}"
|
|
7
|
-
|
|
7
|
+
forge.all_versions.each do |v|
|
|
8
|
+
puts v
|
|
9
|
+
end
|
|
8
10
|
puts git('version').stdout
|
|
9
11
|
|
|
10
12
|
puts "Config: #{JSON.pretty_generate(args[0])}"
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
class SugarJar
|
|
2
|
+
class Commands
|
|
3
|
+
def modernizeconfig(config)
|
|
4
|
+
require 'tempfile'
|
|
5
|
+
require 'diffy'
|
|
6
|
+
|
|
7
|
+
data = YAML.safe_load_file(config)
|
|
8
|
+
data = _modernize(data).to_yaml
|
|
9
|
+
tfile = Tempfile.new('sugarjar')
|
|
10
|
+
tfile.write(data)
|
|
11
|
+
tfile.close
|
|
12
|
+
diff = Diffy::Diff.new(
|
|
13
|
+
config,
|
|
14
|
+
tfile.path,
|
|
15
|
+
:source => 'files',
|
|
16
|
+
:context => 2,
|
|
17
|
+
:include_diff_info => true,
|
|
18
|
+
:format => @config['color'] ? 'color' : 'text',
|
|
19
|
+
).to_s
|
|
20
|
+
puts "Here is the diff from your existing config to the new one:\n"
|
|
21
|
+
puts diff
|
|
22
|
+
options = [
|
|
23
|
+
'[u]pdate my config, saving my old one to .bak',
|
|
24
|
+
'[w]rite new config to a temporary file for me to inspect',
|
|
25
|
+
]
|
|
26
|
+
msg = "\nWould you like to\n\t" + options.join("\n\t") + "\n > "
|
|
27
|
+
loop do
|
|
28
|
+
$stdout.print(msg)
|
|
29
|
+
ans = $stdin.gets.strip
|
|
30
|
+
case ans
|
|
31
|
+
when /^u/
|
|
32
|
+
old = "#{config}.bak"
|
|
33
|
+
File.rename(config, old)
|
|
34
|
+
File.write(config, data)
|
|
35
|
+
puts "#{config} updated. Old config in #{old}"
|
|
36
|
+
break
|
|
37
|
+
when /^w/
|
|
38
|
+
new = "#{config}.new"
|
|
39
|
+
File.write(new, data)
|
|
40
|
+
puts "New config written to #{new}"
|
|
41
|
+
break
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
tfile.unlink
|
|
45
|
+
end
|
|
46
|
+
alias fixconfig modernizeconfig
|
|
47
|
+
|
|
48
|
+
def _modernize(data)
|
|
49
|
+
data['host_configs'] ||= {}
|
|
50
|
+
data['host_configs']['default'] ||= {}
|
|
51
|
+
|
|
52
|
+
# First, take anything that used to be a top-level config
|
|
53
|
+
# that's now a host config and move it to host_configs->default
|
|
54
|
+
%w{use_forks feature_prefix}.each do |tlc|
|
|
55
|
+
# this needs to return true even if the value is false-y
|
|
56
|
+
next unless data.key?(tlc)
|
|
57
|
+
|
|
58
|
+
if data['host_configs']['default'][tlc]
|
|
59
|
+
if data['host_configs']['default'][tlc] != data[tlc]
|
|
60
|
+
SugarJar::Log.warn(
|
|
61
|
+
"host_configs->default->#{tlc} already set to something" +
|
|
62
|
+
" different than deprecated top-level #{tlc}, so just deleting" +
|
|
63
|
+
' old top-level config.',
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
else
|
|
67
|
+
data['host_configs']['default'][tlc] = data[tlc]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# we delete it either way, just only warn if it's different
|
|
71
|
+
data.delete(tlc)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Users move into the default config, plus other userless hosts
|
|
75
|
+
# of that type
|
|
76
|
+
%w{github gitlab}.each do |forge|
|
|
77
|
+
tlc = "#{forge}_user"
|
|
78
|
+
site = "#{forge}.com"
|
|
79
|
+
next unless data[tlc]
|
|
80
|
+
|
|
81
|
+
# start with the "default site" for this user (github.com/gitlab.com)
|
|
82
|
+
if data.dig('host_configs', site, 'user')
|
|
83
|
+
if data['host_configs'][site]['user'] != data[tlc]
|
|
84
|
+
SugarJar::Log.warn(
|
|
85
|
+
"host_configs->#{site}->user already set to something" +
|
|
86
|
+
" different than deprecated top-level #{tlc}, so just" +
|
|
87
|
+
' deleting old top-level config.',
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
else
|
|
91
|
+
data['host_configs'][site] ||= {}
|
|
92
|
+
data['host_configs'][site]['user'] = data[tlc]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# now loop through any existing hosts that have been configured that
|
|
96
|
+
# are NOT those default hosts... IFthey don't have a user, populate
|
|
97
|
+
# with the relevant top-level user as in the old world, we would have
|
|
98
|
+
# fallen back to ${type}_user
|
|
99
|
+
data['host_configs'].each do |host, cfg|
|
|
100
|
+
next if host == site
|
|
101
|
+
next unless host.include?(forge)
|
|
102
|
+
next if cfg && cfg['user']
|
|
103
|
+
|
|
104
|
+
data['host_configs'][host] ||= {}
|
|
105
|
+
data['host_configs'][host]['user'] = data[tlc]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# and finally, delete the top-level config
|
|
109
|
+
data.delete(tlc)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Remove any unused/deprecated configs.
|
|
113
|
+
#
|
|
114
|
+
# we don't use TOP_LEVEL_CONFIGS here as that includes things
|
|
115
|
+
# that are cli-only
|
|
116
|
+
data.slice(*SugarJar::Config::DEFAULTS.keys)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -1,9 +1,34 @@
|
|
|
1
1
|
class SugarJar
|
|
2
2
|
class Commands
|
|
3
|
-
def smartclone(repo,
|
|
4
|
-
reponame = extract_repo(repo)
|
|
5
|
-
dir ||= reponame
|
|
3
|
+
def smartclone(repo, *args)
|
|
6
4
|
org = extract_org(repo)
|
|
5
|
+
reponame = extract_repo(repo)
|
|
6
|
+
host = extract_host(repo) || @config['default_forge_host']
|
|
7
|
+
unless host
|
|
8
|
+
raise 'Failed to determine host. Please specify --default-forge-host,' +
|
|
9
|
+
' and file a bug.'
|
|
10
|
+
end
|
|
11
|
+
@host_config = gen_host_config(host)
|
|
12
|
+
raise 'Failed to determine forge_type' unless @host_config['forge_type']
|
|
13
|
+
|
|
14
|
+
# force object recreation - the initial creation would not
|
|
15
|
+
# have had the right data. Plus, we want it to check for the
|
|
16
|
+
# right cli
|
|
17
|
+
@forge = nil
|
|
18
|
+
forge
|
|
19
|
+
|
|
20
|
+
# set env vars of the host, just for completeness
|
|
21
|
+
# since it's short-lived we just set both vars
|
|
22
|
+
ENV['GH_HOST'] = host
|
|
23
|
+
ENV['GL_HOST'] = host
|
|
24
|
+
|
|
25
|
+
dir = if args.length.positive? && !args.first.start_with?('-')
|
|
26
|
+
args.shift
|
|
27
|
+
else
|
|
28
|
+
reponame
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
forkname = @config['fork_name'] || reponame
|
|
7
32
|
|
|
8
33
|
SugarJar::Log.info("Cloning #{reponame}...")
|
|
9
34
|
|
|
@@ -13,37 +38,49 @@ class SugarJar
|
|
|
13
38
|
#
|
|
14
39
|
# Unless the repo is in our own org and cannot be forked, then it
|
|
15
40
|
# will fail.
|
|
16
|
-
if
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
_gitlab_clone(org, repo, dir, *)
|
|
41
|
+
if @host_config['use_forks'] && @host_config['user'] != org
|
|
42
|
+
case forge.type
|
|
43
|
+
when 'gitlab', 'forgejo'
|
|
44
|
+
_separate_fork_clone(org, repo, dir, forkname, *args)
|
|
21
45
|
else
|
|
22
|
-
forge(
|
|
46
|
+
forge.run(
|
|
47
|
+
'repo', 'fork', '--clone', canonicalize_repo(repo), dir,
|
|
48
|
+
'--fork-name', forkname, *args
|
|
49
|
+
)
|
|
23
50
|
end
|
|
24
51
|
|
|
25
52
|
# make the main branch track upstream
|
|
26
53
|
Dir.chdir dir do
|
|
27
54
|
git('branch', '-u', "upstream/#{main_branch}")
|
|
28
55
|
end
|
|
56
|
+
else
|
|
57
|
+
git('clone', canonicalize_repo(repo), dir, *args)
|
|
29
58
|
end
|
|
30
59
|
|
|
31
60
|
SugarJar::Log.info('Remotes "origin" and "upstream" configured.')
|
|
32
61
|
end
|
|
33
62
|
alias sclone smartclone
|
|
34
63
|
|
|
35
|
-
def
|
|
64
|
+
def _separate_fork_clone(_org, repo, dir, forkname, *)
|
|
36
65
|
# The gitlab CLI is much less forgiving about already-forked
|
|
37
66
|
# repos, and it has no option to clone to a differently-named
|
|
38
67
|
# directory. So we have to special case it.
|
|
39
68
|
|
|
69
|
+
extract_repo(repo)
|
|
70
|
+
|
|
40
71
|
# glab requires a short-name for the fork command...
|
|
41
72
|
shortname = repo_shortname(repo)
|
|
42
73
|
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
|
|
74
|
+
# For both gitlab and forgejo we fork without clone:
|
|
75
|
+
# * gitlab - it cannot clone to a chosen directory
|
|
76
|
+
# * forgjo - it doesn't have an option to fork and clone in one
|
|
77
|
+
#
|
|
78
|
+
# Also note that for gitlab we must be explicit, if we don't
|
|
79
|
+
# set --clone=false it will prompt.
|
|
80
|
+
repo_ref = forge.type == 'gitlab' ? shortname : repo
|
|
81
|
+
args = ['repo', 'fork', repo_ref, '--name', forkname]
|
|
82
|
+
args << '--clone=false' if forge.type == 'gitlab'
|
|
83
|
+
s = forge.run_nofail(*args)
|
|
47
84
|
|
|
48
85
|
# It fails with:
|
|
49
86
|
# 409 {message: [Project namespace name has already been taken,
|
|
@@ -53,7 +90,8 @@ class SugarJar
|
|
|
53
90
|
# collision. There's no way to tell, so we assume it means we've
|
|
54
91
|
# already forked.
|
|
55
92
|
if s.error?
|
|
56
|
-
if
|
|
93
|
+
if %w{gitlab forgejo}.include?(forge.type) &&
|
|
94
|
+
s.stderr.include?(' 409 ')
|
|
57
95
|
SugarJar::Log.debug('Forking failed, probably already forked')
|
|
58
96
|
else
|
|
59
97
|
s.error!
|
|
@@ -66,7 +104,7 @@ class SugarJar
|
|
|
66
104
|
# and then configure remotes properly
|
|
67
105
|
git('remote', 'rename', 'origin', 'upstream')
|
|
68
106
|
|
|
69
|
-
fork_url = forked_repo(repo, @
|
|
107
|
+
fork_url = forked_repo(repo, @host_config['user'])
|
|
70
108
|
git('remote', 'add', 'origin', fork_url)
|
|
71
109
|
end
|
|
72
110
|
end
|
|
@@ -19,17 +19,24 @@ class SugarJar
|
|
|
19
19
|
|
|
20
20
|
curr = current_branch
|
|
21
21
|
base = tracked_branch
|
|
22
|
-
if @pr_autofill
|
|
22
|
+
if @config['pr_autofill']
|
|
23
23
|
SugarJar::Log.info('Autofilling in PR from commit message')
|
|
24
24
|
num_commits = git(
|
|
25
25
|
'rev-list', '--count', curr, "^#{base}"
|
|
26
26
|
).stdout.strip.to_i
|
|
27
|
-
if num_commits > 1
|
|
27
|
+
if num_commits > 1 && forge.type == 'github'
|
|
28
28
|
args.unshift('--fill-first')
|
|
29
|
+
elsif forge.type == 'forgejo'
|
|
30
|
+
args += _forgejo_pr_opts
|
|
29
31
|
else
|
|
30
32
|
args.unshift('--fill')
|
|
31
33
|
end
|
|
32
34
|
end
|
|
35
|
+
base_opt = if forge.type == 'gitlab'
|
|
36
|
+
'--target-branch'
|
|
37
|
+
else
|
|
38
|
+
'--base'
|
|
39
|
+
end
|
|
33
40
|
unless user_specified_base
|
|
34
41
|
if subfeature?(base)
|
|
35
42
|
if upstream_org != push_org
|
|
@@ -41,44 +48,39 @@ class SugarJar
|
|
|
41
48
|
' PR is rebased.',
|
|
42
49
|
)
|
|
43
50
|
# nil is prompt, true is always, false is never
|
|
44
|
-
elsif @pr_autostack.nil?
|
|
51
|
+
elsif @config['pr_autostack'].nil?
|
|
45
52
|
$stdout.print(
|
|
46
53
|
'It looks like this is a subfeature, would you like to base ' +
|
|
47
54
|
"this PR on #{base}? [y/n] ",
|
|
48
55
|
)
|
|
49
56
|
ans = $stdin.gets.strip
|
|
50
|
-
args.unshift(
|
|
51
|
-
elsif @pr_autostack
|
|
52
|
-
args.unshift(
|
|
57
|
+
args.unshift(base_opt, base) if %w{Y y}.include?(ans)
|
|
58
|
+
elsif @config['pr_autostack']
|
|
59
|
+
args.unshift(base_opt, base)
|
|
53
60
|
end
|
|
54
61
|
elsif base.include?('/') && base != most_main
|
|
55
62
|
# If our base is a remote branch, then use that as the
|
|
56
63
|
# base branch of the PR
|
|
57
|
-
args.unshift(
|
|
64
|
+
args.unshift(base_opt, base.split('/').last)
|
|
58
65
|
end
|
|
59
66
|
end
|
|
60
67
|
|
|
61
68
|
# <org>:<branch> is the GH API syntax for:
|
|
62
69
|
# look for a branch of name <branch>, from a fork in owner <org>
|
|
63
|
-
if
|
|
64
|
-
# On GitHub, the head is the org and the *BRANCH* name to use as
|
|
65
|
-
# the head branch...
|
|
66
|
-
args.unshift('--head', "#{push_org}:#{curr}")
|
|
67
|
-
else
|
|
70
|
+
if forge.type == 'gitlab'
|
|
68
71
|
# On GitLab, the head is the repo (org/repo) to use as the head
|
|
69
72
|
# _repo_, and then branch is configured seperately (with -s), but
|
|
70
73
|
# we don't need that since it defaults to the local branch name.
|
|
71
74
|
#
|
|
72
75
|
# Then we need --yes for it to not prompt us
|
|
73
|
-
args.unshift('--head', "#{push_org}/#{
|
|
76
|
+
args.unshift('--head', "#{push_org}/#{repo_name}", '--yes')
|
|
77
|
+
else
|
|
78
|
+
# On GitHub/Forgeji, the head is the org and the *BRANCH* name to use as
|
|
79
|
+
# the head branch...
|
|
80
|
+
args.unshift('--head', "#{push_org}:#{curr}")
|
|
74
81
|
end
|
|
75
82
|
|
|
76
|
-
|
|
77
|
-
subcmd = _pr_cmd
|
|
78
|
-
SugarJar::Log.trace(
|
|
79
|
-
"Running: #{bin} #{subcmd} create #{args.join(' ')}",
|
|
80
|
-
)
|
|
81
|
-
system(bin, subcmd, 'create', *args)
|
|
83
|
+
forge.run_with_system(_pr_cmd, 'create', *args)
|
|
82
84
|
end
|
|
83
85
|
|
|
84
86
|
alias spr smartpullrequest
|
|
@@ -87,7 +89,7 @@ class SugarJar
|
|
|
87
89
|
private
|
|
88
90
|
|
|
89
91
|
def _pr_cmd
|
|
90
|
-
|
|
92
|
+
forge.type == 'gitlab' ? 'mr' : 'pr'
|
|
91
93
|
end
|
|
92
94
|
|
|
93
95
|
def assert_common_main_branch!
|
|
@@ -103,7 +105,9 @@ class SugarJar
|
|
|
103
105
|
"\tgit remote set-head #{upstream} -a",
|
|
104
106
|
)
|
|
105
107
|
end
|
|
106
|
-
|
|
108
|
+
|
|
109
|
+
# If we don't have an upstream and an origin, we're done
|
|
110
|
+
return if upstream == 'origin'
|
|
107
111
|
|
|
108
112
|
origin_branch = main_remote_branch('origin')
|
|
109
113
|
# NOTE: that on GL, forks don't fork any branches by default, even
|
|
@@ -119,5 +123,11 @@ class SugarJar
|
|
|
119
123
|
'run to update this clone.',
|
|
120
124
|
)
|
|
121
125
|
end
|
|
126
|
+
|
|
127
|
+
def _forgejo_pr_opts
|
|
128
|
+
title = git('log', '-1', '--pretty=format:%s').stdout
|
|
129
|
+
body = git('show', '-s', '--format=%b').stdout
|
|
130
|
+
[title, "--body=#{body}"]
|
|
131
|
+
end
|
|
122
132
|
end
|
|
123
133
|
end
|