twig 1.3 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,9 @@
1
1
  class Twig
2
2
  class Branch
3
3
 
4
- EMPTY_PROPERTY_NAME_ERROR = 'Branch property names cannot be empty strings.'
5
- PROPERTY_NAME_FROM_GIT_CONFIG = /^branch\.[^.]+\.([^=]+)=.*$/
6
- RESERVED_BRANCH_PROPERTIES = %w[branch merge rebase remote]
4
+ EMPTY_PROPERTY_NAME_ERROR = 'Branch property names cannot be empty strings.'
5
+ PROPERTY_NAME_FROM_GIT_CONFIG = /^branch\.[^.]+\.([^=]+)=.*$/
6
+ RESERVED_BRANCH_PROPERTY_NAMES = %w[branch merge rebase remote]
7
7
 
8
8
  class EmptyPropertyNameError < ArgumentError
9
9
  def initialize(message = nil)
@@ -15,8 +15,8 @@ class Twig
15
15
 
16
16
  attr_accessor :name, :last_commit_time
17
17
 
18
- def self.all_properties
19
- @_all_properties ||= begin
18
+ def self.all_property_names
19
+ @_all_property_names ||= begin
20
20
  config_lines = Twig.run('git config --list').split("\n")
21
21
 
22
22
  properties = config_lines.map do |line|
@@ -29,7 +29,7 @@ class Twig
29
29
  key_parts.last if key_parts[0] == 'branch' && key_parts.size > 2
30
30
  end.compact
31
31
 
32
- properties.uniq.sort - RESERVED_BRANCH_PROPERTIES
32
+ properties.uniq.sort - RESERVED_BRANCH_PROPERTY_NAMES
33
33
  end
34
34
  end
35
35
 
@@ -46,12 +46,43 @@ class Twig
46
46
  property_name.gsub(/[ _]+/, '')
47
47
  end
48
48
 
49
+ def get_properties(property_names)
50
+ return {} if property_names.empty?
51
+
52
+ property_name_regexps = property_names.map do |property_name|
53
+ property_name = sanitize_property(property_name)
54
+ raise EmptyPropertyNameError if property_name.empty?
55
+ Regexp.escape(property_name)
56
+ end.join('|')
57
+
58
+ git_config_regexp = "branch\.#{name}\.(#{ property_name_regexps })$"
59
+ cmd = %{git config --get-regexp "#{git_config_regexp}"}
60
+
61
+ git_result = Twig.run(cmd) || ''
62
+ git_result_lines = git_result.split("\n")
63
+
64
+ git_result_lines.inject({}) do |properties, line|
65
+ match_data = line.match(/^branch\.#{name}\.([^\s]+)\s+(.*)$/)
66
+
67
+ if match_data
68
+ property_name = match_data[1]
69
+ property_value = match_data[2]
70
+ else
71
+ property_value = ''
72
+ end
73
+
74
+ if property_value.empty?
75
+ properties
76
+ else
77
+ properties.merge(property_name => property_value)
78
+ end
79
+ end
80
+
81
+ end
82
+
49
83
  def get_property(property_name)
50
84
  property_name = sanitize_property(property_name)
51
- raise EmptyPropertyNameError if property_name.empty?
52
-
53
- value = Twig.run("git config branch.#{name}.#{property_name}")
54
- value == '' ? nil : value
85
+ get_properties([property_name])[property_name]
55
86
  end
56
87
 
57
88
  def set_property(property_name, value)
@@ -60,14 +91,15 @@ class Twig
60
91
 
61
92
  if property_name.empty?
62
93
  raise EmptyPropertyNameError
63
- elsif RESERVED_BRANCH_PROPERTIES.include?(property_name)
94
+ elsif RESERVED_BRANCH_PROPERTY_NAMES.include?(property_name)
64
95
  raise ArgumentError,
65
96
  %{Can't modify the reserved property "#{property_name}".}
66
97
  elsif value.empty?
67
98
  raise ArgumentError,
68
99
  %{Can't set a branch property to an empty string.}
69
100
  else
70
- Twig.run(%{git config branch.#{name}.#{property_name} "#{value}"})
101
+ git_config = "branch.#{name}.#{property_name}"
102
+ Twig.run(%{git config #{git_config} "#{value}"})
71
103
  result_body = %{property "#{property_name}" as "#{value}" for branch "#{name}".}
72
104
  if $?.success?
73
105
  "Saved #{result_body}"
@@ -84,7 +116,8 @@ class Twig
84
116
  value = get_property(property_name)
85
117
 
86
118
  if value
87
- Twig.run(%{git config --unset branch.#{name}.#{property_name}})
119
+ git_config = "branch.#{name}.#{property_name}"
120
+ Twig.run(%{git config --unset #{git_config}})
88
121
  %{Removed property "#{property_name}" for branch "#{name}".}
89
122
  else
90
123
  raise MissingPropertyError,
@@ -94,7 +94,7 @@ class Twig
94
94
  end
95
95
 
96
96
  def read_cli_options!(args)
97
- custom_properties = Twig::Branch.all_properties
97
+ custom_properties = Twig::Branch.all_property_names
98
98
 
99
99
  option_parser = OptionParser.new do |opts|
100
100
  opts.banner = help_intro
@@ -186,7 +186,7 @@ class Twig
186
186
  desc =
187
187
  'Lists all branches regardless of other filtering options. ' +
188
188
  'Useful for overriding options in ' +
189
- File.basename(Twig::Options::CONFIG_FILE) + '.'
189
+ File.basename(Twig::Options::CONFIG_PATH) + '.'
190
190
  opts.on('--all', *help_description(desc)) do |pattern|
191
191
  unset_option(:max_days_old)
192
192
  unset_option(:property_except)
@@ -240,15 +240,42 @@ class Twig
240
240
 
241
241
 
242
242
 
243
+ help_separator(opts, 'GitHub integration:')
244
+
245
+ desc = <<-DESC
246
+ Set a custom GitHub API URI prefix, e.g.,
247
+ https://github-enterprise.example.com/api/v3.
248
+ DESC
249
+ opts.on(
250
+ '--github-api-uri-prefix PREFIX',
251
+ *help_description(desc, :add_separator => true)
252
+ ) do |prefix|
253
+ set_option(:github_api_uri_prefix, prefix)
254
+ end
255
+
256
+ desc = <<-DESC
257
+ Set a custom GitHub URI prefix, e.g.,
258
+ https://github-enterprise.example.com.
259
+ DESC
260
+ opts.on(
261
+ '--github-uri-prefix PREFIX',
262
+ *help_description(desc, :add_separator => true)
263
+ ) do |prefix|
264
+ set_option(:github_uri_prefix, prefix)
265
+ end
266
+
267
+
268
+
243
269
  help_separator(opts, help_paragraph(%{
244
270
  You can put your most frequently used options for filtering and
245
- listing branches into #{Twig::Options::CONFIG_FILE}. For example:
271
+ listing branches into #{Twig::Options::CONFIG_PATH}. For example:
246
272
  }), :trailing => '')
247
273
 
248
274
  help_separator(opts, [
249
275
  ' except-branch: staging',
250
276
  ' header-style: green bold',
251
- ' max-days-old: 30'
277
+ ' max-days-old: 30',
278
+ ' reverse: true',
252
279
  ].join("\n"), :trailing => '')
253
280
 
254
281
  help_separator(opts, help_paragraph(%{
@@ -66,6 +66,7 @@ class Twig
66
66
  end
67
67
 
68
68
  def branch_list_headers(header_options = {})
69
+ all_property_names = Twig::Branch.all_property_names
69
70
  branch_indicator_padding = ' ' * CURRENT_BRANCH_INDICATOR.size
70
71
 
71
72
  header_options.merge!(
@@ -80,7 +81,7 @@ class Twig
80
81
  )
81
82
 
82
83
  out = column(' ', :width => date_time_column_width) << column_gutter
83
- out << Twig::Branch.all_properties.map do |property|
84
+ out << all_property_names.map do |property|
84
85
  width = property_column_width(property)
85
86
  column(property, header_options.merge(:width => width)) << column_gutter
86
87
  end.join
@@ -88,7 +89,7 @@ class Twig
88
89
  out << "\n"
89
90
 
90
91
  out << column(' ', :width => date_time_column_width) << column_gutter
91
- out << Twig::Branch.all_properties.map do |property|
92
+ out << all_property_names.map do |property|
92
93
  width = property_column_width(property)
93
94
  underline = '-' * property.size
94
95
  column(underline, header_options.merge(:width => width)) << column_gutter
@@ -100,20 +101,22 @@ class Twig
100
101
  end
101
102
 
102
103
  def branch_list_line(branch)
103
- is_current_branch = branch.name == current_branch_name
104
-
105
- properties = Twig::Branch.all_properties.inject({}) do |result, property_name|
106
- property = (get_branch_property(branch.name, property_name) || '').strip
107
- property = EMPTY_BRANCH_PROPERTY_INDICATOR if property.empty?
108
- property.gsub!(/[\n\r]+/, ' ')
109
- result.merge(property_name => property)
104
+ all_property_names = Twig::Branch.all_property_names
105
+ is_current_branch = branch.name == current_branch_name
106
+
107
+ properties = branch.get_properties(all_property_names)
108
+ properties = all_property_names.inject({}) do |result, property_name|
109
+ property_value = (properties[property_name] || '').strip
110
+ property_value = EMPTY_BRANCH_PROPERTY_INDICATOR if property_value.empty?
111
+ property_value.gsub!(/[\n\r]+/, ' ')
112
+ result.merge(property_name => property_value)
110
113
  end
111
114
 
112
115
  line = column(branch.last_commit_time.to_s, :width => date_time_column_width)
113
116
  line << column_gutter
114
117
 
115
118
  line <<
116
- Twig::Branch.all_properties.map do |property_name|
119
+ all_property_names.map do |property_name|
117
120
  property_value = properties[property_name] || ''
118
121
  width = property_column_width(property_name)
119
122
  column(property_value, :width => width) << column_gutter
@@ -144,7 +147,10 @@ class Twig
144
147
  string_options << WEIGHTS[options[:weight]] if options[:weight]
145
148
  return string if string_options.empty?
146
149
 
147
- "\e[#{string_options.join(';')}m#{string}\e[0m"
150
+ open_format = "\e[#{string_options.join(';')}m"
151
+ close_format = "\e[0m"
152
+
153
+ open_format + string.to_s + close_format
148
154
  end
149
155
 
150
156
  def unformat_string(string)
@@ -1,3 +1,5 @@
1
+ require 'uri'
2
+
1
3
  class Twig
2
4
  class GithubRepo
3
5
  def initialize
@@ -21,7 +23,9 @@ class Twig
21
23
  end
22
24
 
23
25
  def github_repo?
24
- origin_url.include?('github.com')
26
+ gh_url_prefix = 'https://github.com'
27
+ uri = URI.parse(gh_url_prefix)
28
+ origin_url.include?(uri.host)
25
29
  end
26
30
 
27
31
  def username
@@ -1,15 +1,24 @@
1
1
  class Twig
2
2
  module Options
3
3
 
4
- CONFIG_FILE = '~/.twigrc'
4
+ CONFIG_PATH = '~/.twigconfig'
5
+ DEPRECATED_CONFIG_PATH = '~/.twigrc'
5
6
  MIN_PROPERTY_WIDTH = 3
6
7
 
7
8
  def read_config_file!
8
- config_file_path = File.expand_path(Twig::CONFIG_FILE)
9
- return unless File.readable?(config_file_path)
9
+ config_path = File.expand_path(Twig::CONFIG_PATH)
10
+ unless File.readable?(config_path)
11
+ config_path = File.expand_path(Twig::DEPRECATED_CONFIG_PATH)
12
+ if File.readable?(config_path)
13
+ $stderr.puts "DEPRECATED: #{DEPRECATED_CONFIG_PATH} is deprecated. " <<
14
+ "Please rename it to #{CONFIG_PATH}."
15
+ else
16
+ return
17
+ end
18
+ end
10
19
 
11
- File.open(config_file_path) do |f|
12
- opts = f.read.split("\n").inject({}) do |hsh, line|
20
+ File.open(config_path) do |file|
21
+ opts = file.read.split("\n").inject({}) do |hsh, line|
13
22
  line = line.strip
14
23
 
15
24
  if line !~ /^#/
@@ -44,6 +53,12 @@ class Twig
44
53
  property_name = key.sub(/-width$/, '').to_sym
45
54
  set_option(:property_width, property_name => value)
46
55
 
56
+ # GitHub integration:
57
+ when 'github-api-uri-prefix'
58
+ set_option(:github_api_uri_prefix, value)
59
+ when 'github-uri-prefix'
60
+ set_option(:github_uri_prefix, value)
61
+
47
62
  end
48
63
  end
49
64
  end
@@ -58,6 +73,9 @@ class Twig
58
73
  abort %{The branch "#{value}" could not be found.}
59
74
  end
60
75
 
76
+ when :github_api_uri_prefix, :github_uri_prefix
77
+ options[key] = value
78
+
61
79
  when :header_style
62
80
  set_header_style_option(value)
63
81
 
@@ -122,17 +140,18 @@ class Twig
122
140
 
123
141
  property_name_width = property_name.to_s.size
124
142
  property_value = property_value.to_i
143
+ min_property_value = [property_name_width, MIN_PROPERTY_WIDTH].max
125
144
 
126
- if property_value < [property_name_width, MIN_PROPERTY_WIDTH].max
127
- error = %{The value `--#{property_name}-width=#{property_value}` } +
128
- %{is too low. The minimum is }
129
-
130
- if property_value < property_name_width
131
- error << %{#{property_name_width} (width of "#{property_name}").}
132
- elsif property_value < MIN_PROPERTY_WIDTH
133
- error << %{#{MIN_PROPERTY_WIDTH}.}
145
+ if property_value < min_property_value
146
+ min_desc = if property_value < property_name_width
147
+ %{#{property_name_width} (width of "#{property_name}")}
148
+ else
149
+ %{#{MIN_PROPERTY_WIDTH}}
134
150
  end
135
151
 
152
+ error = %{The value `--#{property_name}-width=#{property_value}` } +
153
+ %{is too low. The minimum is #{min_desc}.}
154
+
136
155
  abort error
137
156
  end
138
157
 
@@ -1,3 +1,3 @@
1
1
  class Twig
2
- VERSION = '1.3'
2
+ VERSION = '1.4'
3
3
  end
@@ -5,9 +5,9 @@ describe Twig::Branch do
5
5
  @twig = Twig.new
6
6
  end
7
7
 
8
- describe '.all_properties' do
8
+ describe '.all_property_names' do
9
9
  before :each do
10
- Twig::Branch.instance_variable_set(:@_all_properties, nil)
10
+ Twig::Branch.instance_variable_set(:@_all_property_names, nil)
11
11
  @config = %{
12
12
  user.name=Ron DeVera
13
13
  branch.autosetupmerge=always
@@ -29,7 +29,7 @@ describe Twig::Branch do
29
29
  it 'returns the union of properties for all branches' do
30
30
  Twig.should_receive(:run).with('git config --list').and_return(@config)
31
31
 
32
- result = Twig::Branch.all_properties
32
+ result = Twig::Branch.all_property_names
33
33
  result.should == %w[test0 test1 test2]
34
34
  end
35
35
 
@@ -37,7 +37,7 @@ describe Twig::Branch do
37
37
  @config << 'branch.dot1.dot2.dot3.dotproperty=dotvalue'
38
38
  Twig.should_receive(:run).with('git config --list').and_return(@config)
39
39
 
40
- result = Twig::Branch.all_properties
40
+ result = Twig::Branch.all_property_names
41
41
  result.should == %w[dotproperty test0 test1 test2]
42
42
  end
43
43
 
@@ -45,20 +45,20 @@ describe Twig::Branch do
45
45
  @config << 'branch.eq1=eq2=eq3.eqproperty=eqvalue'
46
46
  Twig.should_receive(:run).with('git config --list').and_return(@config)
47
47
 
48
- result = Twig::Branch.all_properties
48
+ result = Twig::Branch.all_property_names
49
49
  result.should == %w[eqproperty test0 test1 test2]
50
50
  end
51
51
 
52
52
  it 'skips path values with an equal sign but no value' do
53
53
  @config << 'foo_path='
54
54
  Twig.should_receive(:run).with('git config --list').and_return(@config)
55
- result = Twig::Branch.all_properties
55
+ result = Twig::Branch.all_property_names
56
56
  result.should_not include 'foo_path'
57
57
  end
58
58
 
59
59
  it 'memoizes the result' do
60
60
  Twig.should_receive(:run).once.and_return(@config)
61
- 2.times { Twig::Branch.all_properties }
61
+ 2.times { Twig::Branch.all_property_names }
62
62
  end
63
63
  end
64
64
 
@@ -100,50 +100,78 @@ describe Twig::Branch do
100
100
  end
101
101
  end
102
102
 
103
- describe '#get_property' do
103
+ describe '#get_properties' do
104
104
  before :each do
105
105
  @branch = Twig::Branch.new('test')
106
106
  end
107
107
 
108
- it 'returns a property value' do
109
- property = 'test'
110
- value = 'value'
108
+ it 'returns a hash of property names and values' do
109
+ properties = {
110
+ 'test1' => 'value1',
111
+ 'test2' => 'value2'
112
+ }
113
+ git_result = [
114
+ "branch.#{@branch}.test1 value1",
115
+ "branch.#{@branch}.test2 value2"
116
+ ].join("\n")
111
117
  Twig.should_receive(:run).
112
- with(%{git config branch.#{@branch}.#{property}}).
113
- and_return(value)
118
+ with(%{git config --get-regexp "branch.#{@branch}.(test1|test2)$"}).
119
+ and_return(git_result)
114
120
 
115
- result = @branch.get_property(property)
116
- result.should == value
121
+ result = @branch.get_properties(%w[test1 test2])
122
+ result.should == properties
117
123
  end
118
124
 
119
- it 'removes whitespace from branch property names' do
120
- bad_property = ' foo foo '
121
- property = 'foofoo'
122
- value = 'bar'
125
+ it 'returns an empty hash if no property names are given' do
126
+ Twig.should_not_receive(:run)
127
+
128
+ result = @branch.get_properties([])
129
+ result.should == {}
130
+ end
131
+
132
+ it 'returns an empty hash if no matching property names are found' do
133
+ git_result = ''
123
134
  Twig.should_receive(:run).
124
- with(%{git config branch.#{@branch}.#{property}}).
125
- and_return(value)
135
+ with(%{git config --get-regexp "branch.#{@branch}.(test1|test2)$"}).
136
+ and_return(git_result)
126
137
 
127
- result = @branch.get_property(bad_property)
128
- result.should == value
138
+ result = @branch.get_properties(%w[test1 test2])
139
+ result.should == {}
129
140
  end
130
141
 
131
- it 'returns nil if the property value is an empty string' do
132
- property = 'test'
142
+ it 'removes whitespace from property names' do
143
+ bad_property_name = ' foo foo '
144
+ property_name = 'foofoo'
145
+ property_value = 'bar'
146
+ properties = { property_name => property_value }
147
+ git_result = "branch.#{@branch}.#{property_name} #{property_value}"
133
148
  Twig.should_receive(:run).
134
- with(%{git config branch.#{@branch}.#{property}}).
135
- and_return('')
149
+ with(%{git config --get-regexp "branch.#{@branch}.(#{property_name})$"}).
150
+ and_return(git_result)
136
151
 
137
- result = @branch.get_property(property)
138
- result.should == nil
152
+ result = @branch.get_properties([bad_property_name])
153
+ result.should == properties
139
154
  end
140
155
 
141
- it 'raises an error if the property name is an empty string' do
142
- property = ' '
156
+ it 'excludes properties whose values are empty strings' do
157
+ git_result = [
158
+ "branch.#{@branch}.test1 value1",
159
+ "branch.#{@branch}.test2"
160
+ ].join("\n")
161
+ Twig.should_receive(:run).
162
+ with(%{git config --get-regexp "branch.#{@branch}.(test1|test2)$"}).
163
+ and_return(git_result)
164
+
165
+ result = @branch.get_properties(%w[test1 test2])
166
+ result.should == { 'test1' => 'value1' }
167
+ end
168
+
169
+ it 'raises an error if any property name is an empty string' do
170
+ property_name = ' '
143
171
  Twig.should_not_receive(:run)
144
172
 
145
173
  begin
146
- @branch.get_property(property)
174
+ @branch.get_properties(['test1', property_name])
147
175
  rescue Twig::Branch::EmptyPropertyNameError => exception
148
176
  expected_exception = exception
149
177
  end
@@ -152,6 +180,35 @@ describe Twig::Branch do
152
180
  end
153
181
  end
154
182
 
183
+ describe '#get_property' do
184
+ before :each do
185
+ @branch = Twig::Branch.new('test')
186
+ end
187
+
188
+ it 'returns a property value' do
189
+ property = 'test'
190
+ value = 'value'
191
+ @branch.should_receive(:get_properties).
192
+ with([property]).
193
+ and_return(property => value)
194
+
195
+ result = @branch.get_property(property)
196
+ result.should == value
197
+ end
198
+
199
+ it 'removes whitespace from branch property names' do
200
+ bad_property = ' foo foo '
201
+ property = 'foofoo'
202
+ value = 'bar'
203
+ @branch.should_receive(:get_properties).
204
+ with([property]).
205
+ and_return(property => value)
206
+
207
+ result = @branch.get_property(bad_property)
208
+ result.should == value
209
+ end
210
+ end
211
+
155
212
  describe '#set_property' do
156
213
  before :each do
157
214
  @branch = Twig::Branch.new('test')