git_curate 0.7.1 → 0.7.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 +4 -4
- data/CHANGELOG.md +8 -0
- data/VERSION +1 -1
- data/lib/git_curate.rb +1 -0
- data/lib/git_curate/app.rb +8 -2
- data/lib/git_curate/branch.rb +61 -36
- data/lib/git_curate/cli_parser.rb +4 -2
- data/lib/git_curate/exceptions.rb +16 -0
- data/lib/git_curate/runner.rb +11 -7
- data/lib/git_curate/util.rb +3 -2
- data/lib/git_curate/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81714cf7534f51e20f211a41f3b93173c51fc066c8605e8fdd3c4b2887208309
|
4
|
+
data.tar.gz: 2325066c76763a77dcc7734120da18d0cc71083b5f8586d4d10d8ae7cf647abd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2a73379b744efb995a7aef5727f9be1b77617b26395f649eea0d16cfda72da49d675bfd8f270873e3d478918180e93d45e10fa43078f08da0d0eab3b43ad38c
|
7
|
+
data.tar.gz: 822e799c402d44bd7bb7d7e32d12c88bf411385e628d3d2bfdfba9479b95c7d3b5e4457903f13df2fecabe9508cd439cfa5c753f15bbff43c6a0b94fd0d6d6bf
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
### v0.7.2
|
4
|
+
|
5
|
+
* Nicer error messages; for example, if `git curate` is run outside of a git repo, the user will now see
|
6
|
+
the same error message as they would see from running `git branch` (as opposed to seeing an unsightly stack trace)
|
7
|
+
* Performance improvements: it now runs faster, as the number of system calls made by the
|
8
|
+
application is reduced
|
9
|
+
* Improvements to code structure and internal documentation
|
10
|
+
|
3
11
|
### v0.7.1
|
4
12
|
|
5
13
|
* Fix errors on -h, -v and --version options due to incorrect exit code handling
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.2
|
data/lib/git_curate.rb
CHANGED
data/lib/git_curate/app.rb
CHANGED
@@ -4,17 +4,23 @@ module GitCurate
|
|
4
4
|
|
5
5
|
module App
|
6
6
|
|
7
|
+
# Runs the application and returns an exit status which should be passed to exit() by
|
8
|
+
# the caller of this function.
|
7
9
|
def self.main
|
8
10
|
parser = GitCurate::CLIParser.new
|
9
11
|
continue = parser.parse(ARGV) # will throw on error
|
10
|
-
return
|
12
|
+
return EXIT_SUCCESS unless continue
|
11
13
|
|
12
14
|
runner = GitCurate::Runner.new(parser.parsed_options)
|
15
|
+
# Args not parsed by the CLIParser are passed to Runner.
|
13
16
|
runner.run(ARGV)
|
17
|
+
rescue SystemCommandError => error
|
18
|
+
$stderr.puts(error.message)
|
19
|
+
error.exit_status
|
14
20
|
rescue OptionParser::InvalidOption
|
15
21
|
puts "Unrecognized option"
|
16
22
|
puts "For help, enter `git curate -h`"
|
17
|
-
|
23
|
+
EXIT_FAILURE
|
18
24
|
end
|
19
25
|
|
20
26
|
end
|
data/lib/git_curate/branch.rb
CHANGED
@@ -10,21 +10,30 @@ module GitCurate
|
|
10
10
|
LEADING_STAR_REGEX = /^\* /
|
11
11
|
REMOTE_INFO_REGEX = /^[^\s]+\s+[^\s]+\s+\[(.+?)\]/
|
12
12
|
|
13
|
+
# Returns the branch name, with "* " prefixed if it's the current branch.
|
13
14
|
attr_reader :raw_name
|
14
15
|
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
end
|
16
|
+
# Returns a human-friendly string describing the status of the branch relative to the upstream branch
|
17
|
+
# it's tracking, if any.
|
18
|
+
attr_reader :upstream_info
|
19
19
|
|
20
|
+
# Returns simply the name of the branch, without any other "decoration".
|
20
21
|
def proper_name
|
21
22
|
@proper_name ||= @raw_name.lstrip.sub(CURRENT_BRANCH_REGEX, '')
|
22
23
|
end
|
23
24
|
|
25
|
+
# Returns truthy if and only if this is the currently checked out branch.
|
24
26
|
def current?
|
25
27
|
@current ||= (@raw_name =~ CURRENT_BRANCH_REGEX)
|
26
28
|
end
|
27
29
|
|
30
|
+
# Return truthy if and only if this branch has been merged into the current HEAD.
|
31
|
+
def merged?
|
32
|
+
@merged
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the branch's name, with a prefix of "* " if it's the currently checked out branch, or else a prefix
|
36
|
+
# of " ". Branch displayable names are designed to be aligned with each other for display in a vertical column.
|
28
37
|
def displayable_name(pad:)
|
29
38
|
if pad && !current?
|
30
39
|
" #{@raw_name}"
|
@@ -33,58 +42,74 @@ module GitCurate
|
|
33
42
|
end
|
34
43
|
end
|
35
44
|
|
36
|
-
def
|
37
|
-
|
45
|
+
def last_commit_date
|
46
|
+
initialize_last_commit_data
|
47
|
+
@last_commit_date
|
38
48
|
end
|
39
49
|
|
40
|
-
def
|
41
|
-
|
50
|
+
def last_author
|
51
|
+
initialize_last_commit_data
|
52
|
+
@last_author
|
42
53
|
end
|
43
54
|
|
44
55
|
def last_subject
|
45
|
-
|
56
|
+
initialize_last_commit_data
|
57
|
+
@last_subject
|
46
58
|
end
|
47
59
|
|
48
60
|
# Returns the local branches
|
49
61
|
def self.local
|
50
|
-
|
51
|
-
end
|
62
|
+
merged_branch_raw_names = Util.command_to_a("git branch --merged").to_set
|
52
63
|
|
53
|
-
|
54
|
-
|
55
|
-
|
64
|
+
branch_info.map do |raw_name, info|
|
65
|
+
new(raw_name, merged: merged_branch_raw_names.include?(raw_name), upstream_info: info)
|
66
|
+
end
|
56
67
|
end
|
57
68
|
|
58
|
-
|
59
|
-
|
60
|
-
#
|
61
|
-
|
69
|
+
private
|
70
|
+
|
71
|
+
# Returns a Hash containing, as keys, the raw names of all local branches and, as values,
|
72
|
+
# a brief description of each branch's status relative to its upstream branch (up to
|
73
|
+
# date, or ahead/behind).
|
74
|
+
def self.branch_info
|
62
75
|
Util.command_to_a("git branch -vv").map do |line|
|
63
|
-
line
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
end.compact.to_h
|
76
|
+
line_is_current_branch = (line =~ LEADING_STAR_REGEX)
|
77
|
+
tidied_line = (line_is_current_branch ? line.gsub(LEADING_STAR_REGEX, "") : line)
|
78
|
+
proper_branch_name = tidied_line.split(BRANCH_NAME_REGEX)[0]
|
79
|
+
raw_branch_name = (line_is_current_branch ? "* #{proper_branch_name}" : proper_branch_name)
|
80
|
+
remote_info = tidied_line[REMOTE_INFO_REGEX, 1]
|
81
|
+
upstream_info =
|
82
|
+
if remote_info.nil?
|
83
|
+
"No upstream"
|
84
|
+
else
|
85
|
+
comparison_raw = remote_info.split(":")
|
86
|
+
comparison_raw.length < 2 ? "Up to date" : comparison_raw[1].strip.capitalize
|
87
|
+
end
|
88
|
+
[raw_branch_name, upstream_info]
|
89
|
+
end.to_h
|
78
90
|
end
|
79
91
|
|
80
92
|
def self.delete_multi(*branches)
|
81
93
|
Util.command_output("git branch -D #{branches.map(&:proper_name).join(" ")} --")
|
82
94
|
end
|
83
95
|
|
84
|
-
|
96
|
+
# raw_name should start in "* " if the current branch, but should otherwise have not whitespace.
|
97
|
+
def initialize(raw_name, merged:, upstream_info:)
|
98
|
+
@raw_name = raw_name
|
99
|
+
@merged = merged
|
100
|
+
@upstream_info = upstream_info
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns an array with [date, author, subject], each as a string.
|
104
|
+
def initialize_last_commit_data
|
105
|
+
return if @last_commit_data
|
106
|
+
|
107
|
+
# For Windows compatibility we need double quotes around the format string, as well as spaces
|
108
|
+
# between the placeholders.
|
109
|
+
command = %Q(git log -n1 --date=short --format=format:"%cd %n %an %n %s" #{proper_name} --)
|
110
|
+
@last_commit_data = Util.command_to_a(command)
|
85
111
|
|
86
|
-
|
87
|
-
Util.command_to_a(command).map { |raw_branch_name| self.new(raw_branch_name) }
|
112
|
+
@last_commit_date, @last_author, @last_subject = @last_commit_data
|
88
113
|
end
|
89
114
|
|
90
115
|
end
|
@@ -10,8 +10,10 @@ module GitCurate
|
|
10
10
|
@parsed_options = {}
|
11
11
|
end
|
12
12
|
|
13
|
-
# Sets @parsed_options according to the options received, and return truthy
|
14
|
-
#
|
13
|
+
# Sets @parsed_options according to the options received, and return truthy if and only if the program should
|
14
|
+
# continue after the options are passed. Usually this method should be passed ARGV. Any elements of `options` that
|
15
|
+
# are not processed by this method, will remain in `options`; elements that are processed, will be destructively
|
16
|
+
# removed from `options`.
|
15
17
|
def parse(options)
|
16
18
|
opt_parser = OptionParser.new do |opts|
|
17
19
|
opts.banner = <<-EOF
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module GitCurate
|
2
|
+
|
3
|
+
EXIT_SUCCESS = 0
|
4
|
+
EXIT_FAILURE = 1
|
5
|
+
|
6
|
+
# Error indicating that a system command has exited with a non-success exit status.
|
7
|
+
class SystemCommandError < StandardError
|
8
|
+
|
9
|
+
attr_reader :exit_status
|
10
|
+
|
11
|
+
def initialize(message, exit_status)
|
12
|
+
super(message)
|
13
|
+
@exit_status = exit_status
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/git_curate/runner.rb
CHANGED
@@ -5,15 +5,21 @@ require "tty-screen"
|
|
5
5
|
|
6
6
|
module GitCurate
|
7
7
|
|
8
|
-
|
9
|
-
EXIT_FAILURE = 1
|
10
|
-
|
8
|
+
# Contains the main logic of the application.
|
11
9
|
class Runner
|
12
10
|
|
11
|
+
# Accepts a Hash of options passed from the parsed command line. Currently there is only one option, :list,
|
12
|
+
# which is treated as a boolean, and determines whether the branches will simply be listed non-interactively
|
13
|
+
# (list: true), or interactively with opportunities for the user to select branches for deletion (list: false).
|
13
14
|
def initialize(opts)
|
14
15
|
@opts = opts
|
15
16
|
end
|
16
17
|
|
18
|
+
# Runs the application, listing branches either interactively or non-interactively. Returns an exit status,
|
19
|
+
# suitable for passing to `exit()`.
|
20
|
+
# `args` should be passed an array of non-option/non-flag arguments received from the command
|
21
|
+
# line. If this array is of inappropriate length, EXIT_FAILURE will be returned. (The
|
22
|
+
# appropriate length may be 0.)
|
17
23
|
def run(args)
|
18
24
|
if args.length != 0
|
19
25
|
$stderr.puts "This script does not accept any arguments."
|
@@ -22,8 +28,6 @@ module GitCurate
|
|
22
28
|
|
23
29
|
branches = Branch.local
|
24
30
|
branches.reject!(&:current?) if interactive?
|
25
|
-
merged_branch_names = Branch.local_merged.map(&:proper_name).to_set
|
26
|
-
upstream_branches = Branch.upstream_info
|
27
31
|
|
28
32
|
table = Tabulo::Table.new(branches, vertical_rule_character: " ", intersection_character: " ",
|
29
33
|
horizontal_rule_character: "-", column_padding: 0, align_header: :left) do |t|
|
@@ -32,8 +36,8 @@ module GitCurate
|
|
32
36
|
t.add_column("Last commit", &:last_commit_date)
|
33
37
|
t.add_column("Last author", &:last_author)
|
34
38
|
t.add_column("Last subject", &:last_subject)
|
35
|
-
t.add_column("Merged#{$/}into HEAD?") { |b|
|
36
|
-
t.add_column("Status vs#{$/}upstream"
|
39
|
+
t.add_column("Merged#{$/}into HEAD?") { |b| b.merged? ? "Merged" : "Not merged" }
|
40
|
+
t.add_column("Status vs#{$/}upstream", &:upstream_info)
|
37
41
|
end
|
38
42
|
|
39
43
|
prompt = " Delete? [y/N/done/abort/help] "
|
data/lib/git_curate/util.rb
CHANGED
@@ -15,9 +15,10 @@ module GitCurate
|
|
15
15
|
# output as its message.
|
16
16
|
def self.command_output(command)
|
17
17
|
stdout_str, stderr_str, status = Open3.capture3(command)
|
18
|
+
exit_status = status.exitstatus
|
18
19
|
|
19
|
-
if
|
20
|
-
raise
|
20
|
+
if exit_status != EXIT_SUCCESS
|
21
|
+
raise SystemCommandError.new(stderr_str, exit_status)
|
21
22
|
end
|
22
23
|
|
23
24
|
stdout_str
|
data/lib/git_curate/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git_curate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Harvey
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-08-
|
11
|
+
date: 2019-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -163,6 +163,7 @@ files:
|
|
163
163
|
- lib/git_curate/branch.rb
|
164
164
|
- lib/git_curate/cli_parser.rb
|
165
165
|
- lib/git_curate/copyright.rb
|
166
|
+
- lib/git_curate/exceptions.rb
|
166
167
|
- lib/git_curate/runner.rb
|
167
168
|
- lib/git_curate/util.rb
|
168
169
|
- lib/git_curate/version.rb
|