Commit 37f0b600bc9a994136791e6838b3228c56f909b2

Authored by Robert Speicher
1 parent 94af622c

Another RefExtractor refactor

lib/ref_extractor.rb
1 # Module providing an extract_ref method for controllers working with Git 1 # Module providing an extract_ref method for controllers working with Git
2 # tree-ish + path params 2 # tree-ish + path params
3 -#  
4 -# Given a string containing both a Git ref - such as a branch or tag - and a  
5 -# filesystem path joined by forward slashes, attempts to separate the two.  
6 -#  
7 -# Expects a @project instance variable to contain the active project. Used to  
8 -# check the input against a list of valid repository refs.  
9 -#  
10 -# Examples  
11 -#  
12 -# # No @project available  
13 -# extract_ref('master')  
14 -# # => ['', '']  
15 -#  
16 -# extract_ref('master')  
17 -# # => ['master', '/']  
18 -#  
19 -# extract_ref("f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG")  
20 -# # => ['f4b14494ef6abf3d144c28e4af0c20143383e062', '/CHANGELOG']  
21 -#  
22 -# extract_ref("v2.0.0/README.md")  
23 -# # => ['v2.0.0', '/README.md']  
24 -#  
25 -# extract_ref('issues/1234/app/models/project.rb')  
26 -# # => ['issues/1234', '/app/models/project.rb']  
27 -#  
28 -# # Given an invalid branch, we fall back to just splitting on the first slash  
29 -# extract_ref('non/existent/branch/README.md')  
30 -# # => ['non', '/existent/branch/README.md']  
31 -#  
32 -# Returns an Array where the first value is the tree-ish and the second is the  
33 -# path  
34 module RefExtractor 3 module RefExtractor
  4 + # Thrown when given an invalid path
  5 + class InvalidPathError < StandardError; end
  6 +
  7 + # Given a string containing both a Git ref - such as a branch or tag - and a
  8 + # filesystem path joined by forward slashes, attempts to separate the two.
  9 + #
  10 + # Expects a @project instance variable to contain the active project. Used to
  11 + # check the input against a list of valid repository refs.
  12 + #
  13 + # Examples
  14 + #
  15 + # # No @project available
  16 + # extract_ref('master')
  17 + # # => ['', '']
  18 + #
  19 + # extract_ref('master')
  20 + # # => ['master', '']
  21 + #
  22 + # extract_ref("f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG")
  23 + # # => ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']
  24 + #
  25 + # extract_ref("v2.0.0/README.md")
  26 + # # => ['v2.0.0', 'README.md']
  27 + #
  28 + # extract_ref('issues/1234/app/models/project.rb')
  29 + # # => ['issues/1234', 'app/models/project.rb']
  30 + #
  31 + # # Given an invalid branch, we fall back to just splitting on the first slash
  32 + # extract_ref('non/existent/branch/README.md')
  33 + # # => ['non', 'existent/branch/README.md']
  34 + #
  35 + # Returns an Array where the first value is the tree-ish and the second is the
  36 + # path
35 def extract_ref(input) 37 def extract_ref(input)
36 pair = ['', ''] 38 pair = ['', '']
37 39
@@ -41,24 +43,28 @@ module RefExtractor @@ -41,24 +43,28 @@ module RefExtractor
41 # If the ref appears to be a SHA, we're done, just split the string 43 # If the ref appears to be a SHA, we're done, just split the string
42 pair = $~.captures 44 pair = $~.captures
43 else 45 else
  46 + # Otherwise, attempt to detect the ref using a list of the project's
  47 + # branches and tags
  48 +
44 # Append a trailing slash if we only get a ref and no file path 49 # Append a trailing slash if we only get a ref and no file path
45 id = input 50 id = input
46 id += '/' unless id.include?('/') 51 id += '/' unless id.include?('/')
47 52
48 - # Otherwise, attempt to detect the ref using a list of the project's  
49 - # branches and tags  
50 valid_refs = @project.branches + @project.tags 53 valid_refs = @project.branches + @project.tags
51 valid_refs.select! { |v| id.start_with?("#{v}/") } 54 valid_refs.select! { |v| id.start_with?("#{v}/") }
52 55
53 if valid_refs.length != 1 56 if valid_refs.length != 1
54 # No exact ref match, so just try our best 57 # No exact ref match, so just try our best
55 - pair = id.match(/([^\/]+)(.+)/).captures 58 + pair = id.match(/([^\/]+)(.*)/).captures
56 else 59 else
57 # Partition the string into the ref and the path, ignoring the empty first value 60 # Partition the string into the ref and the path, ignoring the empty first value
58 pair = id.partition(valid_refs.first)[1..-1] 61 pair = id.partition(valid_refs.first)[1..-1]
59 end 62 end
60 end 63 end
61 64
  65 + # Remove leading slash from path
  66 + pair[1].gsub!(/^\//, '')
  67 +
62 pair 68 pair
63 end 69 end
64 end 70 end
spec/lib/ref_extractor_spec.rb
@@ -11,29 +11,48 @@ describe RefExtractor do @@ -11,29 +11,48 @@ describe RefExtractor do
11 project.stub(:tags).and_return(['v1.0.0', 'v2.0.0']) 11 project.stub(:tags).and_return(['v1.0.0', 'v2.0.0'])
12 end 12 end
13 13
14 - it "extracts a ref without a path" do  
15 - extract_ref('master').should == ['master', '/']  
16 - end  
17 -  
18 - it "extracts a valid branch ref" do  
19 - extract_ref('foo/bar/baz/CHANGELOG').should == ['foo/bar/baz', '/CHANGELOG']  
20 - end  
21 -  
22 - it "extracts a valid tag ref" do  
23 - extract_ref('v2.0.0/CHANGELOG').should == ['v2.0.0', '/CHANGELOG']  
24 - end  
25 -  
26 - it "extracts a valid commit ref" do  
27 - extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG').should ==  
28 - ['f4b14494ef6abf3d144c28e4af0c20143383e062', '/CHANGELOG']  
29 - end  
30 -  
31 - it "falls back to a primitive split for an invalid ref" do  
32 - extract_ref('stable/CHANGELOG').should == ['stable', '/CHANGELOG']  
33 - end  
34 -  
35 - it "returns an empty pair when no @project is set" do  
36 - @project = nil  
37 - extract_ref('master/CHANGELOG').should == ['', ''] 14 + describe '#extract_ref' do
  15 + it "returns an empty pair when no @project is set" do
  16 + @project = nil
  17 + extract_ref('master/CHANGELOG').should == ['', '']
  18 + end
  19 +
  20 + context "without a path" do
  21 + it "extracts a valid branch" do
  22 + extract_ref('master').should == ['master', '']
  23 + end
  24 +
  25 + it "extracts a valid tag" do
  26 + extract_ref('v2.0.0').should == ['v2.0.0', '']
  27 + end
  28 +
  29 + it "extracts a valid commit ref without a path" do
  30 + extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062').should ==
  31 + ['f4b14494ef6abf3d144c28e4af0c20143383e062', '']
  32 + end
  33 +
  34 + it "falls back to a primitive split for an invalid ref" do
  35 + extract_ref('stable').should == ['stable', '']
  36 + end
  37 + end
  38 +
  39 + context "with a path" do
  40 + it "extracts a valid branch" do
  41 + extract_ref('foo/bar/baz/CHANGELOG').should == ['foo/bar/baz', 'CHANGELOG']
  42 + end
  43 +
  44 + it "extracts a valid tag" do
  45 + extract_ref('v2.0.0/CHANGELOG').should == ['v2.0.0', 'CHANGELOG']
  46 + end
  47 +
  48 + it "extracts a valid commit SHA" do
  49 + extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG').should ==
  50 + ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']
  51 + end
  52 +
  53 + it "falls back to a primitive split for an invalid ref" do
  54 + extract_ref('stable/CHANGELOG').should == ['stable', 'CHANGELOG']
  55 + end
  56 + end
38 end 57 end
39 end 58 end