sugarjar 2.0.0.beta.1 → 2.0.1
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 +161 -0
- data/CONTRIBUTING.md +37 -0
- data/README.md +113 -187
- data/examples/sample_config.yaml +24 -0
- data/examples/sample_repoconfig.yaml +77 -0
- data/lib/sugarjar/commands/amend.rb +17 -0
- data/lib/sugarjar/commands/bclean.rb +118 -0
- data/lib/sugarjar/commands/branch.rb +42 -0
- data/lib/sugarjar/commands/checks.rb +139 -0
- data/lib/sugarjar/commands/debuginfo.rb +16 -0
- data/lib/sugarjar/commands/feature.rb +35 -0
- data/lib/sugarjar/commands/pullsuggestions.rb +48 -0
- data/lib/sugarjar/commands/push.rb +66 -0
- data/lib/sugarjar/commands/smartclone.rb +30 -0
- data/lib/sugarjar/commands/smartpullrequest.rb +101 -0
- data/lib/sugarjar/commands/up.rb +103 -0
- data/lib/sugarjar/commands.rb +284 -5
- data/lib/sugarjar/repoconfig.rb +2 -4
- data/lib/sugarjar/util.rb +20 -309
- data/lib/sugarjar/version.rb +1 -1
- data/sugarjar.gemspec +11 -5
- metadata +26 -7
@@ -0,0 +1,24 @@
|
|
1
|
+
# This is a sample SugarJar config
|
2
|
+
#
|
3
|
+
# SugarJar will look for this config in:
|
4
|
+
#
|
5
|
+
# - /etc/sugarjar/config.yaml
|
6
|
+
# - ~/.config/sugarjar/config.yaml
|
7
|
+
#
|
8
|
+
# The latter will overwrite anything in the former.
|
9
|
+
#
|
10
|
+
|
11
|
+
# NOTE: This file does NOT document ALL options since any command-line option
|
12
|
+
# to SugarJar is a valid configuration in this file, so see `sj help` for full
|
13
|
+
# details.
|
14
|
+
|
15
|
+
# Autofill in my PRs from my commit message (default: true)
|
16
|
+
pr_autofile: true
|
17
|
+
|
18
|
+
# Auto stack PRs when subfeatures are detected (default is `nil`, which prompts,
|
19
|
+
# but use `true` or `false` to force an option without prompting)
|
20
|
+
pr_autostack: true
|
21
|
+
|
22
|
+
# Don't warn about deprecated config file options if they are in this
|
23
|
+
# list
|
24
|
+
ignore_deprecated_options: [ 'gh_cli' ]
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# This is a sample `repoconfig` for SugarJar
|
2
|
+
#
|
3
|
+
# Configs should be named `.sugarjar.yaml` and placed in the root
|
4
|
+
# of your repository.
|
5
|
+
#
|
6
|
+
|
7
|
+
# `include_from` is a meta config wich will read from an additional
|
8
|
+
# configuration file and merge anything from the file onto whatever is in the
|
9
|
+
# primary file. This is helpful to have a repo configuration that applies to
|
10
|
+
# all/most developers, but allow individual developers to add to over overwrite
|
11
|
+
# specific configurations for themselves. If the file does not exist, this
|
12
|
+
# configuration is ignored.
|
13
|
+
|
14
|
+
include_from: .sugarjar_local.yaml
|
15
|
+
|
16
|
+
# `overwrite_from` is a meta config which works much like `include_from`,
|
17
|
+
# except that if the file is found, everything else in this configuration file
|
18
|
+
# will be ignored and the configuration will be entirely read from the
|
19
|
+
# referenced file. If the file does not exist, this configuration is ignored.
|
20
|
+
|
21
|
+
overwrite_from: .sugarjar_local_overwrite.yaml
|
22
|
+
|
23
|
+
# `lint` is a list of scripts to run when `sj lint` is executed (or, if
|
24
|
+
# configured, to run on `sj spush`/`sj fpush` - see `on_push` below).
|
25
|
+
# Regardless of where `sj` is run from, these scripts will be run from the root
|
26
|
+
# of the repo. If a slash is detected in the first 'word' of the command, it
|
27
|
+
# is assumed it is a relative path and `sj` will check that the file exists.
|
28
|
+
|
29
|
+
lint:
|
30
|
+
- scripts/run_rubocop.sh
|
31
|
+
- scripts/run_mdl.sh
|
32
|
+
|
33
|
+
# `unit` is a list of scripts to run when `sj unit` is executed (or, if
|
34
|
+
# configured to run on `sj spush`/`sj fpush`- see `on_push` below). Regardless
|
35
|
+
# of where `sj` is run from, these scripts will be run from the root of the
|
36
|
+
# repo. If a slash is detected in the first 'word' of the command, it is
|
37
|
+
# assumed it is a relative path and `sj` will check that the file exists.
|
38
|
+
|
39
|
+
unit:
|
40
|
+
- bundle exec rspec
|
41
|
+
- scripts/run_tests.sh
|
42
|
+
|
43
|
+
# `lint_list_cmd` is like `lint`, except it's a command to run which will
|
44
|
+
# determine the proper lints to run and return them, one per line. This is
|
45
|
+
# useful, for example, when you want to only run lints relevant to the changed
|
46
|
+
# files.
|
47
|
+
|
48
|
+
lint_list_cmd: scripts/determine_linters.sh
|
49
|
+
|
50
|
+
# `unit_list_cmd` is like `unit`, except it's a command to run which will
|
51
|
+
# determine the proper units to run and return them, one per line. This is
|
52
|
+
# useful, for example, when you want to only run tests relevant to the changed
|
53
|
+
# files.
|
54
|
+
|
55
|
+
unit_list_cmd: scripts/determine_tests.sh
|
56
|
+
|
57
|
+
# `on_push` determines what checks should be run when pushing a repo. Valid
|
58
|
+
# options are `lint` and/or `unit` (or nothing, of course).
|
59
|
+
|
60
|
+
on_push: [lint] # or [lint, unit]
|
61
|
+
|
62
|
+
# `commit_template` points to a file to set the git `commit.template` config
|
63
|
+
# to. This is really useful for ensuring that everyone has the same
|
64
|
+
# template configured.
|
65
|
+
|
66
|
+
commit_template: .git_commit_template.txt
|
67
|
+
|
68
|
+
# `github_user` is the user to use when talking to GitHub. Overrides any such
|
69
|
+
# setting in the regular SugarJar config. Most useful when in the
|
70
|
+
# `include_from` file.
|
71
|
+
|
72
|
+
github_user: myuser
|
73
|
+
|
74
|
+
# `github_host` is the GitHub host to use when talking to GitHub (for hosted
|
75
|
+
# GHE). See `github_user`.
|
76
|
+
|
77
|
+
github_host: github.sample.com
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative '../util'
|
2
|
+
|
3
|
+
class SugarJar
|
4
|
+
class Commands
|
5
|
+
def amend(*)
|
6
|
+
assert_in_repo!
|
7
|
+
# This cannot use shellout since we need a full terminal for the editor
|
8
|
+
exit(system(SugarJar::Util.which('git'), 'commit', '--amend', *))
|
9
|
+
end
|
10
|
+
|
11
|
+
def qamend(*)
|
12
|
+
assert_in_repo!
|
13
|
+
SugarJar::Log.info(git('commit', '--amend', '--no-edit', *).stdout)
|
14
|
+
end
|
15
|
+
alias amendq qamend
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
class SugarJar
|
2
|
+
class Commands
|
3
|
+
def bclean(name = nil)
|
4
|
+
assert_in_repo!
|
5
|
+
name ||= current_branch
|
6
|
+
name = fprefix(name)
|
7
|
+
if clean_branch(name)
|
8
|
+
SugarJar::Log.info("#{name}: #{color('reaped', :green)}")
|
9
|
+
else
|
10
|
+
die(
|
11
|
+
"#{color("Cannot clean #{name}", :red)}! there are unmerged " +
|
12
|
+
"commits; use 'git branch -D #{name}' to forcefully delete it.",
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def bcleanall
|
18
|
+
assert_in_repo!
|
19
|
+
curr = current_branch
|
20
|
+
all_local_branches.each do |branch|
|
21
|
+
if MAIN_BRANCHES.include?(branch)
|
22
|
+
SugarJar::Log.debug("Skipping #{branch}")
|
23
|
+
next
|
24
|
+
end
|
25
|
+
|
26
|
+
if clean_branch(branch)
|
27
|
+
SugarJar::Log.info("#{branch}: #{color('reaped', :green)}")
|
28
|
+
else
|
29
|
+
SugarJar::Log.info("#{branch}: skipped")
|
30
|
+
SugarJar::Log.debug(
|
31
|
+
"There are unmerged commits; use 'git branch -D #{branch}' to " +
|
32
|
+
'forcefully delete it)',
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Return to the branch we were on, or main
|
38
|
+
if all_local_branches.include?(curr)
|
39
|
+
git('checkout', curr)
|
40
|
+
else
|
41
|
+
checkout_main_branch
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def clean_branch(name)
|
48
|
+
die("Cannot remove #{name} branch") if MAIN_BRANCHES.include?(name)
|
49
|
+
SugarJar::Log.debug('Fetch relevant remote...')
|
50
|
+
fetch_upstream
|
51
|
+
return false unless safe_to_clean(name)
|
52
|
+
|
53
|
+
SugarJar::Log.debug('branch deemed safe to delete...')
|
54
|
+
checkout_main_branch
|
55
|
+
git('branch', '-D', name)
|
56
|
+
rebase
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
def safe_to_clean(branch)
|
61
|
+
# cherry -v will output 1 line per commit on the target branch
|
62
|
+
# prefixed by a - or + - anything with a - can be dropped, anything
|
63
|
+
# else cannot.
|
64
|
+
out = git(
|
65
|
+
'cherry', '-v', tracked_branch, branch
|
66
|
+
).stdout.lines.reject do |line|
|
67
|
+
line.start_with?('-')
|
68
|
+
end
|
69
|
+
if out.empty?
|
70
|
+
SugarJar::Log.debug(
|
71
|
+
"cherry-pick shows branch #{branch} obviously safe to delete",
|
72
|
+
)
|
73
|
+
return true
|
74
|
+
end
|
75
|
+
|
76
|
+
# if the "easy" check didn't work, it's probably because there
|
77
|
+
# was a squash-merge. To check for that we make our own squash
|
78
|
+
# merge to upstream/main and see if that has any delta
|
79
|
+
|
80
|
+
# First we need a temp branch to work on
|
81
|
+
tmpbranch = "_sugar_jar.#{Process.pid}"
|
82
|
+
|
83
|
+
git('checkout', '-b', tmpbranch, tracked_branch)
|
84
|
+
s = git_nofail('merge', '--squash', branch)
|
85
|
+
if s.error?
|
86
|
+
cleanup_tmp_branch(tmpbranch, branch)
|
87
|
+
SugarJar::Log.debug(
|
88
|
+
'Failed to merge changes into current main. This means we could ' +
|
89
|
+
'not figure out if this is merged or not. Check manually and use ' +
|
90
|
+
"'git branch -D #{branch}' if it is safe to do so.",
|
91
|
+
)
|
92
|
+
return false
|
93
|
+
end
|
94
|
+
|
95
|
+
s = git('diff', '--staged')
|
96
|
+
out = s.stdout
|
97
|
+
SugarJar::Log.debug("Squash-merged diff: #{out}")
|
98
|
+
cleanup_tmp_branch(tmpbranch, branch)
|
99
|
+
if out.empty?
|
100
|
+
SugarJar::Log.debug(
|
101
|
+
'After squash-merging, this branch appears safe to delete',
|
102
|
+
)
|
103
|
+
true
|
104
|
+
else
|
105
|
+
SugarJar::Log.debug(
|
106
|
+
'After squash-merging, this branch is NOT fully merged to main',
|
107
|
+
)
|
108
|
+
false
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def cleanup_tmp_branch(tmp, backto)
|
113
|
+
git('reset', '--hard', tracked_branch)
|
114
|
+
git('checkout', backto)
|
115
|
+
git('branch', '-D', tmp)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class SugarJar
|
2
|
+
class Commands
|
3
|
+
def checkout(*args)
|
4
|
+
assert_in_repo!
|
5
|
+
# Pop the last arguement, which is _probably_ a branch name
|
6
|
+
# and then add any featureprefix, and if _that_ is a branch
|
7
|
+
# name, replace the last arguement with that
|
8
|
+
name = args.last
|
9
|
+
bname = fprefix(name)
|
10
|
+
if all_local_branches.include?(bname)
|
11
|
+
SugarJar::Log.debug("Featurepefixing #{name} -> #{bname}")
|
12
|
+
args[-1] = bname
|
13
|
+
end
|
14
|
+
s = git('checkout', *args)
|
15
|
+
SugarJar::Log.info(s.stderr + s.stdout.chomp)
|
16
|
+
end
|
17
|
+
alias co checkout
|
18
|
+
|
19
|
+
def br
|
20
|
+
assert_in_repo!
|
21
|
+
SugarJar::Log.info(git('branch', '-v').stdout.chomp)
|
22
|
+
end
|
23
|
+
|
24
|
+
def binfo
|
25
|
+
assert_in_repo!
|
26
|
+
SugarJar::Log.info(git(
|
27
|
+
'log', '--graph', '--oneline', '--decorate', '--boundary',
|
28
|
+
"#{tracked_branch}.."
|
29
|
+
).stdout.chomp)
|
30
|
+
end
|
31
|
+
|
32
|
+
# binfo for all branches
|
33
|
+
def smartlog
|
34
|
+
assert_in_repo!
|
35
|
+
SugarJar::Log.info(git(
|
36
|
+
'log', '--graph', '--oneline', '--decorate', '--boundary',
|
37
|
+
'--branches', "#{most_main}.."
|
38
|
+
).stdout.chomp)
|
39
|
+
end
|
40
|
+
alias sl smartlog
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require_relative '../util'
|
2
|
+
|
3
|
+
class SugarJar
|
4
|
+
class Commands
|
5
|
+
def lint
|
6
|
+
assert_in_repo!
|
7
|
+
if dirty?
|
8
|
+
if @ignore_dirty
|
9
|
+
SugarJar::Log.warn(
|
10
|
+
'Your repo is dirty, but --ignore-dirty was specified, so ' +
|
11
|
+
'carrying on anyway. If the linter autocorrects, the displayed ' +
|
12
|
+
'diff will be misleading',
|
13
|
+
)
|
14
|
+
else
|
15
|
+
SugarJar::Log.error(
|
16
|
+
'Your repo is dirty, but --ignore-dirty was not specified. ' +
|
17
|
+
'Refusing to run lint. This is to ensure that if the linter ' +
|
18
|
+
'autocorrects, we can show the correct diff.',
|
19
|
+
)
|
20
|
+
exit(1)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
exit(1) unless run_check('lint')
|
24
|
+
end
|
25
|
+
|
26
|
+
def unit
|
27
|
+
assert_in_repo!
|
28
|
+
exit(1) unless run_check('unit')
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_checks_from_command(type)
|
32
|
+
return nil unless @repo_config["#{type}_list_cmd"]
|
33
|
+
|
34
|
+
cmd = @repo_config["#{type}_list_cmd"]
|
35
|
+
short = cmd.split.first
|
36
|
+
unless File.exist?(short)
|
37
|
+
SugarJar::Log.error(
|
38
|
+
"Configured #{type}_list_cmd #{short} does not exist!",
|
39
|
+
)
|
40
|
+
return false
|
41
|
+
end
|
42
|
+
s = Mixlib::ShellOut.new(cmd).run_command
|
43
|
+
if s.error?
|
44
|
+
SugarJar::Log.error(
|
45
|
+
"#{type}_list_cmd (#{cmd}) failed: #{s.format_for_exception}",
|
46
|
+
)
|
47
|
+
return false
|
48
|
+
end
|
49
|
+
s.stdout.split("\n")
|
50
|
+
end
|
51
|
+
|
52
|
+
# determine if we're using the _list_cmd and if so run it to get the
|
53
|
+
# checks, or just use the directly-defined check, and cache it
|
54
|
+
def get_checks(type)
|
55
|
+
return @checks[type] if @checks[type]
|
56
|
+
|
57
|
+
ret = get_checks_from_command(type)
|
58
|
+
if ret
|
59
|
+
SugarJar::Log.debug("Found #{type}s: #{ret}")
|
60
|
+
@checks[type] = ret
|
61
|
+
# if it's explicitly false, we failed to run the command
|
62
|
+
elsif ret == false
|
63
|
+
@checks[type] = false
|
64
|
+
# otherwise, we move on (basically: it's nil, there was no _list_cmd)
|
65
|
+
else
|
66
|
+
SugarJar::Log.debug("[#{type}]: using listed linters: #{ret}")
|
67
|
+
@checks[type] = @repo_config[type] || []
|
68
|
+
end
|
69
|
+
@checks[type]
|
70
|
+
end
|
71
|
+
|
72
|
+
def run_check(type)
|
73
|
+
repo_root = SugarJar::Util.repo_root
|
74
|
+
Dir.chdir repo_root do
|
75
|
+
checks = get_checks(type)
|
76
|
+
# if we failed to determine the checks, the the checks have effectively
|
77
|
+
# failed
|
78
|
+
return false unless checks
|
79
|
+
|
80
|
+
checks.each do |check|
|
81
|
+
SugarJar::Log.debug("Running #{type} #{check}")
|
82
|
+
|
83
|
+
short = check.split.first
|
84
|
+
if short.include?('/')
|
85
|
+
short = File.join(repo_root, short) unless short.start_with?('/')
|
86
|
+
unless File.exist?(short)
|
87
|
+
SugarJar::Log.error("Configured #{type} #{short} does not exist!")
|
88
|
+
end
|
89
|
+
elsif !SugarJar::Util.which_nofail(short)
|
90
|
+
SugarJar::Log.error("Configured #{type} #{short} does not exist!")
|
91
|
+
return false
|
92
|
+
end
|
93
|
+
s = Mixlib::ShellOut.new(check).run_command
|
94
|
+
|
95
|
+
# Linters auto-correct, lets handle that gracefully
|
96
|
+
if type == 'lint' && dirty?
|
97
|
+
SugarJar::Log.info(
|
98
|
+
"[#{type}] #{short}: #{color('Corrected', :yellow)}",
|
99
|
+
)
|
100
|
+
SugarJar::Log.warn(
|
101
|
+
"The linter modified the repo. Here's the diff:\n",
|
102
|
+
)
|
103
|
+
puts git('diff').stdout
|
104
|
+
loop do
|
105
|
+
$stdout.print(
|
106
|
+
"\nWould you like to\n\t[q]uit and inspect\n\t[a]mend the " +
|
107
|
+
"changes to the current commit and re-run\n > ",
|
108
|
+
)
|
109
|
+
ans = $stdin.gets.strip
|
110
|
+
case ans
|
111
|
+
when /^q/
|
112
|
+
SugarJar::Log.info('Exiting at user request.')
|
113
|
+
exit(1)
|
114
|
+
when /^a/
|
115
|
+
qamend('-a')
|
116
|
+
# break here, if we get out of this loop we 'redo', assuming
|
117
|
+
# the user chose this option
|
118
|
+
break
|
119
|
+
end
|
120
|
+
end
|
121
|
+
redo
|
122
|
+
end
|
123
|
+
|
124
|
+
if s.error?
|
125
|
+
SugarJar::Log.info(
|
126
|
+
"[#{type}] #{short} #{color('failed', :red)}, output follows " +
|
127
|
+
"(see debug for more)\n#{s.stdout}",
|
128
|
+
)
|
129
|
+
SugarJar::Log.debug(s.format_for_exception)
|
130
|
+
return false
|
131
|
+
end
|
132
|
+
SugarJar::Log.info(
|
133
|
+
"[#{type}] #{short}: #{color('OK', :green)}",
|
134
|
+
)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class SugarJar
|
4
|
+
class Commands
|
5
|
+
def debuginfo(*args)
|
6
|
+
puts "sugarjar version #{SugarJar::VERSION}"
|
7
|
+
puts ghcli('version').stdout
|
8
|
+
puts git('version').stdout
|
9
|
+
|
10
|
+
puts "Config: #{JSON.pretty_generate(args[0])}"
|
11
|
+
return unless @repo_config
|
12
|
+
|
13
|
+
puts "Repo config: #{JSON.pretty_generate(@repo_config)}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class SugarJar
|
2
|
+
class Commands
|
3
|
+
def feature(name, base = nil)
|
4
|
+
assert_in_repo!
|
5
|
+
SugarJar::Log.debug("Feature: #{name}, #{base}")
|
6
|
+
name = fprefix(name)
|
7
|
+
die("#{name} already exists!") if all_local_branches.include?(name)
|
8
|
+
if base
|
9
|
+
fbase = fprefix(base)
|
10
|
+
base = fbase if all_local_branches.include?(fbase)
|
11
|
+
else
|
12
|
+
base ||= most_main
|
13
|
+
end
|
14
|
+
# If our base is a local branch, don't try to parse it for a remote name
|
15
|
+
unless all_local_branches.include?(base)
|
16
|
+
base_pieces = base.split('/')
|
17
|
+
git('fetch', base_pieces[0]) if base_pieces.length > 1
|
18
|
+
end
|
19
|
+
git('checkout', '-b', name, base)
|
20
|
+
git('branch', '-u', base)
|
21
|
+
SugarJar::Log.info(
|
22
|
+
"Created feature branch #{color(name, :green)} based on " +
|
23
|
+
color(base, :green),
|
24
|
+
)
|
25
|
+
end
|
26
|
+
alias f feature
|
27
|
+
|
28
|
+
def subfeature(name)
|
29
|
+
assert_in_repo!
|
30
|
+
SugarJar::Log.debug("Subfature: #{name}")
|
31
|
+
feature(name, current_branch)
|
32
|
+
end
|
33
|
+
alias sf subfeature
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative '../util'
|
2
|
+
|
3
|
+
class SugarJar
|
4
|
+
class Commands
|
5
|
+
def pullsuggestions
|
6
|
+
assert_in_repo!
|
7
|
+
|
8
|
+
if dirty?
|
9
|
+
if @ignore_dirty
|
10
|
+
SugarJar::Log.warn(
|
11
|
+
'Your repo is dirty, but --ignore-dirty was specified, so ' +
|
12
|
+
'carrying on anyway.',
|
13
|
+
)
|
14
|
+
else
|
15
|
+
SugarJar::Log.error(
|
16
|
+
'Your repo is dirty, so I am not going to push. Please commit ' +
|
17
|
+
'or amend first.',
|
18
|
+
)
|
19
|
+
exit(1)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
src = "origin/#{current_branch}"
|
24
|
+
fetch('origin')
|
25
|
+
diff = git('diff', "..#{src}").stdout
|
26
|
+
return unless diff && !diff.empty?
|
27
|
+
|
28
|
+
puts "Will merge the following suggestions:\n\n#{diff}"
|
29
|
+
|
30
|
+
loop do
|
31
|
+
$stdout.print("\nAre you sure? [y/n] ")
|
32
|
+
ans = $stdin.gets.strip
|
33
|
+
case ans
|
34
|
+
when /^[Yy]$/
|
35
|
+
git = SugarJar::Util.which('git')
|
36
|
+
system(git, 'merge', '--ff', "origin/#{current_branch}")
|
37
|
+
break
|
38
|
+
when /^[Nn]$/, /^[Qq](uit)?/
|
39
|
+
puts 'Not merging at user request...'
|
40
|
+
break
|
41
|
+
else
|
42
|
+
puts "Didn't understand '#{ans}'."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
alias ps pullsuggestions
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
class SugarJar
|
2
|
+
class Commands
|
3
|
+
def smartpush(remote = nil, branch = nil)
|
4
|
+
assert_in_repo!
|
5
|
+
_smartpush(remote, branch, false)
|
6
|
+
end
|
7
|
+
alias spush smartpush
|
8
|
+
|
9
|
+
def forcepush(remote = nil, branch = nil)
|
10
|
+
assert_in_repo!
|
11
|
+
_smartpush(remote, branch, true)
|
12
|
+
end
|
13
|
+
alias fpush forcepush
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def _smartpush(remote, branch, force)
|
18
|
+
unless remote && branch
|
19
|
+
remote ||= 'origin'
|
20
|
+
branch ||= current_branch
|
21
|
+
end
|
22
|
+
|
23
|
+
if dirty?
|
24
|
+
if @ignore_dirty
|
25
|
+
SugarJar::Log.warn(
|
26
|
+
'Your repo is dirty, but --ignore-dirty was specified, so ' +
|
27
|
+
'carrying on anyway.',
|
28
|
+
)
|
29
|
+
else
|
30
|
+
SugarJar::Log.error(
|
31
|
+
'Your repo is dirty, so I am not going to push. Please commit ' +
|
32
|
+
'or amend first.',
|
33
|
+
)
|
34
|
+
exit(1)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
unless run_prepush
|
39
|
+
if @ignore_prerun_failure
|
40
|
+
SugarJar::Log.warn(
|
41
|
+
'Pre-push checks failed, but --ignore-prerun-failure was ' +
|
42
|
+
'specified, so carrying on anyway',
|
43
|
+
)
|
44
|
+
else
|
45
|
+
SugarJar::Log.error('Pre-push checks failed. Not pushing.')
|
46
|
+
exit(1)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
args = ['push', remote, branch]
|
51
|
+
args << '--force-with-lease' if force
|
52
|
+
puts git(*args).stderr
|
53
|
+
end
|
54
|
+
|
55
|
+
def run_prepush
|
56
|
+
@repo_config['on_push']&.each do |item|
|
57
|
+
SugarJar::Log.debug("Running on_push check type #{item}")
|
58
|
+
unless run_check(item)
|
59
|
+
SugarJar::Log.info("[prepush]: #{item} #{color('failed', :red)}.")
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class SugarJar
|
2
|
+
class Commands
|
3
|
+
def smartclone(repo, dir = nil, *)
|
4
|
+
reponame = File.basename(repo, '.git')
|
5
|
+
dir ||= reponame
|
6
|
+
org = extract_org(repo)
|
7
|
+
|
8
|
+
SugarJar::Log.info("Cloning #{reponame}...")
|
9
|
+
|
10
|
+
# GH's 'fork' command (with the --clone arg) will fork, if necessary,
|
11
|
+
# then clone, and then setup the remotes with the appropriate names. So
|
12
|
+
# we just let it do all the work for us and return.
|
13
|
+
#
|
14
|
+
# Unless the repo is in our own org and cannot be forked, then it
|
15
|
+
# will fail.
|
16
|
+
if org == @ghuser
|
17
|
+
git('clone', canonicalize_repo(repo), dir, *)
|
18
|
+
else
|
19
|
+
ghcli('repo', 'fork', '--clone', canonicalize_repo(repo), dir, *)
|
20
|
+
# make the main branch track upstream
|
21
|
+
Dir.chdir dir do
|
22
|
+
git('branch', '-u', "upstream/#{main_branch}")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
SugarJar::Log.info('Remotes "origin" and "upstream" configured.')
|
27
|
+
end
|
28
|
+
alias sclone smartclone
|
29
|
+
end
|
30
|
+
end
|