sugarjar 0.0.10 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +85 -30
- data/bin/sj +48 -10
- data/lib/sugarjar/commands.rb +293 -60
- data/lib/sugarjar/config.rb +3 -2
- data/lib/sugarjar/util.rb +47 -3
- data/lib/sugarjar/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95e4979017c0ed58f99c446d9215a6b64aec7d5ebc22694a95903710d5af9d7e
|
4
|
+
data.tar.gz: b4b7a648bc7e8002e46dfbaa73cc52749cd38258b5782a2b33a6d66db98facfc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e34735382f6646bf5fe1577eb6637ad7aaceaa9ccf2d2dad024d4a95f3e2a0e8ec080fe086fd5dae7354b3f15f83d26e6ae8b067a1fae9fb5b3da777f9e1f86
|
7
|
+
data.tar.gz: 155d1aa1c7148f2d7181678f64ef64b17fb5efc90386ce3bd27c2bcc7b256113680b4e69a16558790ab3c77080325fc36a56c9f3cc76cf4962f8f575cd00d5d7
|
data/README.md
CHANGED
@@ -3,10 +3,17 @@
|
|
3
3
|
[![Lint](https://github.com/jaymzh/sugarjar/workflows/Lint/badge.svg)](https://github.com/jaymzh/sugarjar/actions?query=workflow%3ALint)
|
4
4
|
[![Unittest](https://github.com/jaymzh/sugarjar/workflows/Unittests/badge.svg)](https://github.com/jaymzh/sugarjar/actions?query=workflow%3AUnittests)
|
5
5
|
[![DCO](https://github.com/jaymzh/sugarjar/workflows/DCO%20Check/badge.svg)](https://github.com/jaymzh/sugarjar/actions?query=workflow%3A%22DCO+Check%22)
|
6
|
-
[![Gem Version](https://badge.fury.io/rb/sugarjar.svg)](https://badge.fury.io/rb/sugarjar)
|
7
6
|
|
8
|
-
|
9
|
-
[
|
7
|
+
> [!IMPORTANT]
|
8
|
+
> You probably want to use [Sapling](https://sapling-scm.com/)
|
9
|
+
> instead of this! This was written as a stop-gap to approximate some features
|
10
|
+
> of the Facebook/Meta internal development tools before they were released.
|
11
|
+
> Now that those tools have been open-sourced and work with GitHub, this is
|
12
|
+
> likely to be deprecated at some point. Sapling is far more feature rich,
|
13
|
+
> faster, and have more development resources behind them.
|
14
|
+
|
15
|
+
Welcome to SugarJar - a git/github helper. It needs one of the GitHub CLI's:
|
16
|
+
either [gh](https://cli.github.com/) or the older [hub](https://hub.github.com/).
|
10
17
|
|
11
18
|
SugarJar is inspired by [arcanist](https://github.com/phacility/arcanist), and
|
12
19
|
its replacement at Facebook, JellyFish. Many of the features they provide for
|
@@ -19,6 +26,30 @@ If you miss Mondrian or Phabricator - this is the tool for you!
|
|
19
26
|
|
20
27
|
If you don't, there's a ton of useful stuff for everyone!
|
21
28
|
|
29
|
+
## Installation
|
30
|
+
|
31
|
+
Sugarjar is packaged in a variety of Linux distributions - see if it's on the
|
32
|
+
list here, and if so, use your package manager (or `gem`) to install it:
|
33
|
+
|
34
|
+
[![Packaging status](https://repology.org/badge/vertical-allrepos/sugarjar.svg)](https://repology.org/project/sugarjar/versions)
|
35
|
+
|
36
|
+
For Ubuntu users, Sugarjar will likely be available starting in the upcoming
|
37
|
+
23.04 release. Until then, for supported LTS releases starting 20.04 (focal)
|
38
|
+
and the latest non-LTS release, you can use [this PPA](
|
39
|
+
https://launchpad.net/~michel-slm/+archive/ubuntu/sugarjar) maintained by the
|
40
|
+
Debian package maintainer.
|
41
|
+
|
42
|
+
Another option is to use our [omnibus
|
43
|
+
packages](https://github.com/jaymzh/sugarjar/releases). We keep Omnibus
|
44
|
+
packages for most distros that do not package Sugarjar. Omnibus packages are
|
45
|
+
distro packages (deb, rpm, etc.) that have all dependencies bundled up together
|
46
|
+
(including Ruby), and install in `/opt/sugarjar` allowing you to manage the
|
47
|
+
installation with your package manager, but with as a hermetically sealed app
|
48
|
+
that doesn't depend on the rest of your distro.
|
49
|
+
|
50
|
+
Finally, if none of those work for you, you can clone this repo and run it
|
51
|
+
directly from there.
|
52
|
+
|
22
53
|
## Auto cleanup squash-merged branches
|
23
54
|
|
24
55
|
It is common for a PR to go back and forth with a variety of nits, lint fixes,
|
@@ -73,7 +104,7 @@ This will:
|
|
73
104
|
* Clone your fork
|
74
105
|
* Add the original as an 'upstream' remote
|
75
106
|
|
76
|
-
Note that it takes
|
107
|
+
Note that it takes short names for repos. No need to specify a full URL,
|
77
108
|
just a $org/$repo.
|
78
109
|
|
79
110
|
Like `git clone`, `sj sclone` will accept an additional argument as the
|
@@ -198,6 +229,15 @@ smartlog` or `sj sl` for short.
|
|
198
229
|
|
199
230
|
![smartlog screenshot](https://github.com/jaymzh/sugarjar/blob/master/smartlog.png)
|
200
231
|
|
232
|
+
## Pulling in suggestions from the web
|
233
|
+
|
234
|
+
When someone 'suggests' a change in the GitHub WebUI, once you choose to commit
|
235
|
+
them, your origin and local branches are no longer in-sync. The
|
236
|
+
`pullsuggestions` command will attempt to merge in any remote commits to your
|
237
|
+
local branch. This command will show a diff and ask for confirmation before
|
238
|
+
attempting the merge and - if allowed to continue - will use a fast-forward
|
239
|
+
merge.
|
240
|
+
|
201
241
|
## And more!
|
202
242
|
|
203
243
|
See `sj help` for more commands!
|
@@ -205,8 +245,11 @@ See `sj help` for more commands!
|
|
205
245
|
## Using SugarJar as a git wrapper
|
206
246
|
|
207
247
|
SugarJar, by default, will pass any command it doesn't know straight to `hub`
|
208
|
-
(which passes commands **it** doesn't know to `git`).
|
209
|
-
to `
|
248
|
+
(which passes commands **it** doesn't know to `git`). If you have configured
|
249
|
+
SugarJar to use `gh` instead of `hub`, then it will pass commands straight to
|
250
|
+
`git` since `gh` doesn't act as a `git` wrapper.
|
251
|
+
|
252
|
+
As such you can alias it to `git` and just have a super-git.
|
210
253
|
|
211
254
|
```shell
|
212
255
|
$ alias git=sj
|
@@ -248,8 +291,8 @@ log_level: debug
|
|
248
291
|
github_user: jaymzh
|
249
292
|
```
|
250
293
|
|
251
|
-
In addition, the environment variable `
|
252
|
-
|
294
|
+
In addition, the environment variable `SUGARJAR_LOGLEVEL` can be defined to set
|
295
|
+
a log level. This is primarily used as a way to turn debug on earlier in order to
|
253
296
|
troubleshoot configuration parsing.
|
254
297
|
|
255
298
|
## Repository Configuration
|
@@ -258,9 +301,15 @@ Sugarjar looks for a `.sugarjar.yaml` in the root of the repository to tell it
|
|
258
301
|
how to handle repo-specific things. Currently there options are:
|
259
302
|
|
260
303
|
* `lint` - A list of scripts to run on `sj lint`. These should be linters like
|
261
|
-
rubocop or pyflake.
|
304
|
+
rubocop or pyflake. Linters will be run from the root of the repo.
|
305
|
+
* `lint_list_cmd` - A command to run which will print out linters to run, one
|
306
|
+
per line. Takes precedence over `lint`. The command (and the resulting
|
307
|
+
linters) will be run from the root of the repo.
|
262
308
|
* `unit` - A list of scripts to run on `sj unit`. These should be unittest
|
263
|
-
runners like rspec or pyunit.
|
309
|
+
runners like rspec or pyunit. Test will be run from the root of the repo.
|
310
|
+
* `unit_list_cmd` - A command to run which will print out the unit tests to
|
311
|
+
run, one more line. Takes precedence over `unit`. The command (and the
|
312
|
+
resulting unit tests) will be run from the root of the repo.
|
264
313
|
* `on_push` - A list of types (`lint`, `unit`) of checks to run before pushing.
|
265
314
|
It is highly recommended this is only `lint`. The goal here is to allow for
|
266
315
|
the user to get quick stylistic feedback before pushing their branch to avoid
|
@@ -312,34 +361,40 @@ sj clone jaymzh/sugarjar --github-host githuh.com
|
|
312
361
|
We will add the `hub.host` to the `sugarjar` clone so that future `hub` or `sj`
|
313
362
|
commands work without needing to specify..
|
314
363
|
|
315
|
-
##
|
316
|
-
|
317
|
-
There are many ways to install SugarJar. The easiest is to use one of the
|
318
|
-
packages we provide in the
|
319
|
-
[releases](https://github.com/jaymzh/sugarjar/releases) section. Currently we
|
320
|
-
provide packages for Fedora, CentOS, Debian, and Ubuntu, but if you want
|
321
|
-
others, file an Issue. Since these packages are
|
322
|
-
[omnibus](https://github.com/chef/omnibus) packages which means they are bundled
|
323
|
-
with all of their dependencies. This means these packages will likely work as-is
|
324
|
-
on later releases of these distros or any similar distros.
|
364
|
+
## Choosing a GitHub CLI
|
325
365
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
366
|
+
SugarJar will use `gh` if it is available or otherwise fall back to `hub`. You
|
367
|
+
can override this by specifying `--github-cli` on the command line or setting
|
368
|
+
`github_cli` to either `gh` or `hub` (it defaults to `auto`) in your
|
369
|
+
configuration.
|
330
370
|
|
331
371
|
## FAQ
|
332
372
|
|
333
|
-
Why the name SugarJar
|
373
|
+
**Why the name SugarJar?**
|
334
374
|
|
335
|
-
It's mostly a
|
375
|
+
It's mostly a backronym. Like jellyfish, I wanted two letters that were on home
|
336
376
|
row on different sides of the keyboard to make it easy to type. I looked at the
|
337
377
|
possible options that where there and not taken and tried to find one I could
|
338
378
|
make an appropriate name out of. Since this utility adds lots of sugar to git
|
339
379
|
and github, it seemed appropriate.
|
340
380
|
|
341
|
-
Why did you use `hub` instead of the newer `gh` CLI
|
381
|
+
**Why did you originally use `hub` instead of the newer `gh` CLI?**
|
382
|
+
|
383
|
+
When I originally wrote SugarJar, `gh` was in early development, and `hub` had
|
384
|
+
many more features. In addition, I wrote SugarJar to be a wrapper for git/hub,
|
385
|
+
and `hub` allows this but `gh` does not.
|
386
|
+
|
387
|
+
When `gh` matured, we added experimental `gh` support in 0.0.11, and switched the
|
388
|
+
default to prefer `gh` in 1.0.0.
|
389
|
+
|
390
|
+
**I'd like to package SugarJar for my favorite distro/OS, is that OK?**
|
391
|
+
|
392
|
+
Of course! But I'd appreciate you emailing me to give me a heads up. Doing so
|
393
|
+
will allow me to make sure it shows up in the Repology badge above as well as
|
394
|
+
stop building Omnibus packages for whatever distro.
|
395
|
+
|
396
|
+
**What platforms does it work on?**
|
342
397
|
|
343
|
-
|
344
|
-
|
345
|
-
|
398
|
+
Since it's Ruby, it should work across all platforms, however, it's developed
|
399
|
+
and primarily tested on Linux as well as regularly used on Mac. I've not tested
|
400
|
+
it on Windows, but I'll happily accept patches for Windows compatibility.
|
data/bin/sj
CHANGED
@@ -29,12 +29,22 @@ parser = OptionParser.new do |opts|
|
|
29
29
|
opts.separator ''
|
30
30
|
opts.separator 'OPTIONS:'
|
31
31
|
|
32
|
-
opts.on('--[no-]fallthru', 'Fall-thru to git') do |fallthru|
|
32
|
+
opts.on('--[no-]fallthru', 'Fall-thru to git. [default: true]') do |fallthru|
|
33
33
|
options['fallthru'] = fallthru
|
34
34
|
end
|
35
35
|
|
36
|
-
opts.on('--
|
37
|
-
options['
|
36
|
+
opts.on('--feature-prefix', 'Prefix to use for feature branches') do |prefix|
|
37
|
+
options['feature_prefix'] = prefix
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on(
|
41
|
+
'--github-cli CLI',
|
42
|
+
%w{gh cli},
|
43
|
+
'Github CLI to use ("gh" or "hub" or "auto"). Auto (the default) will ' +
|
44
|
+
'prefer "gh" if it is available but will fall back to "hub." ' +
|
45
|
+
'[default: "auto"]',
|
46
|
+
) do |cli|
|
47
|
+
options['github_cli'] = cli
|
38
48
|
end
|
39
49
|
|
40
50
|
opts.on(
|
@@ -48,6 +58,10 @@ parser = OptionParser.new do |opts|
|
|
48
58
|
options['github_host'] = host
|
49
59
|
end
|
50
60
|
|
61
|
+
opts.on('--github-user USER', 'Github username') do |user|
|
62
|
+
options['github_user'] = user
|
63
|
+
end
|
64
|
+
|
51
65
|
opts.on('-h', '--help', 'Print this help message') do
|
52
66
|
puts opts
|
53
67
|
exit
|
@@ -55,22 +69,24 @@ parser = OptionParser.new do |opts|
|
|
55
69
|
|
56
70
|
opts.on(
|
57
71
|
'--ignore-dirty',
|
58
|
-
'Tell command that check for a dirty repo to carry on anyway.'
|
72
|
+
'Tell command that check for a dirty repo to carry on anyway. ' +
|
73
|
+
'[default: false]',
|
59
74
|
) do
|
60
75
|
options['ignore_dirty'] = true
|
61
76
|
end
|
62
77
|
|
63
78
|
opts.on(
|
64
79
|
'--ignore-prerun-failure',
|
65
|
-
'Ignore preprun failure on *push commands.',
|
80
|
+
'Ignore preprun failure on *push commands. [default: false]',
|
66
81
|
) do
|
67
82
|
options['ignore_prerun_failure'] = true
|
68
83
|
end
|
69
84
|
|
70
85
|
opts.on(
|
71
86
|
'--log-level LEVEL',
|
72
|
-
'Set logging level (fatal, error, warning, info, debug, trace).
|
73
|
-
'
|
87
|
+
'Set logging level (fatal, error, warning, info, debug, trace). This can ' +
|
88
|
+
'also be set via the SUGARJAR_LOGLEVEL environment variable. [default: ' +
|
89
|
+
'info]',
|
74
90
|
) do |level|
|
75
91
|
options['log_level'] = level
|
76
92
|
end
|
@@ -118,6 +134,12 @@ COMMANDS:
|
|
118
134
|
of preference it will be upstream/master, origin/master, master,
|
119
135
|
depending upon what remotes are available.
|
120
136
|
|
137
|
+
Note that you can specify "--feature-prefix" (or add
|
138
|
+
"feature_prefix" to your config) to have all features created
|
139
|
+
with a prefix. This is useful for branch-based workflows where
|
140
|
+
developers are expected to create branches names that, for
|
141
|
+
example, start with their username.
|
142
|
+
|
121
143
|
forcepush, fpush
|
122
144
|
The same as "smartpush", but uses "--force-with-lease". This is
|
123
145
|
a "safer" way of doing force-pushes and is the recommended way
|
@@ -128,6 +150,11 @@ COMMANDS:
|
|
128
150
|
lint
|
129
151
|
Run any linters configured in .sugarjar.yaml.
|
130
152
|
|
153
|
+
pullsuggestions, ps
|
154
|
+
Pull any suggestions *that have been committed* in the GitHub UI.
|
155
|
+
This will show the diff and prompt for confirmation before
|
156
|
+
merging. Note that a fast-forward merge will be used.
|
157
|
+
|
131
158
|
smartclone, sclone
|
132
159
|
A smart wrapper to "git clone" that handles forking and managing
|
133
160
|
remotes for you.
|
@@ -162,6 +189,10 @@ COMMANDS:
|
|
162
189
|
version
|
163
190
|
Print the version of sugarjar, and then run 'hub version'
|
164
191
|
to show the hub and git versions.
|
192
|
+
|
193
|
+
Be sure to checkout Sapling (https://sapling-scm.com/)! This was written as
|
194
|
+
a stop-gap to get Sapling features before it was open-sourced, and as such
|
195
|
+
I may deprecate this in the future.
|
165
196
|
COMMANDS
|
166
197
|
|
167
198
|
# rubocop:enable Layout/HeredocIndentation
|
@@ -232,7 +263,9 @@ else
|
|
232
263
|
end
|
233
264
|
end
|
234
265
|
|
235
|
-
|
266
|
+
subcommand = argv_copy.reject { |x| x.start_with?('-') }.first
|
267
|
+
|
268
|
+
if ARGV.empty? || !subcommand
|
236
269
|
puts parser
|
237
270
|
exit
|
238
271
|
end
|
@@ -243,7 +276,6 @@ options = config.merge(options)
|
|
243
276
|
SugarJar::Log.level = options['log_level'].to_sym if options['log_level']
|
244
277
|
sj = SugarJar::Commands.new(options)
|
245
278
|
|
246
|
-
subcommand = argv_copy.reject { |x| x.start_with?('-') }.first
|
247
279
|
is_valid_command = valid_commands.include?(subcommand.to_sym)
|
248
280
|
argv_copy.delete(subcommand)
|
249
281
|
SugarJar::Log.debug("subcommand is #{subcommand}")
|
@@ -265,7 +297,13 @@ if is_valid_command
|
|
265
297
|
sj.send(subcommand.to_sym, *extra_opts)
|
266
298
|
elsif options['fallthru']
|
267
299
|
SugarJar::Log.debug("Falling thru to: hub #{ARGV.join(' ')}")
|
268
|
-
|
300
|
+
if options['github_cli'] == 'hub'
|
301
|
+
exec('hub', *ARGV)
|
302
|
+
else
|
303
|
+
# If we're using 'gh', it doesn't have 'git fall thru' support, so
|
304
|
+
# we pass thru directly to 'git'
|
305
|
+
exec('git', *ARGV)
|
306
|
+
end
|
269
307
|
else
|
270
308
|
SugarJar::Log.error("No such subcommand: #{subcommand}")
|
271
309
|
end
|
data/lib/sugarjar/commands.rb
CHANGED
@@ -22,20 +22,29 @@ class SugarJar
|
|
22
22
|
@ignore_prerun_failure = options['ignore_prerun_failure']
|
23
23
|
@repo_config = SugarJar::RepoConfig.config
|
24
24
|
@color = options['color']
|
25
|
+
@feature_prefix = options['feature_prefix']
|
26
|
+
@checks = {}
|
27
|
+
@main_branch = nil
|
28
|
+
@main_remote_branches = {}
|
25
29
|
return if options['no_change']
|
26
30
|
|
27
|
-
|
31
|
+
# technically this doesn't "change" things, but we won't have this
|
32
|
+
# option on the no_change call
|
33
|
+
@cli = determine_cli(options['github_cli'])
|
34
|
+
|
35
|
+
set_hub_host
|
28
36
|
set_commit_template if @repo_config['commit_template']
|
29
37
|
end
|
30
38
|
|
31
39
|
def feature(name, base = nil)
|
32
40
|
assert_in_repo
|
33
41
|
SugarJar::Log.debug("Feature: #{name}, #{base}")
|
34
|
-
|
42
|
+
name = fprefix(name)
|
43
|
+
die("#{name} already exists!") if all_local_branches.include?(name)
|
35
44
|
base ||= most_main
|
36
45
|
base_pieces = base.split('/')
|
37
|
-
|
38
|
-
|
46
|
+
git('fetch', base_pieces[0]) if base_pieces.length > 1
|
47
|
+
git('checkout', '-b', name, base)
|
39
48
|
SugarJar::Log.info(
|
40
49
|
"Created feature branch #{color(name, :green)} based on " +
|
41
50
|
color(base, :green),
|
@@ -45,6 +54,7 @@ class SugarJar
|
|
45
54
|
def bclean(name = nil)
|
46
55
|
assert_in_repo
|
47
56
|
name ||= current_branch
|
57
|
+
name = fprefix(name) unless all_local_branches.include?(name)
|
48
58
|
if clean_branch(name)
|
49
59
|
SugarJar::Log.info("#{name}: #{color('reaped', :green)}")
|
50
60
|
else
|
@@ -58,7 +68,7 @@ class SugarJar
|
|
58
68
|
def bcleanall
|
59
69
|
assert_in_repo
|
60
70
|
curr = current_branch
|
61
|
-
|
71
|
+
all_local_branches.each do |branch|
|
62
72
|
if MAIN_BRANCHES.include?(branch)
|
63
73
|
SugarJar::Log.debug("Skipping #{branch}")
|
64
74
|
next
|
@@ -76,8 +86,8 @@ class SugarJar
|
|
76
86
|
end
|
77
87
|
|
78
88
|
# Return to the branch we were on, or main
|
79
|
-
if
|
80
|
-
|
89
|
+
if all_local_branches.include?(curr)
|
90
|
+
git('checkout', curr)
|
81
91
|
else
|
82
92
|
checkout_main_branch
|
83
93
|
end
|
@@ -85,18 +95,18 @@ class SugarJar
|
|
85
95
|
|
86
96
|
def co(*args)
|
87
97
|
assert_in_repo
|
88
|
-
s =
|
98
|
+
s = git('checkout', *args)
|
89
99
|
SugarJar::Log.info(s.stderr + s.stdout.chomp)
|
90
100
|
end
|
91
101
|
|
92
102
|
def br
|
93
103
|
assert_in_repo
|
94
|
-
SugarJar::Log.info(
|
104
|
+
SugarJar::Log.info(git('branch', '-v').stdout.chomp)
|
95
105
|
end
|
96
106
|
|
97
107
|
def binfo
|
98
108
|
assert_in_repo
|
99
|
-
SugarJar::Log.info(
|
109
|
+
SugarJar::Log.info(git(
|
100
110
|
'log', '--graph', '--oneline', '--decorate', '--boundary',
|
101
111
|
"#{tracked_branch}.."
|
102
112
|
).stdout.chomp)
|
@@ -105,7 +115,7 @@ class SugarJar
|
|
105
115
|
# binfo for all branches
|
106
116
|
def smartlog
|
107
117
|
assert_in_repo
|
108
|
-
SugarJar::Log.info(
|
118
|
+
SugarJar::Log.info(git(
|
109
119
|
'log', '--graph', '--oneline', '--decorate', '--boundary',
|
110
120
|
'--branches', "#{most_main}.."
|
111
121
|
).stdout.chomp)
|
@@ -142,24 +152,24 @@ class SugarJar
|
|
142
152
|
|
143
153
|
def qamend(*args)
|
144
154
|
assert_in_repo
|
145
|
-
SugarJar::Log.info(
|
155
|
+
SugarJar::Log.info(git('commit', '--amend', '--no-edit', *args).stdout)
|
146
156
|
end
|
147
157
|
|
148
158
|
alias amendq qamend
|
149
159
|
|
150
160
|
def upall
|
151
161
|
assert_in_repo
|
152
|
-
|
162
|
+
all_local_branches.each do |branch|
|
153
163
|
next if MAIN_BRANCHES.include?(branch)
|
154
164
|
|
155
|
-
|
165
|
+
git('checkout', branch)
|
156
166
|
result = gitup
|
157
167
|
if result['so'].error?
|
158
168
|
SugarJar::Log.error(
|
159
169
|
"#{color(branch, :red)} failed rebase. Reverting attempt and " +
|
160
170
|
'moving to next branch. Try `sj up` manually on that branch.',
|
161
171
|
)
|
162
|
-
|
172
|
+
git('rebase', '--abort')
|
163
173
|
else
|
164
174
|
SugarJar::Log.info(
|
165
175
|
"#{color(branch, :green)} rebased on " +
|
@@ -176,21 +186,42 @@ class SugarJar
|
|
176
186
|
|
177
187
|
reponame = File.basename(repo, '.git')
|
178
188
|
dir ||= reponame
|
189
|
+
org = extract_org(repo)
|
190
|
+
|
179
191
|
SugarJar::Log.info("Cloning #{reponame}...")
|
180
|
-
hub('clone', canonicalize_repo(repo), dir, *args)
|
181
192
|
|
193
|
+
# GH's 'fork' command (with the --clone arg) will fork, if necessary,
|
194
|
+
# then clone, and then setup the remotes with the appropriate names. So
|
195
|
+
# we just let it do all the work for us and return.
|
196
|
+
#
|
197
|
+
# Unless the repo is in our own org and cannot be forked, then it
|
198
|
+
# will fail.
|
199
|
+
if gh? && org != @ghuser
|
200
|
+
ghcli('repo', 'fork', '--clone', canonicalize_repo(repo), dir, *args)
|
201
|
+
SugarJar::Log.info('Remotes "origin" and "upstream" configured.')
|
202
|
+
return
|
203
|
+
end
|
204
|
+
|
205
|
+
# For 'hub' first we clone, using git, as 'hub' always needs a repo to
|
206
|
+
# operate on.
|
207
|
+
#
|
208
|
+
# Or for 'gh' when we can't fork...
|
209
|
+
git('clone', canonicalize_repo(repo), dir, *args)
|
210
|
+
|
211
|
+
# Then we go into it and attempt to use the 'fork' capability
|
212
|
+
# or if not
|
182
213
|
Dir.chdir dir do
|
183
214
|
# Now that we have a repo, if we have a hub host set it.
|
184
|
-
set_hub_host
|
215
|
+
set_hub_host
|
185
216
|
|
186
|
-
org = extract_org(repo)
|
187
217
|
SugarJar::Log.debug("Comparing org #{org} to ghuser #{@ghuser}")
|
188
218
|
if org == @ghuser
|
189
219
|
puts 'Cloned forked or self-owned repo. Not creating "upstream".'
|
220
|
+
SugarJar::Log.info('Remotes "origin" and "upstream" configured.')
|
190
221
|
return
|
191
222
|
end
|
192
223
|
|
193
|
-
s =
|
224
|
+
s = ghcli_nofail('repo', 'fork', '--remote-name=origin')
|
194
225
|
if s.error?
|
195
226
|
if s.stdout.include?('SAML enforcement')
|
196
227
|
SugarJar::Log.info(
|
@@ -199,18 +230,18 @@ class SugarJar
|
|
199
230
|
)
|
200
231
|
exit(1)
|
201
232
|
else
|
202
|
-
#
|
203
|
-
# already existed. If we got an error, but didn't recognize
|
204
|
-
# that, we'll assume that's what happened and try to add the
|
205
|
-
#
|
233
|
+
# gh as well as old versions of hub, it would fail if the upstream
|
234
|
+
# fork already existed. If we got an error, but didn't recognize
|
235
|
+
# that, we'll assume that's what happened and try to add the remote
|
236
|
+
# ourselves.
|
206
237
|
SugarJar::Log.info("Fork (#{@ghuser}/#{reponame}) detected.")
|
207
238
|
SugarJar::Log.debug(
|
208
239
|
'The above is a bit of a lie. "hub" failed to fork and it was ' +
|
209
240
|
'not a SAML error, so our best guess is that a fork exists ' +
|
210
241
|
'and so we will try to configure it.',
|
211
242
|
)
|
212
|
-
|
213
|
-
|
243
|
+
git('remote', 'rename', 'origin', 'upstream')
|
244
|
+
git('remote', 'add', 'origin', forked_repo(repo, @ghuser))
|
214
245
|
end
|
215
246
|
else
|
216
247
|
SugarJar::Log.info("Forked #{reponame} to #{@ghuser}")
|
@@ -247,11 +278,15 @@ class SugarJar
|
|
247
278
|
|
248
279
|
def version
|
249
280
|
puts "sugarjar version #{SugarJar::VERSION}"
|
250
|
-
puts
|
281
|
+
puts ghcli('version').stdout
|
282
|
+
# 'hub' prints the 'git' version, but gh doesn't, so if we're on 'gh'
|
283
|
+
# print out the git version directly
|
284
|
+
puts git('version').stdout if gh?
|
251
285
|
end
|
252
286
|
|
253
|
-
def smartpullrequest
|
287
|
+
def smartpullrequest(*args)
|
254
288
|
assert_in_repo
|
289
|
+
assert_common_main_branch
|
255
290
|
if dirty?
|
256
291
|
SugarJar::Log.warn(
|
257
292
|
'Your repo is dirty, so I am not going to create a pull request. ' +
|
@@ -259,14 +294,73 @@ class SugarJar
|
|
259
294
|
)
|
260
295
|
exit(1)
|
261
296
|
end
|
262
|
-
|
297
|
+
if gh?
|
298
|
+
SugarJar::Log.trace("Running: gh pr create #{args.join(' ')}")
|
299
|
+
system(which('gh'), 'pr', 'create', *args)
|
300
|
+
else
|
301
|
+
SugarJar::Log.trace("Running: hub pull-request #{args.join(' ')}")
|
302
|
+
system(which('hub'), 'pull-request', *args)
|
303
|
+
end
|
263
304
|
end
|
264
305
|
|
265
306
|
alias spr smartpullrequest
|
266
307
|
alias smartpr smartpullrequest
|
267
308
|
|
309
|
+
def pullsuggestions
|
310
|
+
assert_in_repo
|
311
|
+
|
312
|
+
if dirty?
|
313
|
+
if @ignore_dirty
|
314
|
+
SugarJar::Log.warn(
|
315
|
+
'Your repo is dirty, but --ignore-dirty was specified, so ' +
|
316
|
+
'carrying on anyway.',
|
317
|
+
)
|
318
|
+
else
|
319
|
+
SugarJar::Log.error(
|
320
|
+
'Your repo is dirty, so I am not going to push. Please commit ' +
|
321
|
+
'or amend first.',
|
322
|
+
)
|
323
|
+
exit(1)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
src = "origin/#{current_branch}"
|
328
|
+
fetch('origin')
|
329
|
+
diff = git('diff', src).stdout
|
330
|
+
return unless diff && !diff.empty?
|
331
|
+
|
332
|
+
puts "Will merge the following suggestions:\n\n#{diff}"
|
333
|
+
|
334
|
+
loop do
|
335
|
+
$stdout.print("\nAre you sure? [y/n] ")
|
336
|
+
ans = $stdin.gets.strip
|
337
|
+
case ans
|
338
|
+
when /^[Yy]$/
|
339
|
+
system(which('git'), 'merge', '--ff', "origin/#{current_branch}")
|
340
|
+
break
|
341
|
+
when /^[Nn]$/, /^[Qq](uit)?/
|
342
|
+
puts 'Not merging at user request...'
|
343
|
+
break
|
344
|
+
else
|
345
|
+
puts "Didn't understand '#{ans}'."
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
alias ps pullsuggestions
|
351
|
+
|
268
352
|
private
|
269
353
|
|
354
|
+
def fprefix(name)
|
355
|
+
return name unless @feature_prefix
|
356
|
+
|
357
|
+
newname = "#{@feature_prefix}#{name}"
|
358
|
+
SugarJar::Log.debug(
|
359
|
+
"Munging feature name: #{name} -> #{newname} due to feature prefix",
|
360
|
+
)
|
361
|
+
newname
|
362
|
+
end
|
363
|
+
|
270
364
|
def _smartpush(remote, branch, force)
|
271
365
|
unless remote && branch
|
272
366
|
remote ||= 'origin'
|
@@ -302,11 +396,11 @@ class SugarJar
|
|
302
396
|
|
303
397
|
args = ['push', remote, branch]
|
304
398
|
args << '--force-with-lease' if force
|
305
|
-
puts
|
399
|
+
puts git(*args).stderr
|
306
400
|
end
|
307
401
|
|
308
402
|
def dirty?
|
309
|
-
s =
|
403
|
+
s = git_nofail('diff', '--quiet')
|
310
404
|
s.error?
|
311
405
|
end
|
312
406
|
|
@@ -343,9 +437,9 @@ class SugarJar
|
|
343
437
|
end
|
344
438
|
|
345
439
|
def set_hub_host
|
346
|
-
return unless in_repo
|
440
|
+
return unless hub? && in_repo && @ghhost
|
347
441
|
|
348
|
-
s =
|
442
|
+
s = git_nofail('config', '--local', '--get', 'hub.host')
|
349
443
|
if s.error?
|
350
444
|
SugarJar::Log.info("Setting repo hub.host = #{@ghhost}")
|
351
445
|
else
|
@@ -363,7 +457,7 @@ class SugarJar
|
|
363
457
|
end
|
364
458
|
return
|
365
459
|
end
|
366
|
-
|
460
|
+
git('config', '--local', '--add', 'hub.host', @ghhost)
|
367
461
|
end
|
368
462
|
|
369
463
|
def set_commit_template
|
@@ -384,7 +478,7 @@ class SugarJar
|
|
384
478
|
)
|
385
479
|
end
|
386
480
|
|
387
|
-
s =
|
481
|
+
s = git_nofail('config', '--local', 'commit.template')
|
388
482
|
unless s.error?
|
389
483
|
current = s.stdout.strip
|
390
484
|
if current == @repo_config['commit_template']
|
@@ -402,18 +496,60 @@ class SugarJar
|
|
402
496
|
'Setting repo-specific commit template to ' +
|
403
497
|
"#{@repo_config['commit_template']} per sugarjar repo config.",
|
404
498
|
)
|
405
|
-
|
499
|
+
git(
|
406
500
|
'config', '--local', 'commit.template', @repo_config['commit_template']
|
407
501
|
)
|
408
502
|
end
|
409
503
|
|
410
|
-
def
|
411
|
-
unless @repo_config[type]
|
412
|
-
|
413
|
-
|
504
|
+
def get_checks_from_command(type)
|
505
|
+
return nil unless @repo_config["#{type}_list_cmd"]
|
506
|
+
|
507
|
+
cmd = @repo_config["#{type}_list_cmd"]
|
508
|
+
short = cmd.split.first
|
509
|
+
unless File.exist?(short)
|
510
|
+
SugarJar::Log.error(
|
511
|
+
"Configured #{type}_list_cmd #{short} does not exist!",
|
512
|
+
)
|
513
|
+
return false
|
514
|
+
end
|
515
|
+
s = Mixlib::ShellOut.new(cmd).run_command
|
516
|
+
if s.error?
|
517
|
+
SugarJar::Log.error(
|
518
|
+
"#{type}_list_cmd (#{cmd}) failed: #{s.format_for_exception}",
|
519
|
+
)
|
520
|
+
return false
|
521
|
+
end
|
522
|
+
s.stdout.split("\n")
|
523
|
+
end
|
524
|
+
|
525
|
+
# determine if we're using the _list_cmd and if so run it to get the
|
526
|
+
# checks, or just use the directly-defined check, and cache it
|
527
|
+
def get_checks(type)
|
528
|
+
return @checks[type] if @checks[type]
|
529
|
+
|
530
|
+
ret = get_checks_from_command(type)
|
531
|
+
if ret
|
532
|
+
SugarJar::Log.debug("Found #{type}s: #{ret}")
|
533
|
+
@checks[type] = ret
|
534
|
+
# if it's explicitly false, we failed to run the command
|
535
|
+
elsif ret == false
|
536
|
+
@checks[type] = false
|
537
|
+
# otherwise, we move on (basically: it's nil, there was no _list_cmd)
|
538
|
+
else
|
539
|
+
SugarJar::Log.debug("[#{type}]: using listed linters: #{ret}")
|
540
|
+
@checks[type] = @repo_config[type] || []
|
414
541
|
end
|
542
|
+
@checks[type]
|
543
|
+
end
|
544
|
+
|
545
|
+
def run_check(type)
|
415
546
|
Dir.chdir repo_root do
|
416
|
-
|
547
|
+
checks = get_checks(type)
|
548
|
+
# if we failed to determine the checks, the the checks have effectively
|
549
|
+
# failed
|
550
|
+
return false unless checks
|
551
|
+
|
552
|
+
checks.each do |check|
|
417
553
|
SugarJar::Log.debug("Running #{type} #{check}")
|
418
554
|
|
419
555
|
short = check.split.first
|
@@ -431,7 +567,7 @@ class SugarJar
|
|
431
567
|
SugarJar::Log.warn(
|
432
568
|
"The linter modified the repo. Here's the diff:\n",
|
433
569
|
)
|
434
|
-
puts
|
570
|
+
puts git('diff').stdout
|
435
571
|
loop do
|
436
572
|
$stdout.print(
|
437
573
|
"\nWould you like to\n\t[q]uit and inspect\n\t[a]mend the " +
|
@@ -483,16 +619,53 @@ class SugarJar
|
|
483
619
|
exit(1)
|
484
620
|
end
|
485
621
|
|
622
|
+
def assert_common_main_branch
|
623
|
+
upstream_branch = main_remote_branch(upstream)
|
624
|
+
unless main_branch == upstream_branch
|
625
|
+
die(
|
626
|
+
"The local main branch is '#{main_branch}', but the main branch " +
|
627
|
+
"of the #{upstream} remote is '#{upstream_branch}'. You probably " +
|
628
|
+
"want to rename your local branch by doing:\n\t" +
|
629
|
+
"git branch -m #{main_branch} #{upstream_branch}\n\t" +
|
630
|
+
"git fetch #{upstream}\n\t" +
|
631
|
+
"git branch -u #{upstream}/#{upstream_branch} #{upstream_branch}\n" +
|
632
|
+
"\tgit remote set-head #{upstream} -a",
|
633
|
+
)
|
634
|
+
end
|
635
|
+
return if upstream_branch == 'origin'
|
636
|
+
|
637
|
+
origin_branch = main_remote_branch('origin')
|
638
|
+
return if origin_branch == upstream_branch
|
639
|
+
|
640
|
+
die(
|
641
|
+
"The main branch of your upstream (#{upstream_branch}) and your " +
|
642
|
+
"fork/origin (#{origin_branch}) are not the same. You should go " +
|
643
|
+
"to https://#{@ghhost || 'github.com'}/#{@ghuser}/#{repo_name}/" +
|
644
|
+
'branches/ and rename the \'default\' branch to ' +
|
645
|
+
"'#{upstream_branch}'. It will then give you some commands to " +
|
646
|
+
'run to update this clone.',
|
647
|
+
)
|
648
|
+
end
|
649
|
+
|
486
650
|
def assert_in_repo
|
487
651
|
die('sugarjar must be run from inside a git repo') unless in_repo
|
488
652
|
end
|
489
653
|
|
654
|
+
def determine_main_branch(branches)
|
655
|
+
branches.include?('main') ? 'main' : 'master'
|
656
|
+
end
|
657
|
+
|
490
658
|
def main_branch
|
491
|
-
@main_branch =
|
659
|
+
@main_branch = determine_main_branch(all_local_branches)
|
660
|
+
end
|
661
|
+
|
662
|
+
def main_remote_branch(remote)
|
663
|
+
@main_remote_branches[remote] ||=
|
664
|
+
determine_main_branch(all_remote_branches(remote))
|
492
665
|
end
|
493
666
|
|
494
667
|
def checkout_main_branch
|
495
|
-
|
668
|
+
git('checkout', main_branch)
|
496
669
|
end
|
497
670
|
|
498
671
|
def clean_branch(name)
|
@@ -503,15 +676,25 @@ class SugarJar
|
|
503
676
|
|
504
677
|
SugarJar::Log.debug('branch deemed safe to delete...')
|
505
678
|
checkout_main_branch
|
506
|
-
|
679
|
+
git('branch', '-D', name)
|
507
680
|
gitup
|
508
681
|
true
|
509
682
|
end
|
510
683
|
|
511
|
-
def
|
684
|
+
def all_remote_branches(remote = 'origin')
|
685
|
+
branches = []
|
686
|
+
git('branch', '-r', '--format', '%(refname)').stdout.lines.each do |line|
|
687
|
+
next unless line.start_with?("refs/remotes/#{remote}/")
|
688
|
+
|
689
|
+
branches << branch_from_ref(line.strip, :remote)
|
690
|
+
end
|
691
|
+
branches
|
692
|
+
end
|
693
|
+
|
694
|
+
def all_local_branches
|
512
695
|
branches = []
|
513
|
-
|
514
|
-
branches << line.strip
|
696
|
+
git('branch', '--format', '%(refname)').stdout.lines.each do |line|
|
697
|
+
branches << branch_from_ref(line.strip)
|
515
698
|
end
|
516
699
|
branches
|
517
700
|
end
|
@@ -520,12 +703,12 @@ class SugarJar
|
|
520
703
|
# cherry -v will output 1 line per commit on the target branch
|
521
704
|
# prefixed by a - or + - anything with a - can be dropped, anything
|
522
705
|
# else cannot.
|
523
|
-
out =
|
706
|
+
out = git(
|
524
707
|
'cherry', '-v', tracked_branch, branch
|
525
708
|
).stdout.lines.reject do |line|
|
526
709
|
line.start_with?('-')
|
527
710
|
end
|
528
|
-
if out.
|
711
|
+
if out.empty?
|
529
712
|
SugarJar::Log.debug(
|
530
713
|
"cherry-pick shows branch #{branch} obviously safe to delete",
|
531
714
|
)
|
@@ -539,8 +722,8 @@ class SugarJar
|
|
539
722
|
# First we need a temp branch to work on
|
540
723
|
tmpbranch = "_sugar_jar.#{Process.pid}"
|
541
724
|
|
542
|
-
|
543
|
-
s =
|
725
|
+
git('checkout', '-b', tmpbranch, tracked_branch)
|
726
|
+
s = git_nofail('merge', '--squash', branch)
|
544
727
|
if s.error?
|
545
728
|
cleanup_tmp_branch(tmpbranch, branch)
|
546
729
|
SugarJar::Log.debug(
|
@@ -551,7 +734,7 @@ class SugarJar
|
|
551
734
|
return false
|
552
735
|
end
|
553
736
|
|
554
|
-
s =
|
737
|
+
s = git('diff', '--staged')
|
555
738
|
out = s.stdout
|
556
739
|
SugarJar::Log.debug("Squash-merged diff: #{out}")
|
557
740
|
cleanup_tmp_branch(tmpbranch, branch)
|
@@ -569,18 +752,22 @@ class SugarJar
|
|
569
752
|
end
|
570
753
|
|
571
754
|
def cleanup_tmp_branch(tmp, backto)
|
572
|
-
|
573
|
-
|
574
|
-
|
755
|
+
git('reset', '--hard', tracked_branch)
|
756
|
+
git('checkout', backto)
|
757
|
+
git('branch', '-D', tmp)
|
575
758
|
end
|
576
759
|
|
577
760
|
def current_branch
|
578
|
-
|
761
|
+
branch_from_ref(git('symbolic-ref', 'HEAD').stdout.strip)
|
579
762
|
end
|
580
763
|
|
581
764
|
def fetch_upstream
|
582
765
|
us = upstream
|
583
|
-
|
766
|
+
fetch(us) if us
|
767
|
+
end
|
768
|
+
|
769
|
+
def fetch(remote)
|
770
|
+
git('fetch', remote)
|
584
771
|
end
|
585
772
|
|
586
773
|
def gitup
|
@@ -598,7 +785,7 @@ class SugarJar
|
|
598
785
|
)
|
599
786
|
end
|
600
787
|
SugarJar::Log.debug('Rebasing')
|
601
|
-
s =
|
788
|
+
s = git_nofail('rebase', base)
|
602
789
|
{
|
603
790
|
'so' => s,
|
604
791
|
'base' => base,
|
@@ -606,7 +793,7 @@ class SugarJar
|
|
606
793
|
end
|
607
794
|
|
608
795
|
def tracked_branch
|
609
|
-
s =
|
796
|
+
s = git_nofail(
|
610
797
|
'rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}'
|
611
798
|
)
|
612
799
|
if s.error?
|
@@ -628,7 +815,7 @@ class SugarJar
|
|
628
815
|
def upstream
|
629
816
|
return @remote if @remote
|
630
817
|
|
631
|
-
s =
|
818
|
+
s = git('remote')
|
632
819
|
|
633
820
|
remotes = s.stdout.lines.map(&:strip)
|
634
821
|
SugarJar::Log.debug("remotes is #{remotes}")
|
@@ -646,6 +833,13 @@ class SugarJar
|
|
646
833
|
@remote
|
647
834
|
end
|
648
835
|
|
836
|
+
def branch_from_ref(ref, type = :local)
|
837
|
+
# local branches are refs/head/XXXX
|
838
|
+
# remote branches are refs/remotes/<remote>/XXXX
|
839
|
+
base = type == :local ? 2 : 3
|
840
|
+
ref.split('/')[base..].join('/')
|
841
|
+
end
|
842
|
+
|
649
843
|
def color(string, *colors)
|
650
844
|
if @color
|
651
845
|
pastel.decorate(string, *colors)
|
@@ -660,5 +854,44 @@ class SugarJar
|
|
660
854
|
Pastel.new
|
661
855
|
end
|
662
856
|
end
|
857
|
+
|
858
|
+
def determine_cli(cli)
|
859
|
+
return cli if %w{gh hub}.include?(cli)
|
860
|
+
|
861
|
+
die("'github_cli' has unknown setting: #{cli}") unless cli == 'auto'
|
862
|
+
|
863
|
+
SugarJar::Log.debug('github_cli set to auto')
|
864
|
+
|
865
|
+
if which_nofail('gh')
|
866
|
+
SugarJar::Log.debug('Found "gh"')
|
867
|
+
return 'gh'
|
868
|
+
end
|
869
|
+
if which_nofail('hub')
|
870
|
+
SugarJar::Log.debug('Did not find "gh" but did find "hub"')
|
871
|
+
return 'hub'
|
872
|
+
end
|
873
|
+
|
874
|
+
die(
|
875
|
+
'Neither "gh" nor "hub" found in PATH, please ensure at least one ' +
|
876
|
+
'of these utilities is in the PATH. If both are available you can ' +
|
877
|
+
'specify which to use with --github-cli',
|
878
|
+
)
|
879
|
+
end
|
880
|
+
|
881
|
+
def hub?
|
882
|
+
@cli == 'hub'
|
883
|
+
end
|
884
|
+
|
885
|
+
def gh?
|
886
|
+
@cli == 'gh'
|
887
|
+
end
|
888
|
+
|
889
|
+
def ghcli_nofail(*args)
|
890
|
+
gh? ? gh_nofail(*args) : hub_nofail(*args)
|
891
|
+
end
|
892
|
+
|
893
|
+
def ghcli(*args)
|
894
|
+
gh? ? gh(*args) : hub(*args)
|
895
|
+
end
|
663
896
|
end
|
664
897
|
end
|
data/lib/sugarjar/config.rb
CHANGED
@@ -6,14 +6,15 @@ class SugarJar
|
|
6
6
|
# This is stuff like log level, github-user, etc.
|
7
7
|
class Config
|
8
8
|
DEFAULTS = {
|
9
|
-
'
|
9
|
+
'github_cli' => 'auto',
|
10
|
+
'github_user' => ENV.fetch('USER'),
|
10
11
|
'fallthru' => true,
|
11
12
|
}.freeze
|
12
13
|
|
13
14
|
def self._find_ordered_files
|
14
15
|
[
|
15
16
|
'/etc/sugarjar/config.yaml',
|
16
|
-
"#{
|
17
|
+
"#{Dir.home}/.config/sugarjar/config.yaml",
|
17
18
|
].select { |f| File.exist?(f) }
|
18
19
|
end
|
19
20
|
|
data/lib/sugarjar/util.rb
CHANGED
@@ -26,11 +26,25 @@ class SugarJar
|
|
26
26
|
exit(1)
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def git_nofail(*args)
|
30
30
|
if %w{diff log grep branch}.include?(args[0]) &&
|
31
31
|
args.none? { |x| x.include?('color') }
|
32
32
|
args << (@color ? '--color' : '--no-color')
|
33
33
|
end
|
34
|
+
SugarJar::Log.trace("Running: git #{args.join(' ')}")
|
35
|
+
Mixlib::ShellOut.new([which('git')] + args).run_command
|
36
|
+
end
|
37
|
+
|
38
|
+
def git(*args)
|
39
|
+
s = git_nofail(*args)
|
40
|
+
s.error!
|
41
|
+
s
|
42
|
+
end
|
43
|
+
|
44
|
+
def hub_nofail(*args)
|
45
|
+
# this allows us to use 'hub' stuff that's top-level, but is under
|
46
|
+
# repo for this.
|
47
|
+
args.delete_at(0) if args[0] == 'repo'
|
34
48
|
SugarJar::Log.trace("Running: hub #{args.join(' ')}")
|
35
49
|
s = Mixlib::ShellOut.new([which('hub')] + args).run_command
|
36
50
|
if s.error?
|
@@ -84,13 +98,43 @@ class SugarJar
|
|
84
98
|
s
|
85
99
|
end
|
86
100
|
|
101
|
+
def gh_nofail(*args)
|
102
|
+
SugarJar::Log.trace("Running: gh #{args.join(' ')}")
|
103
|
+
s = Mixlib::ShellOut.new([which('gh')] + args).run_command
|
104
|
+
if s.error? && s.stderr.include?('gh auth')
|
105
|
+
SugarJar::Log.info(
|
106
|
+
'gh was run but no github token exists. Will run "gh auth login" ' +
|
107
|
+
"to force\ngh to authenticate...",
|
108
|
+
)
|
109
|
+
unless system(which('gh'), 'auth', 'login', '-p', 'ssh')
|
110
|
+
SugarJar::Log.fatal(
|
111
|
+
'That failed, I will bail out. Hub needs to get a github ' +
|
112
|
+
'token. Try running "gh auth login" (will list info about ' +
|
113
|
+
'your account) and try this again when that works.',
|
114
|
+
)
|
115
|
+
exit(1)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
s
|
119
|
+
end
|
120
|
+
|
121
|
+
def gh(*args)
|
122
|
+
s = gh_nofail(*args)
|
123
|
+
s.error!
|
124
|
+
s
|
125
|
+
end
|
126
|
+
|
87
127
|
def in_repo
|
88
|
-
s =
|
128
|
+
s = git_nofail('rev-parse', '--is-inside-work-tree')
|
89
129
|
!s.error? && s.stdout.strip == 'true'
|
90
130
|
end
|
91
131
|
|
92
132
|
def repo_root
|
93
|
-
|
133
|
+
git('rev-parse', '--show-toplevel').stdout.strip
|
134
|
+
end
|
135
|
+
|
136
|
+
def repo_name
|
137
|
+
repo_root.split('/').last
|
94
138
|
end
|
95
139
|
end
|
96
140
|
end
|
data/lib/sugarjar/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sugarjar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Phil Dibowitz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mixlib-log
|
@@ -95,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
requirements: []
|
98
|
-
rubygems_version: 3.3.
|
98
|
+
rubygems_version: 3.3.7
|
99
99
|
signing_key:
|
100
100
|
specification_version: 4
|
101
101
|
summary: A git/github helper script
|