Commit 567767bcf2af2c330c46fde820101fcf847e852f

Authored by Robert Speicher
1 parent b389247c

Add ref_extractor helper module for upcoming controllers

lib/ref_extractor.rb 0 → 100644
... ... @@ -0,0 +1,64 @@
  1 +# Module providing an extract_ref method for controllers working with Git
  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
  35 + def extract_ref(input)
  36 + pair = ['', '']
  37 +
  38 + return pair unless @project
  39 +
  40 + if input.match(/^([[:alnum:]]{40})(.+)/)
  41 + # If the ref appears to be a SHA, we're done, just split the string
  42 + pair = $~.captures
  43 + else
  44 + # Append a trailing slash if we only get a ref and no file path
  45 + id = input
  46 + id += '/' unless id.include?('/')
  47 +
  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
  51 + valid_refs.select! { |v| id.start_with?("#{v}/") }
  52 +
  53 + if valid_refs.length != 1
  54 + # No exact ref match, so just try our best
  55 + pair = id.match(/([^\/]+)(.+)/).captures
  56 + else
  57 + # Partition the string into the ref and the path, ignoring the empty first value
  58 + pair = id.partition(valid_refs.first)[1..-1]
  59 + end
  60 + end
  61 +
  62 + pair
  63 + end
  64 +end
... ...
spec/lib/ref_extractor_spec.rb 0 → 100644
... ... @@ -0,0 +1,39 @@
  1 +require 'spec_helper'
  2 +
  3 +describe RefExtractor do
  4 + include RefExtractor
  5 +
  6 + let(:project) { double('project') }
  7 +
  8 + before do
  9 + @project = project
  10 + project.stub(:branches).and_return(['master', 'foo/bar/baz'])
  11 + project.stub(:tags).and_return(['v1.0.0', 'v2.0.0'])
  12 + end
  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 == ['', '']
  38 + end
  39 +end
... ...