git_snip 0.0.3 → 0.0.4

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
  SHA1:
3
- metadata.gz: 971bfdab966edf6e8d0f147bd19f85eb0f72c8ac
4
- data.tar.gz: c8c3db3af432f657a11ff0e4bde9d292b26a10b3
3
+ metadata.gz: a20a58119f68056d5761981e0440ba321231416d
4
+ data.tar.gz: 8c095dc7ee582d109391f0ab07dab8fe0c48fc13
5
5
  SHA512:
6
- metadata.gz: b5d5cff6b4b5e2ba9b495925283b30d16e042a8c7b81e94ccc0f81b96acb71035fdf030927871593d69744ca2f2719c5edc08c569e0f454d72bdd57e0da511a0
7
- data.tar.gz: c55e1e8fbe97572c4b8b858c65f4509170d87ac4d5f6e59c6c8899756cbca9650d05fc1679d900e5a9c9d349359c8ed152e99ea1e515398ee52c90dae6a3dfff
6
+ metadata.gz: bb771326cd8b86b479b7ce7c9ae1a7f23758327445370b65cc682e7537bf10a07ca08df7b0bf7bb2cbcd0be2feaa9e88ec7c5e106b0220d50d79c80d7b7b5b38
7
+ data.tar.gz: ce9d2f055e48b91d10422ffefcc7cf3983774a72b0c979a014773fb933a831ea1177ae13c61c00ea2dec62e7afe9f84d7b75eaf4d3203faff0409acaf26ab874
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  ## master (unreleased)
2
2
 
3
+ ## 0.0.4
4
+
5
+ * Add config file.
6
+
7
+ * Add `--full` option to show most branch information without cropping.
8
+
9
+ Thanks to @bgreg for the idea and suggestions. Thanks to
10
+ [Ruby Workshop](http://www.meetup.com/Silicone-Valley-Ruby-Workshop/) too.
11
+
3
12
  ## 0.0.3
4
13
 
5
14
  * Fix missing new line after each branch line.
data/README.md CHANGED
@@ -38,6 +38,11 @@ Delete branches already merged to master:
38
38
 
39
39
  $ git snip -f
40
40
 
41
+ Delete branches already merged to master and show more detailed listing of
42
+ deleted branches:
43
+
44
+ $ git snip -f --full
45
+
41
46
  Delete branches already merged to master, except staging and production:
42
47
 
43
48
  $ git snip -f --ignore=staging production
@@ -50,6 +55,26 @@ Delete branches already merged to `branch_a`:
50
55
 
51
56
  $ git snip -f --target=branch_a
52
57
 
58
+ You can also list the available options from command line:
59
+
60
+ $ git snip help
61
+
62
+ ## Config file
63
+
64
+ If you want some arguments to always be set, add a file to the root of the
65
+ repository with name `.git_snip.yml`. Specify the default arguments as YAML in
66
+ the file like this:
67
+
68
+ ```yaml
69
+ full: true
70
+ ignore:
71
+ - staging
72
+ - production
73
+ ```
74
+
75
+ The config arguments are overridden when the same arguments are set from command
76
+ line.
77
+
53
78
  ## Contributing
54
79
 
55
80
  1. Fork it ( https://github.com/htanata/git_snip/fork )
@@ -1,15 +1,24 @@
1
1
  module GitSnip
2
2
  module Branch
3
- class Column < Struct.new(:sha, :name, :date, :author, :message)
3
+ Row = Struct.new(:sha, :name, :date, :author, :message)
4
+
5
+ def self.row(branch)
6
+ Row.new.tap do |row|
7
+ row.sha = column(branch.gcommit.sha, 7)
8
+ row.name = column(branch.name, 12)
9
+ row.date = column(branch.gcommit.date.strftime('%F'), 10)
10
+ row.author = column(branch.gcommit.author.email.sub(/@.*/, ''), 8)
11
+ row.message = column(first_line(branch.gcommit.message), 39)
12
+ end
4
13
  end
5
14
 
6
- def self.columnize(branch)
7
- Column.new.tap do |column|
8
- column.sha = column(branch.gcommit.sha, 7)
9
- column.name = column(branch.name, 12)
10
- column.date = column(branch.gcommit.date.strftime('%F'), 10)
11
- column.author = column(branch.gcommit.author.email.sub(/@.*/, ''), 8)
12
- column.message = column(first_line(branch.gcommit.message), 39)
15
+ def self.full_row(branch)
16
+ Row.new.tap do |row|
17
+ row.sha = branch.gcommit.sha
18
+ row.name = branch.name
19
+ row.date = branch.gcommit.date.iso8601
20
+ row.author = branch.gcommit.author.email
21
+ row.message = first_line(branch.gcommit.message)
13
22
  end
14
23
  end
15
24
 
data/lib/git_snip/cli.rb CHANGED
@@ -1,11 +1,18 @@
1
1
  require 'thor'
2
2
  require 'git_snip/cleaner'
3
3
  require 'git_snip/branch'
4
+ require 'git_snip/config'
4
5
 
5
6
  module GitSnip
6
7
  class CLI < Thor
7
8
  include Thor::Actions
8
9
 
10
+ class << self
11
+ def help(shell, subcommand = 'snip')
12
+ command_help(shell, subcommand)
13
+ end
14
+ end
15
+
9
16
  option :force, type: :boolean, aliases: '-f',
10
17
  desc: 'Will refuse to run unless given -f or -n.'
11
18
 
@@ -21,13 +28,16 @@ module GitSnip
21
28
  option :ignore, type: :array, default: [],
22
29
  desc: 'List of branches to ignore.'
23
30
 
31
+ option :full, type: :boolean,
32
+ desc: 'Show most branch information without cropping.'
33
+
24
34
  desc '', 'Delete branches which have been merged to target.'
25
35
  def snip
26
- if options[:dry_run]
36
+ if opts[:dry_run]
27
37
  return dry_run
28
38
  end
29
39
 
30
- if !options[:force]
40
+ if !opts[:force]
31
41
  say '-f option is needed to delete branches.', :red
32
42
  exit 64
33
43
  end
@@ -69,18 +79,39 @@ module GitSnip
69
79
  end
70
80
  end
71
81
 
72
- def say_branch_info(branch)
73
- Branch.columnize(branch).tap do |column|
74
- say column.sha + ' ', :yellow
75
- say column.name + ' ', :magenta
76
- say column.date + ' ', :green
77
- say column.author + ' ', [:blue, :bold]
78
- say column.message.strip + "\n"
79
- end
82
+ def say_branch_info(branch, full = false)
83
+ row = opts[:full] ? Branch.full_row(branch) : Branch.row(branch)
84
+
85
+ say row.sha + ' ', :yellow
86
+ say row.name + ' ', :magenta
87
+ say row.date + ' ', :green
88
+ say row.author + ' ', [:blue, :bold]
89
+ say row.message.strip + "\n"
80
90
  end
81
91
 
82
92
  def cleaner_args
83
- options.values_at(:repo, :target, :ignore)
93
+ opts.values_at(:repo, :target, :ignore)
94
+ end
95
+
96
+ def opts
97
+ @opts ||= begin
98
+ config = Config.new(options[:repo])
99
+
100
+ options_dup = options.dup
101
+
102
+ options_dup.each_pair do |k, v|
103
+ if v.is_a?(Array) && v.empty?
104
+ config_value = config.options[k]
105
+
106
+ if config_value.is_a?(Array) && config_value.any?
107
+ options_dup[k] = config_value
108
+ end
109
+ end
110
+ end
111
+
112
+ Thor::CoreExt::HashWithIndifferentAccess.new(
113
+ config.options.merge(options_dup)).freeze
114
+ end
84
115
  end
85
116
  end
86
117
  end
@@ -0,0 +1,23 @@
1
+ require 'yaml'
2
+
3
+ module GitSnip
4
+ class Config
5
+ def initialize(repo_path = '.')
6
+ @repo_path = repo_path
7
+ end
8
+
9
+ def options
10
+ @options ||= read_file || {}
11
+ end
12
+
13
+ private
14
+
15
+ def read_file
16
+ YAML.load_file(config_path) if File.exist?(config_path)
17
+ end
18
+
19
+ def config_path
20
+ "#{@repo_path.chomp('/')}/.git_snip.yml"
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module GitSnip
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -1,42 +1,61 @@
1
1
  require 'git_snip/branch'
2
2
 
3
3
  RSpec.describe GitSnip::Branch do
4
- it 'should return values with number of characters within 80' do
5
- result = described_class.columnize(build_branch(build_column))
4
+ describe '.row' do
5
+ it 'should return values with number of characters within 80' do
6
+ result = described_class.row(build_branch(build_row))
6
7
 
7
- expect([
8
- result.sha, result.name, result.author, result.date, result.message
9
- ].join(' ').size).to eq(80)
8
+ expect([
9
+ result.sha, result.name, result.author, result.date, result.message
10
+ ].join(' ').size).to eq(80)
11
+ end
12
+
13
+ it 'should remove message starting from the first new line' do
14
+ row = build_row(message: "First line\n\nThird line")
15
+ result = described_class.row(build_branch(row))
16
+
17
+ expect(result.message).to eq('First line' + (' ' * 29))
18
+ end
10
19
  end
11
20
 
12
- it 'should remove message starting from the first new line' do
13
- column = build_column(message: "First line\n\nThird line")
14
- result = described_class.columnize(build_branch(column))
21
+ describe '.full_row' do
22
+ it 'should return values while keeping most of the words' do
23
+ row = build_row(
24
+ message: ('A' * 100) + "\n\n" + ('B' * 85),
25
+ author: 'would_you_kindly@example.com'
26
+ )
27
+
28
+ result = described_class.full_row(build_branch(row))
15
29
 
16
- expect(result.message).to eq('First line' + (' ' * 29))
30
+ expect(result.sha).to eq(row.sha)
31
+ expect(result.name).to eq(row.name)
32
+ expect(result.author).to eq(row.author)
33
+ expect(result.date).to eq(row.date.iso8601)
34
+ expect(result.message).to eq('A' * 100)
35
+ end
17
36
  end
18
37
 
19
- def build_branch(column)
20
- author = instance_double('Git::Author', email: column.author)
38
+ def build_branch(row)
39
+ author = instance_double('Git::Author', email: row.author)
21
40
 
22
41
  gcommit = instance_double(
23
42
  'Git::Gcommit',
24
- sha: column.sha,
25
- date: column.date,
26
- message: column.message,
43
+ sha: row.sha,
44
+ date: row.date,
45
+ message: row.message,
27
46
  author: author
28
47
  )
29
48
 
30
- instance_double('Git::Branch', name: column.name, gcommit: gcommit)
49
+ instance_double('Git::Branch', name: row.name, gcommit: gcommit)
31
50
  end
32
51
 
33
- def build_column(attrs = {})
34
- described_class::Column.new.tap do |column|
35
- column.sha = attrs[:sha] || '28720606978a7257f735ce67df50bc55ccf1c138'
36
- column.name = attrs[:name] || 'a_pretty_long_branch_name'
37
- column.author = attrs[:author] || 'inigo_montoya@example.com'
38
- column.date = attrs[:date] || Time.now
39
- column.message = attrs[:message] || 'Hello, my name is Inigo Montoya.'
52
+ def build_row(attrs = {})
53
+ described_class::Row.new.tap do |row|
54
+ row.sha = attrs[:sha] || '28720606978a7257f735ce67df50bc55ccf1c138'
55
+ row.name = attrs[:name] || 'a_pretty_long_branch_name'
56
+ row.author = attrs[:author] || 'inigo_montoya@example.com'
57
+ row.date = attrs[:date] || Time.now
58
+ row.message = attrs[:message] || 'Hello, my name is Inigo Montoya.'
40
59
  end
41
60
  end
42
61
 
@@ -0,0 +1,11 @@
1
+ require 'git_snip/cli'
2
+
3
+ RSpec.describe GitSnip::CLI, 'help' do
4
+ include CliHelper
5
+
6
+ it 'should display help for snip subcommand' do
7
+ stdout, _, _ = git_snip('help', :blank_slate)
8
+ expect(stdout).to match('--force')
9
+ expect(stdout).to match('--dry-run')
10
+ end
11
+ end
@@ -139,4 +139,72 @@ RSpec.describe GitSnip::CLI do
139
139
  expect(stdout).to match(/merged.+Version 2\n/)
140
140
  end
141
141
  end
142
+
143
+ describe 'with --full' do
144
+ it 'should not wrap the branch listing' do
145
+ setup_basic_repo
146
+
147
+ repo.commit_on_branch(
148
+ 'branch_with_really_long_name', "#{'A' * 100}\n\n#{'B' * 100}")
149
+
150
+ repo.merge_to_master('branch_with_really_long_name')
151
+
152
+ stdout, _, _ = git_snip('-n --full')
153
+
154
+ expect(stdout).to match("#{'A' * 100}\n")
155
+ expect(stdout).to match('branch_with_really_long_name')
156
+ end
157
+ end
158
+
159
+ context 'with config file' do
160
+ include_context 'config'
161
+
162
+ let(:config_dir) { repo.path }
163
+
164
+ before do
165
+ remove_config(config_dir)
166
+ end
167
+
168
+ it 'should handle boolean config options' do
169
+ setup_basic_repo
170
+
171
+ create_config(config_dir, 'dry_run' => true)
172
+
173
+ stdout, _, exitstatus = git_snip
174
+
175
+ expect(exitstatus).to eq(0)
176
+ expect(stdout).to match("Would delete the following branches...\n\n")
177
+ expect(stdout).to match("merged")
178
+ expect(stdout).to match("\n\nDone.")
179
+ expect(exitstatus).to eq(0)
180
+
181
+ expect(repo.branch_exists?('merged')).to be_truthy
182
+ end
183
+
184
+ it 'should set handle list config options' do
185
+ setup_basic_repo
186
+
187
+ create_config(config_dir, 'ignore' => ['merged'])
188
+
189
+ stdout, _, exitstatus = git_snip('--dry-run')
190
+
191
+ expect(stdout).to eq(
192
+ "Would delete the following branches...\n\n" \
193
+ "No branches would be deleted.\n"
194
+ )
195
+
196
+ expect(exitstatus).to eq(0)
197
+ end
198
+
199
+ specify 'command line arguments should override config' do
200
+ setup_basic_repo
201
+
202
+ create_config(config_dir, 'dry_run' => true)
203
+
204
+ stdout, _, exitstatus = git_snip('--no-dry-run')
205
+
206
+ expect(stdout).to eq("-f option is needed to delete branches.\n")
207
+ expect(exitstatus).to eq(64)
208
+ end
209
+ end
142
210
  end
@@ -0,0 +1,24 @@
1
+ require 'git_snip/config'
2
+
3
+ RSpec.describe GitSnip::Config do
4
+ include_context 'config'
5
+
6
+ let(:config_dir) { 'tmp' }
7
+
8
+ before do
9
+ remove_config(config_dir)
10
+ end
11
+
12
+ describe '#options' do
13
+ it "should be an empty hash when config file doesn't exist" do
14
+ expect(described_class.new(config_dir).options).to eq({})
15
+ end
16
+
17
+ it 'should read content of config file and convert keys to symbol' do
18
+ options = { 'foo' => 'bar' }
19
+ create_config(config_dir, options)
20
+
21
+ expect(described_class.new(config_dir).options).to eq('foo' => 'bar')
22
+ end
23
+ end
24
+ end
@@ -14,11 +14,14 @@ module CliHelper
14
14
  end
15
15
  end
16
16
 
17
- def git_snip(args = '')
17
+ def git_snip(args = '', blank_slate = false)
18
18
  stdin, stdout, stderr = Array.new(3) { StringIO.new }
19
19
 
20
+ arguments = args.dup
21
+ arguments << " --repo=#{repo.path}" unless blank_slate
22
+
20
23
  runner =
21
- GitSnip::CLIRunner.new("#{args} --repo=#{repo.path}".split(' '),
24
+ GitSnip::CLIRunner.new(arguments.split(' '),
22
25
  stdin, stdout, stderr, FakeKernel.new)
23
26
 
24
27
  exitstatus = runner.execute!
@@ -0,0 +1,18 @@
1
+ require 'yaml'
2
+
3
+ shared_context 'config' do
4
+ def create_config(config_dir, options)
5
+ FileUtils.mkdir_p(config_dir)
6
+ File.open(config_path(config_dir), 'w') { |f| f.write(options.to_yaml) }
7
+ end
8
+
9
+ def remove_config(config_dir)
10
+ path = config_path(config_dir)
11
+
12
+ FileUtils.rm_f(path)
13
+ end
14
+
15
+ def config_path(config_dir)
16
+ "#{config_dir}/.git_snip.yml"
17
+ end
18
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git_snip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hendy Tanata
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-12 00:00:00.000000000 Z
11
+ date: 2015-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: git
@@ -102,13 +102,17 @@ files:
102
102
  - lib/git_snip/branch.rb
103
103
  - lib/git_snip/cleaner.rb
104
104
  - lib/git_snip/cli.rb
105
+ - lib/git_snip/config.rb
105
106
  - lib/git_snip/version.rb
106
107
  - spec/lib/git_snip/branch_spec.rb
107
108
  - spec/lib/git_snip/cleaner_spec.rb
109
+ - spec/lib/git_snip/cli_help_spec.rb
108
110
  - spec/lib/git_snip/cli_spec.rb
111
+ - spec/lib/git_snip/config_spec.rb
109
112
  - spec/spec_helper.rb
110
113
  - spec/support/cli_helper.rb
111
114
  - spec/support/cli_runner.rb
115
+ - spec/support/config_shared_context.rb
112
116
  - spec/support/repo.rb
113
117
  homepage: https://github.com/htanata/git_snip
114
118
  licenses:
@@ -137,8 +141,11 @@ summary: Clean obsolete branches on your local git repository safely
137
141
  test_files:
138
142
  - spec/lib/git_snip/branch_spec.rb
139
143
  - spec/lib/git_snip/cleaner_spec.rb
144
+ - spec/lib/git_snip/cli_help_spec.rb
140
145
  - spec/lib/git_snip/cli_spec.rb
146
+ - spec/lib/git_snip/config_spec.rb
141
147
  - spec/spec_helper.rb
142
148
  - spec/support/cli_helper.rb
143
149
  - spec/support/cli_runner.rb
150
+ - spec/support/config_shared_context.rb
144
151
  - spec/support/repo.rb