Commit d4acda12 authored by Robert Speicher's avatar Robert Speicher

Merge branch 'rs-relative-link-up-one' into 'master'

Allow relative links to go up one directory level

See merge request !1352
parents d4a96016 2b94f5fb
...@@ -59,25 +59,43 @@ module Gitlab ...@@ -59,25 +59,43 @@ module Gitlab
end end
def relative_file_path(path) def relative_file_path(path)
nested_path = build_nested_path(path, context[:requested_path]) nested_path = build_relative_path(path, context[:requested_path])
file_exists?(nested_path) ? nested_path : path file_exists?(nested_path) ? nested_path : path
end end
# Covering a special case, when the link is referencing file in the same # Convert a relative path into its correct location based on the currently
# directory. # requested path
# If we are at doc/api/README.md and the README.md contains relative #
# links like [Users](users.md), this takes the request # path - Relative path String
# path(doc/api/README.md) and replaces the README.md with users.md so the # request_path - Currently-requested path String
# path looks like doc/api/users.md. #
# If we are at doc/api and the README.md shown in below the tree view # Examples:
# this takes the request path(doc/api) and adds users.md so the path #
# looks like doc/api/users.md # # File in the same directory as the current path
def build_nested_path(path, request_path) # build_relative_path("users.md", "doc/api/README.md")
# # => "doc/api/users.md"
#
# # File in the same directory, which is also the current path
# build_relative_path("users.md", "doc/api")
# # => "doc/api/users.md"
#
# # Going up one level to a different directory
# build_relative_path("../update/7.14-to-8.0.md", "doc/api/README.md")
# # => "doc/update/7.14-to-8.0.md"
#
# Returns a String
def build_relative_path(path, request_path)
return request_path if path.empty? return request_path if path.empty?
return path unless request_path return path unless request_path
parts = request_path.split('/') parts = request_path.split('/')
parts.pop if path_type(request_path) != 'tree' parts.pop if path_type(request_path) != 'tree'
while parts.length > 1 && path.start_with?('../')
parts.pop
path.sub!('../', '')
end
parts.push(path).join('/') parts.push(path).join('/')
end end
......
...@@ -4,14 +4,16 @@ require 'spec_helper' ...@@ -4,14 +4,16 @@ require 'spec_helper'
module Gitlab::Markdown module Gitlab::Markdown
describe RelativeLinkFilter do describe RelativeLinkFilter do
def filter(doc) def filter(doc, contexts = {})
described_class.call(doc, { contexts.reverse_merge!({
commit: project.commit, commit: project.commit,
project: project, project: project,
project_wiki: project_wiki, project_wiki: project_wiki,
ref: ref, ref: ref,
requested_path: requested_path requested_path: requested_path
}) })
described_class.call(doc, contexts)
end end
def image(path) def image(path)
...@@ -75,6 +77,22 @@ module Gitlab::Markdown ...@@ -75,6 +77,22 @@ module Gitlab::Markdown
to eq "/#{project_path}/blob/#{ref}/doc/api/README.md" to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
end end
it 'rebuilds relative URL for a file in the repo up one directory' do
relative_link = link('../api/README.md')
doc = filter(relative_link, requested_path: 'doc/update/7.14-to-8.0.md')
expect(doc.at_css('a')['href']).
to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
end
it 'rebuilds relative URL for a file in the repo up multiple directories' do
relative_link = link('../../../api/README.md')
doc = filter(relative_link, requested_path: 'doc/foo/bar/baz/README.md')
expect(doc.at_css('a')['href']).
to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
end
it 'rebuilds relative URL for a file in the repo with an anchor' do it 'rebuilds relative URL for a file in the repo with an anchor' do
doc = filter(link('README.md#section')) doc = filter(link('README.md#section'))
expect(doc.at_css('a')['href']). expect(doc.at_css('a')['href']).
...@@ -108,8 +126,8 @@ module Gitlab::Markdown ...@@ -108,8 +126,8 @@ module Gitlab::Markdown
escaped = Addressable::URI.escape(path) escaped = Addressable::URI.escape(path)
# Stub these methods so the file doesn't actually need to be in the repo # Stub these methods so the file doesn't actually need to be in the repo
allow_any_instance_of(described_class).to receive(:file_exists?). allow_any_instance_of(described_class).
and_return(true) to receive(:file_exists?).and_return(true)
allow_any_instance_of(described_class). allow_any_instance_of(described_class).
to receive(:image?).with(path).and_return(true) to receive(:image?).with(path).and_return(true)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment