git_snip 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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