sugarjar 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d2c4dd59aaf4843033f5c38df43b3fdfa556298708bc7f437f2923e00f9133c8
4
- data.tar.gz: 5edeeb730db94059fd10b115b192ed239782b797473eb3b1fcf5aa749ca23e95
3
+ metadata.gz: c9a62438fa0d483eb64cd28cb5de3e603d6907a353194fac8df0bc8cd51a55f1
4
+ data.tar.gz: ff816417124253671a07ffe4ee2c6cb066a3b8f3f6dc0bac439a667297b595bf
5
5
  SHA512:
6
- metadata.gz: 3869512549691df320f1dc344424b65944cd8cb501e25cd1a982f9b8d4d92cf608531147a8c5eb7a7437eee7644683ef9cf57e6035c44b61e4d247eec3331e03
7
- data.tar.gz: 159e663e59a6c2aa939a5e9aecb90ce811bb9a168476d842ced28eab7a9968b760daec22661455a7bdaf3ac75ecc11a1c706e2ea07a6368ab653bcc3a222a597
6
+ metadata.gz: a97436c810c10af47d507eeb8c29070da38927884aef6f6ffaa39a9476777ba88e4c176fdb69ab67a979c832c3d32339f1c848c97ef1f6ecd5dcf17025f2b9e0
7
+ data.tar.gz: 478d20bcc6c8ed561f2ab6294d38a0e3267a96f0e239a565e498b483505dff950ad1712931a777012141e955438bb5f082db75698eb478a36981666bba38af19
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # SugjarJar
1
+ # SugarJar
2
2
 
3
3
  ![CI](https://github.com/jaymzh/sugarjar/workflows/CI/badge.svg)
4
4
 
@@ -12,84 +12,219 @@ the Phabricator workflow this aims to bring to the GitHub workflow.
12
12
  In particular there are a lot of helpers for using a squash-merge workflow that
13
13
  is poorly handled by the standard toolsets.
14
14
 
15
- ## Commands
15
+ If you miss Mondrian or Phabrictor - this is the tool for you!
16
16
 
17
- ### amend
17
+ If you don't, there's a ton of useful stuff for everyone!
18
18
 
19
- Amend the current commit. Alias for `git commit --amend`. Accepts other
20
- arguments such as `-a` or files.
19
+ ## Auto cleanup squash-merged branches
21
20
 
22
- ### amendq, qamend
21
+ It is common for a PR to go back and forth with a variety of nits, lint fixes,
22
+ typos, etc. that can muddy history. So many projects will "squash and merge"
23
+ when they accept a pull request. Howevet, that means `git branch -d <branch>`
24
+ doesn't work. Git will tell you the branch isn't fully merged. You can, of
25
+ course `git branch -D <branch>`, but that does no safety checks at all, it
26
+ forces the deletion.
23
27
 
24
- Same as `amend` but without changing the message. Alias for `git commit --amend
25
- --no-edit`.
28
+ Enter `sj bclean` - it determines of the contents of your branch has been merge
29
+ and safely deletes if so.
26
30
 
27
- ### bclean
31
+ ``` shell
32
+ sj bclean
33
+ ```
34
+
35
+ Will delete a branch, if it has been merged, **even if it was squash-merged**.
28
36
 
29
- If safe, delete the current branch. Unlike `git branch -d`, bclean can handle
30
- squash-merged branches. Think of it as a smarter `git branch -d`.
37
+ You can pass it a branch if you'd like (it defaults to the branch you're on):
38
+ `sj bclean <branch>`.
31
39
 
32
- ### bcleanall
40
+ But it gets better! You can use `sj bcleanall` to remove all branches that have
41
+ been merged:
42
+
43
+ ```shell
44
+ $ git branch
45
+ * argparse
46
+ master
47
+ feature
48
+ hubhost
49
+ $ git bcleanall
50
+ Skipping branch argparse - there are unmerged commits
51
+ Reaped branch feature
52
+ Reaped branch hubhost
53
+ ```
33
54
 
34
- Walk all branches, and try to delete them if it's safe. See `bclean` for
35
- details.
55
+ ## Smarter clones and remotes
56
+
57
+ There's a pattern to every new repo we want to contribute to. First we fork,
58
+ then we clone the fork, then we add a remote of the upstream repo. It's
59
+ monotonous. SugarJar does this for you:
60
+
61
+ ```shell
62
+ sj smartclone jaymzh/sugarjar
63
+ ```
36
64
 
37
- ### binfo
65
+ (also `sj sclone`)
38
66
 
39
- Verbose information about the current branch.
67
+ This will:
40
68
 
41
- ### br
69
+ * Make a fork of the repo, if you don't already have one
70
+ * Clone your fork
71
+ * Add the original as an 'upstream' remote
42
72
 
43
- Verbose branch list. An alias for `git branch -v`.
73
+ Note that it takes `hub`s short-names for repos. No need to specify a full URL,
74
+ just a $org/$repo.
44
75
 
45
- ### feature
76
+ Like `git clone`, `sj sclone` will accept an additional arguement as the
77
+ destination directory to clone to. It will also pass any other unknown options
78
+ to `git clone` under the hood.
46
79
 
47
- Create a "feature branch." It's morally equivalent to `git checkout -b` except
48
- it defaults to creating it based on some form of 'master' instead of your
49
- current branch. In order of preference it will be `upstream/master`,
50
- `origin/master`, or `master`, depending upon what remotes are available.
80
+ ## Work with stacked branches more easily
51
81
 
52
- ### forcepush, fpush
82
+ It's important to break changes into reviewable chunks, but working with
83
+ stacked branches can be confusing. Enter `binfo` - it gives you a view of your
84
+ current branch all the way up to master. In this example imagine we have a
85
+ branch structure like:
53
86
 
54
- The same as `smartpush`, but uses `--force-with-lease`. This is a "safer" way
55
- of doing force-pushes and is the recommended way to push after rebasing or
56
- amending. Never do this to shared branches. Very convenient for keeping the
57
- branch behind a pull-request clean.
87
+ ```text
88
+ +- test2.1
89
+ /
90
+ master --- test --- test2 --- test3
91
+ ```
58
92
 
59
- ### lint
93
+ This is what `binfo` on test3 looks like:
60
94
 
61
- Run any linters configured in `.sugarjar.yaml`.
95
+ ```shell
96
+ $ sj binfo
97
+ * e451865 (HEAD -> test3) test3
98
+ * e545b41 (test2) test2
99
+ * c808eae (test1) test1
100
+ o 44cf9e2 (origin/master, origin/HEAD, master) Lint/gemspec cleanups
101
+ ```
62
102
 
63
- ### smartclone, sclone
103
+ while `binfo` on test2.1 looks like:
64
104
 
65
- A smart wrapper to `git clone` that handles forking and managing remotes for
66
- you. It will clone a git repository using hub-style short name (`$org/$repo`).
67
- If the org of the repository is not the same as your github-user then it will
68
- fork the repo for you to your account (if not already done) and then setup your
69
- remotes so that `origin` is your fork and `upstream` is the upstream.
105
+ ```shell
106
+ $ sj binfo
107
+ * 36d0136 (HEAD -> test2.1) test2.1
108
+ * e545b41 (test2) test2
109
+ * c808eae (test1) test1
110
+ o 44cf9e2 (origin/master, origin/HEAD, master) Lint/gemspec cleanups
111
+ ```
70
112
 
71
- ### smartpush, spush
113
+ ## Have a better lint/unittest experience!
72
114
 
73
- A smart wrapper to `git push` that runs whatever is defined in `on_push` in
74
- `.sugarjar.yml`, and only pushes if they succeed.
115
+ Ever made a PR, only to find out later that it failed tests because of some
116
+ small lint issue? Not anymore! SJ can be configured to run things before
117
+ pushing. For example,in the SugarJar repo, we have it run Rubocop (ruby lint)
118
+ and Markdownlint "on_push". If those fail, it lets you know and doesn't push.
75
119
 
76
- It will also allow you to not specify a remote or branch, and will default to
77
- `origin` and whatever your current local branch name is.
120
+ You can configure SugarJar to tell how how to run both lints and unittests for
121
+ a given repo and if one or both should be run prior to pushing.
78
122
 
79
- ### unit
123
+ The details on the config file format is below, but we provide three commands:
80
124
 
81
- Run any unitests configured in `.sugarjar.yaml`.
125
+ ```shell
126
+ git lint
127
+ ```
82
128
 
83
- ### up
129
+ Run all linters.
84
130
 
85
- Rebase the current branch on the branch it's tracking, or if it's tracking one
86
- then, otherise `upstream/master` if it exists, or `origin/master`.
131
+ ```shell
132
+ git unit
133
+ ```
87
134
 
88
- ### upall
135
+ Run all unittests.
89
136
 
90
- Same as `up`, but for all branches.
137
+ ```shell
138
+ git smartpush # or spush
139
+ ```
91
140
 
92
- ## User Configuration
141
+ Run configured push-time actions (nothing, lint, unit, both), and do not
142
+ push if any of them fail.
143
+
144
+ ## Better push defaults
145
+
146
+ In addition to running pre-push tests for you `smartpush` also picks smart
147
+ defaults for push. So if you `sj spush` with no arguements, it uses the
148
+ `origin` remote and the same branch name you're on as the remote branch.
149
+
150
+ ## Cleaning up your own history
151
+
152
+ Perhaps you contribute to a project that prefers to use merge commits, so you
153
+ like to clean up your own history. This is often difficult to get right - a
154
+ combination of rebases, amends and force pushes. We provide two commands here
155
+ to help.
156
+
157
+ The first is pretty straight forward and is basically just an alias: `sj
158
+ amend`. It will ammend whatever you want to the most recent commit (just an
159
+ alias for `git commit --amend`). It has a partner `qamend` (or `amendq` if you
160
+ prefer) that will do so without prompting to update your commit message.
161
+
162
+ So now you've rebased or amended, pushing becomes challening. You can `git push
163
+ --force`, but everyone knows that's incredibly dangerous. Is there a better
164
+ way? There is! Git provides `git push --force-with-lease` - it checks to make
165
+ sure you're up-to-date with the remote before forcing the push. But man that
166
+ command is a mouthful! Enter `sj fpush`. It has all the smarts of `sj
167
+ smartpush` (runs configured pre-push actions), but adds `--force-with-lease` to
168
+ the command!
169
+
170
+ ## Better feature branches
171
+
172
+ When you want to start a new feature, you want to start developing against
173
+ latest. That's why `sj feature` defaults to creating a branch against what we
174
+ call "most master". That is, `upstream/master` if it exists, otherwise
175
+ `origin/master` if that exists, otherwise `master`. You can pass in an
176
+ additional arguement to base it off of something else.
177
+
178
+ ```shell
179
+ $ git branch
180
+ master
181
+ test1
182
+ test2
183
+ * test2.1
184
+ test3
185
+ $ sj feature test-branch
186
+ Created feature branch test-branch based on origin/master
187
+ $ sj feature dependent-feature test-branch
188
+ Created feature branch dependent-feature based on test-branch
189
+ ```
190
+
191
+ ## And more!
192
+
193
+ See `sj help` for more commands!
194
+
195
+ ## Using SugarJar as a git wrapper
196
+
197
+ SugarJar, by default, will pass any command it doesn't know straight to `hub`
198
+ (which passes commands **it** doesn't know to `git`). As such you can alias it
199
+ to `git` and just have a super-git.
200
+
201
+ ```shell
202
+ $ alias git=sj
203
+ $ git config -l | grep color
204
+ color.diff=auto
205
+ color.status=auto
206
+ color.branch=auto
207
+ color.branch.current=yellow reverse
208
+ color.branch.local=yellow
209
+ color.branch.remote=green
210
+ $ git br
211
+ * dependent-feature 44cf9e2 Lint/gemspec cleanups
212
+ master 44cf9e2 Lint/gemspec cleanups
213
+ test-branch 44cf9e2 Lint/gemspec cleanups
214
+ test1 c808eae [ahead 1] test1
215
+ test2 e545b41 test2
216
+ test2.1 c1831b3 test2.1
217
+ test3 e451865 test3
218
+ ```
219
+
220
+ It's for this reason that SugarJar doesn't have conflicting command names. You
221
+ can turn off fallthru by setting `fallthru: false` in your config.
222
+
223
+ The only command we "override" is `version`, in which case we not only print
224
+ our version, but also call `hub version` which prints its version and calls
225
+ `git version` too!
226
+
227
+ ## Configuration
93
228
 
94
229
  Sugarjar will read in both a system-level config file
95
230
  (`/etc/sugarjar/config.yaml`) and a user-level config file
@@ -133,17 +268,41 @@ on_push:
133
268
  - lint
134
269
  ```
135
270
 
271
+ ## Enterprise GitHub
272
+
273
+ Like `hub`, SugarJar supports GitHub Enterprise. In fact, we provide extra
274
+ features just for it.
275
+
276
+ We recommend the global or user config specify the `github_host`. However, most
277
+ users will also have a few repos from upstream so always specifying a
278
+ `github_host` is sub-optimal.
279
+
280
+ So, when you overwrite the `github_host` on the command line, we go ahead and
281
+ set the `hub.host` git config in that single repo so that it'll "just work"
282
+ from there on out.
283
+
284
+ In other words, assuming your global SJ config has `github_host:
285
+ github.sample.com`, and the you clone sugarjar with:
286
+
287
+ ```shell
288
+ sj clone jaymzh/sugarjar --github-host githuh.com
289
+ ```
290
+
291
+ We will add the `hub.host` to the `sugarjar` clone so that future `hub` or `sj`
292
+ commands work without needing to specify..
293
+
136
294
  ## FAQ
137
295
 
138
296
  Why the name SugarJar?
139
297
 
140
- It's mostly a backranym. Like jellyfish, I wanted two letters that were on
141
- home row on different sides of the keyboard to make it easy to type. I looked
142
- at the possible options that where there and not taken and tried to find one
143
- I could make an appropriate name out of. Since this utility adds lots of sugar
144
- to git and github, it seemed appropriate.
298
+ It's mostly a backranym. Like jellyfish, I wanted two letters that were on home
299
+ row on different sides of the keyboard to make it easy to type. I looked at the
300
+ possible options that where there and not taken and tried to find one I could
301
+ make an appropriate name out of. Since this utility adds lots of sugar to git
302
+ and github, it seemed appropriate.
145
303
 
146
304
  Why did you use `hub` instead of the newer `gh` CLI?
147
305
 
148
- `gh` is less feature-rich (currently). I'm also considering making this optionally
149
- act as a wrapper to `hub` the way `hub` can be a wrapper to `git`.
306
+ `gh` is still new and not yet as feature rich as `hub`. Also I wanted SugarJar
307
+ to be able to be a git wrapper, and so wrapping `hub` allows us to do that but
308
+ wrapping `gh` does not.
@@ -22,6 +22,8 @@ class SugarJar
22
22
  SugarJar::Log.debug("Feature: #{name}, #{base}")
23
23
  die("#{name} already exists!") if all_branches.include?(name)
24
24
  base ||= most_master
25
+ base_pieces = base.split('/')
26
+ hub('fetch', base_pieces[0]) if base_pieces.length > 1
25
27
  hub('checkout', '-b', name, base)
26
28
  SugarJar::Log.info("Created feature branch #{name} based on #{base}")
27
29
  end
@@ -44,16 +46,16 @@ class SugarJar
44
46
  # rubocop:disable Style/Next
45
47
  unless clean_branch(branch)
46
48
  SugarJar::Log.info(
47
- "Skipping branch #{branch} - there are unmerged commits"
49
+ "Skipping branch #{branch} - there are unmerged commits",
48
50
  )
49
51
  end
50
52
  # rubocop:enable Style/Next
51
53
  end
52
54
  end
53
55
 
54
- def co(name)
56
+ def co(*args)
55
57
  assert_in_repo
56
- hub('checkout', name)
58
+ hub('checkout', *args)
57
59
  end
58
60
 
59
61
  def br
@@ -82,7 +84,7 @@ class SugarJar
82
84
  def amend(*args)
83
85
  assert_in_repo
84
86
  # This cannot use shellout since we need a full terminal for the editor
85
- exit(system('/usr/bin/git', 'commit', '--amend', *args))
87
+ exit(system(which('git'), 'commit', '--amend', *args))
86
88
  end
87
89
 
88
90
  def qamend(*args)
@@ -104,7 +106,7 @@ class SugarJar
104
106
  else
105
107
  SugarJar::Log.error(
106
108
  "Failed to rebase #{branch}, aborting that and moving to next " +
107
- 'branch'
109
+ 'branch',
108
110
  )
109
111
  hub('rebase', '--abort')
110
112
  end
@@ -202,10 +204,15 @@ class SugarJar
202
204
  if current == @ghost
203
205
  SugarJar::Log.debug('Repo hub.host already set correctly')
204
206
  else
205
- SugarJar::Log.info(
206
- "Overwriting repo hub.host from #{current} to #{@ghhost}"
207
+ # Even though we have an explicit config, in most cases, it
208
+ # comes from a global or user config, but the config in the
209
+ # local repo we likely set. So we'd just constantly revert that.
210
+ SugarJar::Log.debug(
211
+ "Not overwriting repo hub.host. Already set to #{current}. " +
212
+ "To change it, run `git config --local --add hub.host #{@ghhost}`",
207
213
  )
208
214
  end
215
+ return
209
216
  end
210
217
  hub('config', '--local', '--add', 'hub.host', @ghhost)
211
218
  end
@@ -287,7 +294,7 @@ class SugarJar
287
294
  end
288
295
  if out.length.zero?
289
296
  SugarJar::Log.debug(
290
- "cherry-pick shows branch #{branch} obviously safe to delete"
297
+ "cherry-pick shows branch #{branch} obviously safe to delete",
291
298
  )
292
299
  return true
293
300
  end
@@ -303,10 +310,10 @@ class SugarJar
303
310
  s = hub_nofail('merge', '--squash', branch)
304
311
  if s.error?
305
312
  cleanup_tmp_branch(tmpbranch, branch)
306
- error(
313
+ SugarJar::Log.error(
307
314
  'Failed to merge changes into current master. This means we could ' +
308
315
  'not figure out if this is merged or not. Check manually and use ' +
309
- "'git branch -D #{branch}' if it is safe to do so."
316
+ "'git branch -D #{branch}' if it is safe to do so.",
310
317
  )
311
318
  return false
312
319
  end
@@ -317,12 +324,12 @@ class SugarJar
317
324
  cleanup_tmp_branch(tmpbranch, branch)
318
325
  if out.empty?
319
326
  SugarJar::Log.debug(
320
- 'After squash-merging, this branch appears safe to delete'
327
+ 'After squash-merging, this branch appears safe to delete',
321
328
  )
322
329
  true
323
330
  else
324
331
  SugarJar::Log.debug(
325
- 'After squash-merging, this branch is NOT fully merged to master'
332
+ 'After squash-merging, this branch is NOT fully merged to master',
326
333
  )
327
334
  false
328
335
  end
@@ -22,7 +22,9 @@ class SugarJar
22
22
  c = DEFAULTS.dup
23
23
  _find_ordered_files.each do |f|
24
24
  SugarJar::Log.debug("Loading config #{f}")
25
- c.merge!(YAML.safe_load(File.read(f)))
25
+ data = YAML.safe_load(File.read(f))
26
+ # an empty file is a `nil` which you can't merge
27
+ c.merge!(YAML.safe_load(File.read(f))) if data
26
28
  SugarJar::Log.debug("Modified config: #{c}")
27
29
  end
28
30
  c
@@ -3,9 +3,32 @@ require_relative 'log'
3
3
  class SugarJar
4
4
  # Some common methods needed by other classes
5
5
  module Util
6
+ # Finds the first entry in the path for a binary and checks
7
+ # to make sure it's not us (i.e. we may be linked to as 'git'
8
+ # or 'hub', but when we are calling that, we don't want ourselves.
9
+ def which_nofail(cmd)
10
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |dir|
11
+ p = File.join(dir, cmd)
12
+ # if it exists, and it is executable and is not us...
13
+ if File.exist?(p) && File.executable?(p) &&
14
+ File.basename(File.realpath(p)) != 'sj'
15
+ return p
16
+ end
17
+ end
18
+ false
19
+ end
20
+
21
+ def which(cmd)
22
+ path = which_nofail(cmd)
23
+ return path if path
24
+
25
+ SugarJar::Log.fatal("Could not find #{cmd} in your path")
26
+ exit(1)
27
+ end
28
+
6
29
  def hub_nofail(*args)
7
30
  SugarJar::Log.trace("Running: hub #{args.join(' ')}")
8
- Mixlib::ShellOut.new(['/usr/bin/hub'] + args).run_command
31
+ Mixlib::ShellOut.new([which('hub')] + args).run_command
9
32
  end
10
33
 
11
34
  def hub(*args)
@@ -1,3 +1,3 @@
1
1
  class SugarJar
2
- VERSION = '0.0.1'.freeze
2
+ VERSION = '0.0.2'.freeze
3
3
  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.1
4
+ version: 0.0.2
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-06-05 00:00:00.000000000 Z
11
+ date: 2020-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mixlib-log
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: yaml
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: bundler
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -130,7 +116,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
116
  - !ruby/object:Gem::Version
131
117
  version: '0'
132
118
  requirements: []
133
- rubygems_version: 3.0.3
119
+ rubyforge_project:
120
+ rubygems_version: 2.7.6.2
134
121
  signing_key:
135
122
  specification_version: 4
136
123
  summary: A git/github helper script