sugarjar 0.0.3 → 0.0.8
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/Gemfile +10 -0
- data/README.md +30 -16
- data/bin/sj +266 -0
- data/lib/sugarjar/commands.rb +236 -51
- data/lib/sugarjar/config.rb +2 -2
- data/lib/sugarjar/util.rb +47 -1
- data/lib/sugarjar/version.rb +1 -1
- data/sugarjar.gemspec +23 -0
- metadata +13 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 56cbf17ade9b12f891a658d7224a4571890da6517d9ea77a6f3688b4ff593261
|
4
|
+
data.tar.gz: c0c51ce8312f592cc8fd0fe273c563c2c7d3b2e033776ba64d267767755bd720
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d49efb6124a04112ab8bd80b145a2459bdeb56f79c468524e0c89bbc9ef183dfce001fe199b8274562083b338aa2d81073e818676cd6fb9a43250c7be80c736
|
7
|
+
data.tar.gz: 0acc7fb90fed326a8976a1f029e3f5a9720259c855df686e8fb52aa70f8dc009f500f1bb36ef1c5957b7291b5d36cd3e4e59e902582fc23ed66409a58f73869a
|
data/Gemfile
ADDED
data/README.md
CHANGED
@@ -1,18 +1,21 @@
|
|
1
1
|
# SugarJar
|
2
2
|
|
3
|
-
](https://github.com/jaymzh/sugarjar/actions?query=workflow%3ALint)
|
4
|
+
[](https://github.com/jaymzh/sugarjar/actions?query=workflow%3AUnittests)
|
5
|
+
[](https://github.com/jaymzh/sugarjar/actions?query=workflow%3A%22DCO+Check%22)
|
6
|
+
[](https://badge.fury.io/rb/sugarjar)
|
4
7
|
|
5
8
|
Welcome to SugarJar - a git/github helper. It leverages the amazing GitHub cli,
|
6
9
|
[hub](https://hub.github.com/), so you'll need that installed.
|
7
10
|
|
8
11
|
SugarJar is inspired by [arcanist](https://github.com/phacility/arcanist), and
|
9
|
-
|
12
|
+
its replacement at Facebook, JellyFish. Many of the features they provide for
|
10
13
|
the Phabricator workflow this aims to bring to the GitHub workflow.
|
11
14
|
|
12
15
|
In particular there are a lot of helpers for using a squash-merge workflow that
|
13
16
|
is poorly handled by the standard toolsets.
|
14
17
|
|
15
|
-
If you miss Mondrian or
|
18
|
+
If you miss Mondrian or Phabricator - this is the tool for you!
|
16
19
|
|
17
20
|
If you don't, there's a ton of useful stuff for everyone!
|
18
21
|
|
@@ -20,12 +23,12 @@ If you don't, there's a ton of useful stuff for everyone!
|
|
20
23
|
|
21
24
|
It is common for a PR to go back and forth with a variety of nits, lint fixes,
|
22
25
|
typos, etc. that can muddy history. So many projects will "squash and merge"
|
23
|
-
when they accept a pull request.
|
26
|
+
when they accept a pull request. However, that means `git branch -d <branch>`
|
24
27
|
doesn't work. Git will tell you the branch isn't fully merged. You can, of
|
25
28
|
course `git branch -D <branch>`, but that does no safety checks at all, it
|
26
29
|
forces the deletion.
|
27
30
|
|
28
|
-
Enter `sj bclean` - it determines
|
31
|
+
Enter `sj bclean` - it determines if the contents of your branch has been merge
|
29
32
|
and safely deletes if so.
|
30
33
|
|
31
34
|
``` shell
|
@@ -73,7 +76,7 @@ This will:
|
|
73
76
|
Note that it takes `hub`s short-names for repos. No need to specify a full URL,
|
74
77
|
just a $org/$repo.
|
75
78
|
|
76
|
-
Like `git clone`, `sj sclone` will accept an additional
|
79
|
+
Like `git clone`, `sj sclone` will accept an additional argument as the
|
77
80
|
destination directory to clone to. It will also pass any other unknown options
|
78
81
|
to `git clone` under the hood.
|
79
82
|
|
@@ -117,7 +120,7 @@ small lint issue? Not anymore! SJ can be configured to run things before
|
|
117
120
|
pushing. For example,in the SugarJar repo, we have it run Rubocop (ruby lint)
|
118
121
|
and Markdownlint "on_push". If those fail, it lets you know and doesn't push.
|
119
122
|
|
120
|
-
You can configure SugarJar to tell
|
123
|
+
You can configure SugarJar to tell it how to run both lints and unittests for
|
121
124
|
a given repo and if one or both should be run prior to pushing.
|
122
125
|
|
123
126
|
The details on the config file format is below, but we provide three commands:
|
@@ -144,7 +147,7 @@ push if any of them fail.
|
|
144
147
|
## Better push defaults
|
145
148
|
|
146
149
|
In addition to running pre-push tests for you `smartpush` also picks smart
|
147
|
-
defaults for push. So if you `sj spush` with no
|
150
|
+
defaults for push. So if you `sj spush` with no arguments, it uses the
|
148
151
|
`origin` remote and the same branch name you're on as the remote branch.
|
149
152
|
|
150
153
|
## Cleaning up your own history
|
@@ -155,11 +158,11 @@ combination of rebases, amends and force pushes. We provide two commands here
|
|
155
158
|
to help.
|
156
159
|
|
157
160
|
The first is pretty straight forward and is basically just an alias: `sj
|
158
|
-
amend`. It will
|
161
|
+
amend`. It will amend whatever you want to the most recent commit (just an
|
159
162
|
alias for `git commit --amend`). It has a partner `qamend` (or `amendq` if you
|
160
163
|
prefer) that will do so without prompting to update your commit message.
|
161
164
|
|
162
|
-
So now you've rebased or amended, pushing becomes
|
165
|
+
So now you've rebased or amended, pushing becomes challenging. You can `git push
|
163
166
|
--force`, but everyone knows that's incredibly dangerous. Is there a better
|
164
167
|
way? There is! Git provides `git push --force-with-lease` - it checks to make
|
165
168
|
sure you're up-to-date with the remote before forcing the push. But man that
|
@@ -173,7 +176,7 @@ When you want to start a new feature, you want to start developing against
|
|
173
176
|
latest. That's why `sj feature` defaults to creating a branch against what we
|
174
177
|
call "most master". That is, `upstream/master` if it exists, otherwise
|
175
178
|
`origin/master` if that exists, otherwise `master`. You can pass in an
|
176
|
-
additional
|
179
|
+
additional argument to base it off of something else.
|
177
180
|
|
178
181
|
```shell
|
179
182
|
$ git branch
|
@@ -245,17 +248,19 @@ troubleshoot configuration parsing.
|
|
245
248
|
## Repository Configuration
|
246
249
|
|
247
250
|
Sugarjar looks for a `.sugarjar.yaml` in the root of the repository to tell it
|
248
|
-
how to handle repo-specific things. Currently there are
|
249
|
-
configurations accepted:
|
251
|
+
how to handle repo-specific things. Currently there options are:
|
250
252
|
|
251
|
-
* lint - A list of scripts to run on `sj lint`. These should be linters like
|
253
|
+
* `lint` - A list of scripts to run on `sj lint`. These should be linters like
|
252
254
|
rubocop or pyflake.
|
253
|
-
* unit - A list of scripts to run on `sj unit`. These should be unittest
|
255
|
+
* `unit` - A list of scripts to run on `sj unit`. These should be unittest
|
254
256
|
runners like rspec or pyunit.
|
255
|
-
* on_push - A list of types (`lint`, `unit`) of checks to run before pushing.
|
257
|
+
* `on_push` - A list of types (`lint`, `unit`) of checks to run before pushing.
|
256
258
|
It is highly recommended this is only `lint`. The goal here is to allow for
|
257
259
|
the user to get quick stylistic feedback before pushing their branch to avoid
|
258
260
|
the push-fix-push-fix loop.
|
261
|
+
* `commit_template` - A path to a commit template to set in the `commit.template`
|
262
|
+
git config for this repo. Should be either a fully-qualified path, or a path
|
263
|
+
relative to the repo root.
|
259
264
|
|
260
265
|
Example configuration:
|
261
266
|
|
@@ -266,8 +271,17 @@ unit:
|
|
266
271
|
- scripts/unit
|
267
272
|
on_push:
|
268
273
|
- lint
|
274
|
+
commit_template: .commit-template.txt
|
269
275
|
```
|
270
276
|
|
277
|
+
### Commit Templates
|
278
|
+
|
279
|
+
While GitHub provides a way to specify a pull-request template by putting the
|
280
|
+
right file into a repo, there is no way to tell git to automatically pick up a
|
281
|
+
commit template by dropping a file in the repo. Users must do something like:
|
282
|
+
`git config commit.template <file>`. Making each developer do this is error
|
283
|
+
prone, so this setting will automatically set this up for each developer.
|
284
|
+
|
271
285
|
## Enterprise GitHub
|
272
286
|
|
273
287
|
Like `hub`, SugarJar supports GitHub Enterprise. In fact, we provide extra
|
data/bin/sj
ADDED
@@ -0,0 +1,266 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# SugarJar
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
require 'mixlib/shellout'
|
6
|
+
require_relative '../lib/sugarjar/commands'
|
7
|
+
require_relative '../lib/sugarjar/config'
|
8
|
+
require_relative '../lib/sugarjar/log'
|
9
|
+
require_relative '../lib/sugarjar/util'
|
10
|
+
require_relative '../lib/sugarjar/version'
|
11
|
+
|
12
|
+
SugarJar::Log.level = Logger::INFO
|
13
|
+
|
14
|
+
# Don't put defaults here, put them in SugarJar::Config - otherwise
|
15
|
+
# these defaults overwrite whatever is in config files.
|
16
|
+
options = { 'color' => true }
|
17
|
+
# If ENV['SUGARJAR_DEBUG'] is set, it overrides the config file,
|
18
|
+
# but not the command line options, so set that one here. Also
|
19
|
+
# start the logger at that level, in case we are debugging option loading
|
20
|
+
# itself
|
21
|
+
if ENV['SUGARJAR_LOGLEVEL']
|
22
|
+
options['log_level'] = SugarJar::Log.level = ENV['SUGARJAR_LOGLEVEL'].to_sym
|
23
|
+
end
|
24
|
+
parser = OptionParser.new do |opts|
|
25
|
+
opts.banner = 'Usage: sj <command> [<args>] [<options>]'
|
26
|
+
|
27
|
+
opts.separator ''
|
28
|
+
opts.separator 'Command, args, and options, can appear in any order.'
|
29
|
+
opts.separator ''
|
30
|
+
opts.separator 'OPTIONS:'
|
31
|
+
|
32
|
+
opts.on('--[no-]fallthru', 'Fall-thru to git') do |fallthru|
|
33
|
+
options['fallthru'] = fallthru
|
34
|
+
end
|
35
|
+
|
36
|
+
opts.on('--github-user USER', 'Github username') do |user|
|
37
|
+
options['github_user'] = user
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on(
|
41
|
+
'--github-host HOST',
|
42
|
+
'The host for "hub". Note that we will set this in the local repo ' +
|
43
|
+
'config so there is no need to have multiple config files for multiple ' +
|
44
|
+
'github servers. Put your default one in your config file, and simply ' +
|
45
|
+
'specify this option the first time you clone or touch a repo and it ' +
|
46
|
+
'will be part of that repo until changed.',
|
47
|
+
) do |host|
|
48
|
+
options['github_host'] = host
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.on('-h', '--help', 'Print this help message') do
|
52
|
+
puts opts
|
53
|
+
exit
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.on(
|
57
|
+
'--ignore-dirty',
|
58
|
+
'Tell command that check for a dirty repo to carry on anyway.',
|
59
|
+
) do
|
60
|
+
options['ignore_dirty'] = true
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on(
|
64
|
+
'--ignore-prerun-failure',
|
65
|
+
'Ignore preprun failure on *push commands.',
|
66
|
+
) do
|
67
|
+
options['ignore_prerun_failure'] = true
|
68
|
+
end
|
69
|
+
|
70
|
+
opts.on(
|
71
|
+
'--log-level LEVEL',
|
72
|
+
'Set logging level (fatal, error, warning, info, debug, trace). Default: ' +
|
73
|
+
'info',
|
74
|
+
) do |level|
|
75
|
+
options['log_level'] = level
|
76
|
+
end
|
77
|
+
|
78
|
+
opts.on('--[no-]use-color', 'Enable color. [default: true]') do |color|
|
79
|
+
options['color'] = color
|
80
|
+
end
|
81
|
+
|
82
|
+
opts.on('--version') do
|
83
|
+
puts SugarJar::VERSION
|
84
|
+
exit
|
85
|
+
end
|
86
|
+
|
87
|
+
# rubocop:disable Layout/HeredocIndentation
|
88
|
+
opts.separator <<COMMANDS
|
89
|
+
|
90
|
+
COMMANDS:
|
91
|
+
amend
|
92
|
+
Amend the current commit. Alias for "git commit --amend".
|
93
|
+
Accepts other arguments such as "-a" or files.
|
94
|
+
|
95
|
+
amendq, qamend
|
96
|
+
Same as "amend" but without changing the message. Alias for
|
97
|
+
"git commit --amend --no-edit".
|
98
|
+
|
99
|
+
bclean
|
100
|
+
If safe, delete the current branch. Unlike "git branch -d",
|
101
|
+
bclean can handle squash-merged branches. Think of it as
|
102
|
+
a smarter "git branch -d".
|
103
|
+
|
104
|
+
bcleanall
|
105
|
+
Walk all branches, and try to delete them if it's safe. See
|
106
|
+
"bclean" for details.
|
107
|
+
|
108
|
+
binfo
|
109
|
+
Verbose information about the current branch.
|
110
|
+
|
111
|
+
br
|
112
|
+
Verbose branch list. An alias for "git branch -v".
|
113
|
+
|
114
|
+
feature
|
115
|
+
Create a "feature" branch. It's morally equivalent to
|
116
|
+
"git checkout -b" except it defaults to creating it based on
|
117
|
+
some form of 'master' instead of your current branch. In order
|
118
|
+
of preference it will be upstream/master, origin/master, master,
|
119
|
+
depending upon what remotes are available.
|
120
|
+
|
121
|
+
forcepush, fpush
|
122
|
+
The same as "smartpush", but uses "--force-with-lease". This is
|
123
|
+
a "safer" way of doing force-pushes and is the recommended way
|
124
|
+
to push after rebasing or amending. Never do this to shared
|
125
|
+
branches. Very convenient for keeping the branch behind a pull-
|
126
|
+
request clean.
|
127
|
+
|
128
|
+
lint
|
129
|
+
Run any linters configured in .sugarjar.yaml.
|
130
|
+
|
131
|
+
smartclone, sclone
|
132
|
+
A smart wrapper to "git clone" that handles forking and managing
|
133
|
+
remotes for you.
|
134
|
+
It will clone a git repository using hub-style short name
|
135
|
+
("$org/$repo"). If the org of the repository is not the same
|
136
|
+
as your github-user then it will fork the repo for you to
|
137
|
+
your account (if not already done) and then setup your remotes
|
138
|
+
so that "origin" is your fork and "upstream" is the upstream.
|
139
|
+
|
140
|
+
smartlog, sl
|
141
|
+
Inspired by Facebook's "sl" extension to Mercurial, this command
|
142
|
+
will show you a tree of all your local branches relative to your
|
143
|
+
upstream.
|
144
|
+
|
145
|
+
smartpullrequest, smartpr, spr
|
146
|
+
A smart wrapper to "hub pull-request" that checks if your repo
|
147
|
+
is dirty before creating the pull request.
|
148
|
+
|
149
|
+
smartpush, spush
|
150
|
+
A smart wrapper to "git push" that runs whatever is defined in
|
151
|
+
"on_push" in .sugarjar.yml, and only pushes if they succeed.
|
152
|
+
|
153
|
+
unit
|
154
|
+
Run any unitests configured in .sugarjar.yaml.
|
155
|
+
|
156
|
+
up
|
157
|
+
Rebase the current branch on upstream/master or origin/master.
|
158
|
+
|
159
|
+
upall
|
160
|
+
Same as "up", but for all branches.
|
161
|
+
|
162
|
+
version
|
163
|
+
Print the version of sugarjar, and then run 'hub version'
|
164
|
+
to show the hub and git versions.
|
165
|
+
COMMANDS
|
166
|
+
|
167
|
+
# rubocop:enable Layout/HeredocIndentation
|
168
|
+
end
|
169
|
+
|
170
|
+
# we make a copy of these because we will assign back to the ARGV
|
171
|
+
# we parse later. We also need a pristine copy in case we want to
|
172
|
+
# run git as we were called.
|
173
|
+
argv_copy = ARGV.dup
|
174
|
+
|
175
|
+
# We don't have options yet, but we need an instance of SJ in order
|
176
|
+
# to list public methods. We will recreate it
|
177
|
+
sj = SugarJar::Commands.new(options.merge({ 'no_change' => true }))
|
178
|
+
extra_opts = []
|
179
|
+
|
180
|
+
# as with above, this can't go into 'options', until after we parse
|
181
|
+
# the command line args
|
182
|
+
config = SugarJar::Config.config
|
183
|
+
|
184
|
+
valid_commands = sj.public_methods - Object.public_methods
|
185
|
+
|
186
|
+
is_valid_command = ARGV.any? { |arg| valid_commands.include?(arg.to_s.to_sym) }
|
187
|
+
|
188
|
+
# if we're configured to fall thru and the subcommand isn't one
|
189
|
+
# we recognize, don't parse the options as they may be different
|
190
|
+
# than git's. For example `git config -l` - we error because we
|
191
|
+
# require an arguement to `-l`.
|
192
|
+
if config['fallthru'] && !is_valid_command
|
193
|
+
SugarJar::Log.debug(
|
194
|
+
'Skipping option parsing: fall-thru is set and we do not recognize ' +
|
195
|
+
'any subcommands',
|
196
|
+
)
|
197
|
+
else
|
198
|
+
# We want to allow people to pass in extra args to be passed to
|
199
|
+
# git commands, but OptionParser doesn't easily allow this. So we
|
200
|
+
# loop over it, catching exceptions.
|
201
|
+
begin
|
202
|
+
# HOWEVER, anytime it throws an exception, for some reason, it clears
|
203
|
+
# out all of ARGV, or whatever you passed to as ARGV.
|
204
|
+
#
|
205
|
+
# This not only prevents further parsing, but also means we lose
|
206
|
+
# any non-option arguements (like the subcommand!)
|
207
|
+
#
|
208
|
+
# So we save a copy, and if we throw an exception, save the option that
|
209
|
+
# caused it, remove that option from our copy, and then re-populate argv
|
210
|
+
# with what's left.
|
211
|
+
#
|
212
|
+
# By doing this we not only get to parse all the options properly and
|
213
|
+
# save unknown ones, but non-option arguements, which OptionParser
|
214
|
+
# normally leaves in ARGV stay in ARGV.
|
215
|
+
saved_argv = argv_copy.dup
|
216
|
+
parser.parse!(argv_copy)
|
217
|
+
rescue OptionParser::InvalidOption => e
|
218
|
+
SugarJar::Log.debug("Saving unknown argument #{e.args}")
|
219
|
+
extra_opts += e.args
|
220
|
+
|
221
|
+
# e.args is an array, but it's only ever one arguement per exception
|
222
|
+
saved_argv.delete(e.args.first)
|
223
|
+
argv_copy = saved_argv.dup
|
224
|
+
SugarJar::Log.debug(
|
225
|
+
"Continuing option parsing with remaining ARGV: #{argv_copy}",
|
226
|
+
)
|
227
|
+
retry
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
if ARGV.empty?
|
232
|
+
puts parser
|
233
|
+
exit
|
234
|
+
end
|
235
|
+
|
236
|
+
options = config.merge(options)
|
237
|
+
|
238
|
+
# Recreate SJ with all of our options
|
239
|
+
SugarJar::Log.level = options['log_level'].to_sym if options['log_level']
|
240
|
+
sj = SugarJar::Commands.new(options)
|
241
|
+
|
242
|
+
subcommand = argv_copy.reject { |x| x.start_with?('-') }.first
|
243
|
+
argv_copy.delete(subcommand)
|
244
|
+
SugarJar::Log.debug("subcommand is #{subcommand}")
|
245
|
+
|
246
|
+
# Extra options we got, plus any left over arguements are what we
|
247
|
+
# pass to Commands so they can be passed to git as necessary
|
248
|
+
extra_opts += argv_copy
|
249
|
+
SugarJar::Log.debug("extra unknown options: #{extra_opts}")
|
250
|
+
|
251
|
+
if subcommand == 'help'
|
252
|
+
puts parser
|
253
|
+
exit
|
254
|
+
end
|
255
|
+
|
256
|
+
if is_valid_command
|
257
|
+
SugarJar::Log.debug(
|
258
|
+
"running #{subcommand}; extra opts: #{extra_opts.join(', ')}",
|
259
|
+
)
|
260
|
+
sj.send(subcommand.to_sym, *extra_opts)
|
261
|
+
elsif options['fallthru']
|
262
|
+
SugarJar::Log.debug("Falling thru to: hub #{ARGV.join(' ')}")
|
263
|
+
exec('hub', *ARGV)
|
264
|
+
else
|
265
|
+
SugarJar::Log.error("No such subcommand: #{subcommand}")
|
266
|
+
end
|
data/lib/sugarjar/commands.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'mixlib/shellout'
|
2
|
+
|
1
3
|
require_relative 'util'
|
2
4
|
require_relative 'repoconfig'
|
3
5
|
require_relative 'log'
|
@@ -11,10 +13,17 @@ class SugarJar
|
|
11
13
|
include SugarJar::Util
|
12
14
|
|
13
15
|
def initialize(options)
|
16
|
+
SugarJar::Log.debug("Commands.initialize options: #{options}")
|
14
17
|
@ghuser = options['github_user']
|
15
18
|
@ghhost = options['github_host']
|
19
|
+
@ignore_dirty = options['ignore_dirty']
|
20
|
+
@ignore_prerun_failure = options['ignore_prerun_failure']
|
16
21
|
@repo_config = SugarJar::RepoConfig.config
|
22
|
+
@color = options['color']
|
23
|
+
return if options['no_change']
|
24
|
+
|
17
25
|
set_hub_host if @ghhost
|
26
|
+
set_commit_template if @repo_config['commit_template']
|
18
27
|
end
|
19
28
|
|
20
29
|
def feature(name, base = nil)
|
@@ -25,42 +34,62 @@ class SugarJar
|
|
25
34
|
base_pieces = base.split('/')
|
26
35
|
hub('fetch', base_pieces[0]) if base_pieces.length > 1
|
27
36
|
hub('checkout', '-b', name, base)
|
28
|
-
SugarJar::Log.info(
|
37
|
+
SugarJar::Log.info(
|
38
|
+
"Created feature branch #{color(name, :green)} based on " +
|
39
|
+
color(base, :green),
|
40
|
+
)
|
29
41
|
end
|
30
42
|
|
31
43
|
def bclean(name = nil)
|
32
44
|
assert_in_repo
|
33
45
|
name ||= current_branch
|
34
|
-
|
35
|
-
|
36
|
-
|
46
|
+
if clean_branch(name)
|
47
|
+
SugarJar::Log.info("#{name}: #{color('reaped', :green)}")
|
48
|
+
else
|
49
|
+
die(
|
50
|
+
"#{color("Cannot clean #{name}", :red)}! there are unmerged " +
|
51
|
+
"commits; use 'git branch -D #{name}' to forcefully delete it.",
|
52
|
+
)
|
37
53
|
end
|
38
|
-
# rubocop:enable Style/GuardClause
|
39
54
|
end
|
40
55
|
|
41
56
|
def bcleanall
|
42
57
|
assert_in_repo
|
58
|
+
curr = current_branch
|
43
59
|
all_branches.each do |branch|
|
44
|
-
|
60
|
+
if branch == 'master'
|
61
|
+
SugarJar::Log.debug('Skipping master')
|
62
|
+
next
|
63
|
+
end
|
45
64
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
65
|
+
if clean_branch(branch)
|
66
|
+
SugarJar::Log.info("#{branch}: #{color('reaped', :green)}")
|
67
|
+
else
|
68
|
+
SugarJar::Log.info("#{branch}: skipped")
|
69
|
+
SugarJar::Log.debug(
|
70
|
+
"There are unmerged commits; use 'git branch -D #{branch}' to " +
|
71
|
+
'forcefully delete it)',
|
50
72
|
)
|
51
73
|
end
|
52
|
-
|
74
|
+
end
|
75
|
+
|
76
|
+
# Return to the branch we were on, or master
|
77
|
+
if all_branches.include?(curr)
|
78
|
+
hub('checkout', curr)
|
79
|
+
else
|
80
|
+
hub('checkout', 'master')
|
53
81
|
end
|
54
82
|
end
|
55
83
|
|
56
84
|
def co(*args)
|
57
85
|
assert_in_repo
|
58
|
-
hub('checkout', *args)
|
86
|
+
s = hub('checkout', *args)
|
87
|
+
SugarJar::Log.info(s.stderr + s.stdout.chomp)
|
59
88
|
end
|
60
89
|
|
61
90
|
def br
|
62
91
|
assert_in_repo
|
63
|
-
|
92
|
+
SugarJar::Log.info(hub('branch', '-v').stdout.chomp)
|
64
93
|
end
|
65
94
|
|
66
95
|
def binfo
|
@@ -68,16 +97,29 @@ class SugarJar
|
|
68
97
|
SugarJar::Log.info(hub(
|
69
98
|
'log', '--graph', '--oneline', '--decorate', '--boundary',
|
70
99
|
"#{tracked_branch}.."
|
71
|
-
).stdout)
|
100
|
+
).stdout.chomp)
|
72
101
|
end
|
73
102
|
|
103
|
+
# binfo for all branches
|
104
|
+
def smartlog
|
105
|
+
assert_in_repo
|
106
|
+
SugarJar::Log.info(hub(
|
107
|
+
'log', '--graph', '--oneline', '--decorate', '--boundary',
|
108
|
+
'--branches', "#{most_master}.."
|
109
|
+
).stdout.chomp)
|
110
|
+
end
|
111
|
+
|
112
|
+
alias sl smartlog
|
113
|
+
|
74
114
|
def up
|
75
115
|
assert_in_repo
|
76
116
|
result = gitup
|
77
117
|
if result
|
78
|
-
SugarJar::Log.info(
|
118
|
+
SugarJar::Log.info(
|
119
|
+
"#{color(current_branch, :green)} rebased on #{result}",
|
120
|
+
)
|
79
121
|
else
|
80
|
-
die(
|
122
|
+
die("#{color(current_branch, :red)}: Failed to rebase")
|
81
123
|
end
|
82
124
|
end
|
83
125
|
|
@@ -102,11 +144,13 @@ class SugarJar
|
|
102
144
|
hub('checkout', branch)
|
103
145
|
result = gitup
|
104
146
|
if result
|
105
|
-
SugarJar::Log.info(
|
147
|
+
SugarJar::Log.info(
|
148
|
+
"#{color(branch, :green)} rebased on #{color(result, :green)}",
|
149
|
+
)
|
106
150
|
else
|
107
151
|
SugarJar::Log.error(
|
108
|
-
"
|
109
|
-
'branch',
|
152
|
+
"#{color(branch, :red)} failed rebase. Reverting attempt and " +
|
153
|
+
'moving to next branch',
|
110
154
|
)
|
111
155
|
hub('rebase', '--abort')
|
112
156
|
end
|
@@ -127,9 +171,10 @@ class SugarJar
|
|
127
171
|
# Now that we have a repo, if we have a hub host set it.
|
128
172
|
set_hub_host if @ghhost
|
129
173
|
|
130
|
-
org =
|
174
|
+
org = extract_org(repo)
|
175
|
+
SugarJar::Log.debug("Comparing org #{org} to ghuser #{@ghuser}")
|
131
176
|
if org == @ghuser
|
132
|
-
|
177
|
+
puts 'Cloned forked or self-owned repo. Not creating "upstream".'
|
133
178
|
return
|
134
179
|
end
|
135
180
|
|
@@ -137,9 +182,10 @@ class SugarJar
|
|
137
182
|
if s.error?
|
138
183
|
# if the fork command failed, we already have one, so we have
|
139
184
|
# to swap the remote names ourselves
|
185
|
+
# newer 'hub's don't fail and do the right thing...
|
140
186
|
SugarJar::Log.info("Fork (#{@ghuser}/#{reponame}) detected.")
|
141
187
|
hub('remote', 'rename', 'origin', 'upstream')
|
142
|
-
hub('remote', 'add', 'origin', repo
|
188
|
+
hub('remote', 'add', 'origin', forked_path(repo, @ghuser))
|
143
189
|
else
|
144
190
|
SugarJar::Log.info("Forked #{reponame} to #{@ghuser}")
|
145
191
|
end
|
@@ -150,38 +196,25 @@ class SugarJar
|
|
150
196
|
alias sclone smartclone
|
151
197
|
|
152
198
|
def lint
|
199
|
+
assert_in_repo
|
153
200
|
exit(1) unless run_check('lint')
|
154
201
|
end
|
155
202
|
|
156
203
|
def unit
|
157
|
-
|
204
|
+
assert_in_repo
|
205
|
+
exit(1) unless run_check('unit')
|
158
206
|
end
|
159
207
|
|
160
208
|
def smartpush(remote = nil, branch = nil)
|
161
|
-
|
162
|
-
|
163
|
-
branch ||= current_branch
|
164
|
-
end
|
165
|
-
|
166
|
-
if run_prepush
|
167
|
-
puts hub('push', remote, branch).stderr
|
168
|
-
else
|
169
|
-
SugarJar::Log.error('Pre-push checks failed. Not pushing.')
|
170
|
-
end
|
209
|
+
assert_in_repo
|
210
|
+
_smartpush(remote, branch, false)
|
171
211
|
end
|
172
212
|
|
173
213
|
alias spush smartpush
|
174
214
|
|
175
215
|
def forcepush(remote = nil, branch = nil)
|
176
|
-
|
177
|
-
|
178
|
-
branch ||= current_branch
|
179
|
-
end
|
180
|
-
if run_prepush
|
181
|
-
puts hub('push', '--force-with-lease', remote, branch).stderr
|
182
|
-
else
|
183
|
-
SugarJar::Log.error('Pre-push checks failed. Not pushing.')
|
184
|
-
end
|
216
|
+
assert_in_repo
|
217
|
+
_smartpush(remote, branch, true)
|
185
218
|
end
|
186
219
|
|
187
220
|
alias fpush forcepush
|
@@ -191,8 +224,86 @@ class SugarJar
|
|
191
224
|
puts hub('version').stdout
|
192
225
|
end
|
193
226
|
|
227
|
+
def smartpullrequest
|
228
|
+
assert_in_repo
|
229
|
+
if dirty?
|
230
|
+
SugarJar::Log.warn(
|
231
|
+
'Your repo is dirty, so I am not going to create a pull request. ' +
|
232
|
+
'You should commit or amend and push it to your remote first.',
|
233
|
+
)
|
234
|
+
exit(1)
|
235
|
+
end
|
236
|
+
system(which('hub'), 'pull-request')
|
237
|
+
end
|
238
|
+
|
239
|
+
alias spr smartpullrequest
|
240
|
+
alias smartpr smartpullrequest
|
241
|
+
|
194
242
|
private
|
195
243
|
|
244
|
+
def _smartpush(remote, branch, force)
|
245
|
+
unless remote && branch
|
246
|
+
remote ||= 'origin'
|
247
|
+
branch ||= current_branch
|
248
|
+
end
|
249
|
+
|
250
|
+
if dirty?
|
251
|
+
if @ignore_dirty
|
252
|
+
SugarJar::Log.warn(
|
253
|
+
'Your repo is dirty, but --ignore-dirty was specified, so ' +
|
254
|
+
'carrying on anyway.',
|
255
|
+
)
|
256
|
+
else
|
257
|
+
SugarJar::Log.error(
|
258
|
+
'Your repo is dirty, so I am not going to push. Please commit ' +
|
259
|
+
'or amend first.',
|
260
|
+
)
|
261
|
+
exit(1)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
unless run_prepush
|
266
|
+
if @ignore_prerun_failure
|
267
|
+
SugarJar::Log.warn(
|
268
|
+
'Pre-push checks failed, but --ignore-prerun-failure was ' +
|
269
|
+
'specified, so carrying on anyway',
|
270
|
+
)
|
271
|
+
else
|
272
|
+
SugarJar::Log.error('Pre-push checks failed. Not pushing.')
|
273
|
+
exit(1)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
args = ['push', remote, branch]
|
278
|
+
args << '--force-with-lease' if force
|
279
|
+
puts hub(*args).stderr
|
280
|
+
end
|
281
|
+
|
282
|
+
def dirty?
|
283
|
+
s = hub_nofail('diff', '--quiet')
|
284
|
+
s.error?
|
285
|
+
end
|
286
|
+
|
287
|
+
def extract_org(path)
|
288
|
+
if path.start_with?('http')
|
289
|
+
File.basename(File.dirname(path))
|
290
|
+
elsif path.start_with?('git@')
|
291
|
+
path.split(':')[1].split('/')[0]
|
292
|
+
else
|
293
|
+
# assume they passed in a hub-friendly name
|
294
|
+
path.split('/').first
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def forked_path(path, username)
|
299
|
+
repo = if path.start_with?('http', 'git@')
|
300
|
+
File.basename(path)
|
301
|
+
else
|
302
|
+
"#{File.basename(path)}.git"
|
303
|
+
end
|
304
|
+
"git@github.com:#{username}/#{repo}"
|
305
|
+
end
|
306
|
+
|
196
307
|
def set_hub_host
|
197
308
|
return unless in_repo
|
198
309
|
|
@@ -201,7 +312,7 @@ class SugarJar
|
|
201
312
|
SugarJar::Log.info("Setting repo hub.host = #{@ghhost}")
|
202
313
|
else
|
203
314
|
current = s.stdout
|
204
|
-
if current == @
|
315
|
+
if current == @ghhost
|
205
316
|
SugarJar::Log.debug('Repo hub.host already set correctly')
|
206
317
|
else
|
207
318
|
# Even though we have an explicit config, in most cases, it
|
@@ -217,6 +328,47 @@ class SugarJar
|
|
217
328
|
hub('config', '--local', '--add', 'hub.host', @ghhost)
|
218
329
|
end
|
219
330
|
|
331
|
+
def set_commit_template
|
332
|
+
unless in_repo
|
333
|
+
SugarJar::Log.debug('Skipping set_commit_template: not in repo')
|
334
|
+
return
|
335
|
+
end
|
336
|
+
|
337
|
+
realpath = if @repo_config['commit_template'].start_with?('/')
|
338
|
+
@repo_config['commit_template']
|
339
|
+
else
|
340
|
+
"#{repo_root}/#{@repo_config['commit_template']}"
|
341
|
+
end
|
342
|
+
unless File.exist?(realpath)
|
343
|
+
die(
|
344
|
+
"Repo config specifies #{@repo_config['commit_template']} as the " +
|
345
|
+
'commit template, but that file does not exist.',
|
346
|
+
)
|
347
|
+
end
|
348
|
+
|
349
|
+
s = hub_nofail('config', '--local', 'commit.template')
|
350
|
+
unless s.error?
|
351
|
+
current = s.stdout.strip
|
352
|
+
if current == @repo_config['commit_template']
|
353
|
+
SugarJar::Log.debug('Commit template already set correctly')
|
354
|
+
return
|
355
|
+
else
|
356
|
+
SugarJar::Log.warn(
|
357
|
+
"Updating repo-specific commit template from #{current} " +
|
358
|
+
"to #{@repo_config['commit_template']}",
|
359
|
+
)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
SugarJar::Log.debug(
|
364
|
+
'Setting repo-specific commit template to ' +
|
365
|
+
"#{@repo_config['commit_template']} per sugarjar repo config.",
|
366
|
+
)
|
367
|
+
hub(
|
368
|
+
'config', '--local', 'commit.template', @repo_config['commit_template']
|
369
|
+
)
|
370
|
+
end
|
371
|
+
|
220
372
|
def run_check(type)
|
221
373
|
unless @repo_config[type]
|
222
374
|
SugarJar::Log.debug("No #{type} configured. Returning success")
|
@@ -224,17 +376,26 @@ class SugarJar
|
|
224
376
|
end
|
225
377
|
Dir.chdir repo_root do
|
226
378
|
@repo_config[type].each do |check|
|
227
|
-
SugarJar::Log.
|
379
|
+
SugarJar::Log.debug("Running #{type} #{check}")
|
228
380
|
|
229
|
-
unless File.exist?(check)
|
381
|
+
unless File.exist?(check.split.first)
|
230
382
|
SugarJar::Log.error("Configured #{type} #{check} does not exist!")
|
231
383
|
return false
|
232
384
|
end
|
233
385
|
s = Mixlib::ShellOut.new(check).run_command
|
234
|
-
|
235
|
-
SugarJar::Log.info(
|
236
|
-
|
386
|
+
unless s.error?
|
387
|
+
SugarJar::Log.info(
|
388
|
+
"[#{type}] #{check}: #{color('OK', :green)}",
|
389
|
+
)
|
390
|
+
next
|
237
391
|
end
|
392
|
+
|
393
|
+
SugarJar::Log.info(
|
394
|
+
"[#{type}] #{check} #{color('failed', :red)}, output follows " +
|
395
|
+
"(see debug for more)\n#{s.stdout}",
|
396
|
+
)
|
397
|
+
SugarJar::Log.debug(s.format_for_exception)
|
398
|
+
return false
|
238
399
|
end
|
239
400
|
end
|
240
401
|
end
|
@@ -243,7 +404,7 @@ class SugarJar
|
|
243
404
|
@repo_config['on_push']&.each do |item|
|
244
405
|
SugarJar::Log.debug("Running on_push check type #{item}")
|
245
406
|
unless send(:run_check, item)
|
246
|
-
SugarJar::Log.info("
|
407
|
+
SugarJar::Log.info("[prepush]: #{item} #{color('failed', :red)}.")
|
247
408
|
return false
|
248
409
|
end
|
249
410
|
end
|
@@ -269,7 +430,6 @@ class SugarJar
|
|
269
430
|
hub('checkout', 'master')
|
270
431
|
hub('branch', '-D', name)
|
271
432
|
gitup
|
272
|
-
SugarJar::Log.info("Reaped branch #{name}")
|
273
433
|
true
|
274
434
|
end
|
275
435
|
|
@@ -310,7 +470,7 @@ class SugarJar
|
|
310
470
|
s = hub_nofail('merge', '--squash', branch)
|
311
471
|
if s.error?
|
312
472
|
cleanup_tmp_branch(tmpbranch, branch)
|
313
|
-
SugarJar::Log.
|
473
|
+
SugarJar::Log.debug(
|
314
474
|
'Failed to merge changes into current master. This means we could ' +
|
315
475
|
'not figure out if this is merged or not. Check manually and use ' +
|
316
476
|
"'git branch -D #{branch}' if it is safe to do so.",
|
@@ -353,8 +513,18 @@ class SugarJar
|
|
353
513
|
def gitup
|
354
514
|
SugarJar::Log.debug('Fetching upstream')
|
355
515
|
fetch_upstream
|
516
|
+
curr = current_branch
|
356
517
|
SugarJar::Log.debug('Rebasing')
|
357
518
|
base = tracked_branch
|
519
|
+
if curr != 'master' && base == "origin/#{curr}"
|
520
|
+
SugarJar::Log.warn(
|
521
|
+
"This branch is tracking origin/#{curr}, which is probably your " +
|
522
|
+
'downstream (where you push _to_) as opposed to your upstream ' +
|
523
|
+
'(where you pull _from_). This means that "sj up" is probably ' +
|
524
|
+
'rebasing on the wrong thing and doing nothing. You probably want ' +
|
525
|
+
'to do a "git branch -u upstream".',
|
526
|
+
)
|
527
|
+
end
|
358
528
|
s = hub_nofail('rebase', base)
|
359
529
|
s.error? ? nil : base
|
360
530
|
end
|
@@ -399,5 +569,20 @@ class SugarJar
|
|
399
569
|
end
|
400
570
|
@remote
|
401
571
|
end
|
572
|
+
|
573
|
+
def color(string, *colors)
|
574
|
+
if @color
|
575
|
+
pastel.decorate(string, *colors)
|
576
|
+
else
|
577
|
+
string
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
def pastel
|
582
|
+
@pastel ||= begin
|
583
|
+
require 'pastel'
|
584
|
+
Pastel.new
|
585
|
+
end
|
586
|
+
end
|
402
587
|
end
|
403
588
|
end
|
data/lib/sugarjar/config.rb
CHANGED
@@ -6,14 +6,14 @@ class SugarJar
|
|
6
6
|
# This is stuff like log level, github-user, etc.
|
7
7
|
class Config
|
8
8
|
DEFAULTS = {
|
9
|
-
'
|
9
|
+
'github_user' => ENV['USER'],
|
10
10
|
'fallthru' => true,
|
11
11
|
}.freeze
|
12
12
|
|
13
13
|
def self._find_ordered_files
|
14
14
|
[
|
15
15
|
'/etc/sugarjar/config.yaml',
|
16
|
-
"#{ENV['HOME']}/.config/sugarjar/config.yaml"
|
16
|
+
"#{ENV['HOME']}/.config/sugarjar/config.yaml",
|
17
17
|
].select { |f| File.exist?(f) }
|
18
18
|
end
|
19
19
|
|
data/lib/sugarjar/util.rb
CHANGED
@@ -27,8 +27,54 @@ class SugarJar
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def hub_nofail(*args)
|
30
|
+
if %w{diff log grep branch}.include?(args[0]) &&
|
31
|
+
args.none? { |x| x.include?('color') }
|
32
|
+
args << (@color ? '--color' : '--no-color')
|
33
|
+
end
|
30
34
|
SugarJar::Log.trace("Running: hub #{args.join(' ')}")
|
31
|
-
Mixlib::ShellOut.new([which('hub')] + args).run_command
|
35
|
+
s = Mixlib::ShellOut.new([which('hub')] + args).run_command
|
36
|
+
if s.error?
|
37
|
+
# depending on hub version and possibly other things, STDERR
|
38
|
+
# is either "Requires authentication" or "Must authenticate"
|
39
|
+
case s.stderr
|
40
|
+
when /^(Must|Requires) authenticat/
|
41
|
+
SugarJar::Log.info(
|
42
|
+
'Hub was run but no github token exists. Will run "hub api user" ' +
|
43
|
+
"to force\nhub to authenticate...",
|
44
|
+
)
|
45
|
+
unless system(which('hub'), 'api', 'user')
|
46
|
+
SugarJar::Log.fatal(
|
47
|
+
'That failed, I will bail out. Hub needs to get a github ' +
|
48
|
+
'token. Try running "hub api user" (will list info about ' +
|
49
|
+
'your account) and try this again when that works.',
|
50
|
+
)
|
51
|
+
exit(1)
|
52
|
+
end
|
53
|
+
SugarJar::Log.info('Re-running original hub command...')
|
54
|
+
s = Mixlib::ShellOut.new([which('hub')] + args).run_command
|
55
|
+
when /^fatal: could not read Username/
|
56
|
+
# On http(s) URLs, git may prompt for username/passwd
|
57
|
+
SugarJar::Log.info(
|
58
|
+
'Hub was run but git prompted for authentication. This probably ' +
|
59
|
+
"means you have\nused an http repo URL instead of an ssh one. It " +
|
60
|
+
"is recommended you reclone\nusing 'sj sclone' to setup your " +
|
61
|
+
"remotes properly. However, in the meantime,\nwe'll go ahead " +
|
62
|
+
"and re-run the command in a shell so you can type in the\n" +
|
63
|
+
'credentials.',
|
64
|
+
)
|
65
|
+
unless system(which('hub'), *args)
|
66
|
+
SugarJar::Log.fatal(
|
67
|
+
'That failed, I will bail out. You can either manually change ' +
|
68
|
+
'your remotes, or simply create a fresh clone with ' +
|
69
|
+
'"sj smartclone".',
|
70
|
+
)
|
71
|
+
exit(1)
|
72
|
+
end
|
73
|
+
SugarJar::Log.info('Re-running original hub command...')
|
74
|
+
s = Mixlib::ShellOut.new([which('hub')] + args).run_command
|
75
|
+
end
|
76
|
+
end
|
77
|
+
s
|
32
78
|
end
|
33
79
|
|
34
80
|
def hub(*args)
|
data/lib/sugarjar/version.rb
CHANGED
data/sugarjar.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'lib/sugarjar/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'sugarjar'
|
5
|
+
spec.version = SugarJar::VERSION
|
6
|
+
spec.summary = 'A git/github helper script'
|
7
|
+
spec.authors = ['Phil Dibowitz']
|
8
|
+
spec.email = ['phil@ipom.com']
|
9
|
+
spec.license = 'Apache-2.0'
|
10
|
+
spec.homepage = 'https://github.com/jaymzh/sugarjar'
|
11
|
+
spec.required_ruby_version = '>= 2.6.0'
|
12
|
+
docs = %w{README.md LICENSE Gemfile sugarjar.gemspec}
|
13
|
+
spec.extra_rdoc_files = docs
|
14
|
+
spec.executables << 'sj'
|
15
|
+
spec.files =
|
16
|
+
Dir.glob('lib/sugarjar/*.rb') +
|
17
|
+
Dir.glob('bin/*') +
|
18
|
+
docs
|
19
|
+
|
20
|
+
spec.add_dependency 'mixlib-log'
|
21
|
+
spec.add_dependency 'mixlib-shellout'
|
22
|
+
spec.add_dependency 'pastel'
|
23
|
+
end
|
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: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Phil Dibowitz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mixlib-log
|
@@ -39,41 +39,13 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: pastel
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
|
-
type: :
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: mdl
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rubocop
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
48
|
+
type: :runtime
|
77
49
|
prerelease: false
|
78
50
|
version_requirements: !ruby/object:Gem::Requirement
|
79
51
|
requirements:
|
@@ -83,20 +55,26 @@ dependencies:
|
|
83
55
|
description:
|
84
56
|
email:
|
85
57
|
- phil@ipom.com
|
86
|
-
executables:
|
58
|
+
executables:
|
59
|
+
- sj
|
87
60
|
extensions: []
|
88
61
|
extra_rdoc_files:
|
89
62
|
- README.md
|
90
63
|
- LICENSE
|
64
|
+
- Gemfile
|
65
|
+
- sugarjar.gemspec
|
91
66
|
files:
|
67
|
+
- Gemfile
|
92
68
|
- LICENSE
|
93
69
|
- README.md
|
70
|
+
- bin/sj
|
94
71
|
- lib/sugarjar/commands.rb
|
95
72
|
- lib/sugarjar/config.rb
|
96
73
|
- lib/sugarjar/log.rb
|
97
74
|
- lib/sugarjar/repoconfig.rb
|
98
75
|
- lib/sugarjar/util.rb
|
99
76
|
- lib/sugarjar/version.rb
|
77
|
+
- sugarjar.gemspec
|
100
78
|
homepage: https://github.com/jaymzh/sugarjar
|
101
79
|
licenses:
|
102
80
|
- Apache-2.0
|
@@ -109,15 +87,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
109
87
|
requirements:
|
110
88
|
- - ">="
|
111
89
|
- !ruby/object:Gem::Version
|
112
|
-
version:
|
90
|
+
version: 2.6.0
|
113
91
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
92
|
requirements:
|
115
93
|
- - ">="
|
116
94
|
- !ruby/object:Gem::Version
|
117
95
|
version: '0'
|
118
96
|
requirements: []
|
119
|
-
|
120
|
-
rubygems_version: 2.7.6.2
|
97
|
+
rubygems_version: 3.1.2
|
121
98
|
signing_key:
|
122
99
|
specification_version: 4
|
123
100
|
summary: A git/github helper script
|