Support a string source in the route map
This commit is contained in:
parent
3f1bc3370b
commit
636e9bdd11
|
@ -459,6 +459,10 @@ A Route Map is a file inside the repository at `.gitlab/route-map.yml`, which co
|
||||||
This is an example of a route map for [Middleman](https://middlemanapp.com) static websites like [http://about.gitlab.com](https://gitlab.com/gitlab-com/www-gitlab-com):
|
This is an example of a route map for [Middleman](https://middlemanapp.com) static websites like [http://about.gitlab.com](https://gitlab.com/gitlab-com/www-gitlab-com):
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
# Team data
|
||||||
|
- source: 'data/team.yml' # data/team.yml
|
||||||
|
public: 'team/' # team/
|
||||||
|
|
||||||
# Blogposts
|
# Blogposts
|
||||||
- source: /source\/posts\/([0-9]{4})-([0-9]{2})-([0-9]{2})-(.+?)\..*/ # source/posts/2017-01-30-around-the-world-in-6-releases.html.md.erb
|
- source: /source\/posts\/([0-9]{4})-([0-9]{2})-([0-9]{2})-(.+?)\..*/ # source/posts/2017-01-30-around-the-world-in-6-releases.html.md.erb
|
||||||
public: '\1/\2/\3/\4/' # 2017/01/30/around-the-world-in-6-releases/
|
public: '\1/\2/\3/\4/' # 2017/01/30/around-the-world-in-6-releases/
|
||||||
|
@ -474,10 +478,18 @@ This is an example of a route map for [Middleman](https://middlemanapp.com) stat
|
||||||
|
|
||||||
Mappings are defined as entries in the root YAML array, and are identified by a `-` prefix. Within an entry, we have a hash map with two keys:
|
Mappings are defined as entries in the root YAML array, and are identified by a `-` prefix. Within an entry, we have a hash map with two keys:
|
||||||
|
|
||||||
- `source`: a regular expression, starting and ending with `/`. Can include capture groups denoted by `()` that can be referred to in the `public` path. Slashes (`/`) can, but don't have to be, escaped as `\/`.
|
- `source`
|
||||||
- `public`: a string, starting and ending with `'`. Can include `\N` expressions to refer to capture groups in the `source` regular expression in order of their occurence, starting with `\1`.
|
- a string, starting and ending with `'`, for an exact match
|
||||||
|
- a regular expression, starting and ending with `/`, for a pattern match
|
||||||
|
- The regular expression needs to match the entire source path - `^` and `$` anchors are implied.
|
||||||
|
- Can include capture groups denoted by `()` that can be referred to in the `public` path.
|
||||||
|
- Slashes (`/`) can, but don't have to, be escaped as `\/`.
|
||||||
|
- Literal periods (`.`) should be escaped as `\.`.
|
||||||
|
- `public`
|
||||||
|
- a string, starting and ending with `'`.
|
||||||
|
- Can include `\N` expressions to refer to capture groups in the `source` regular expression in order of their occurence, starting with `\1`.
|
||||||
|
|
||||||
The public path for a source path is determined by finding the first `source` expression that matches it, and returning the corresponding `public` path, replacing the `\N` expressions with the values of the `()` capture groups.
|
The public path for a source path is determined by finding the first `source` expression that matches it, and returning the corresponding `public` path, replacing the `\N` expressions with the values of the `()` capture groups if appropriate.
|
||||||
|
|
||||||
In the example above, the fact that mappings are evaluated in order of their definition is used to ensure that `source/index.html.haml` will match `/source\/(.+?\.html).*/` instead of `/source\/(.*)/`, and will result in a public path of `index.html`, instead of `index.html.haml`.
|
In the example above, the fact that mappings are evaluated in order of their definition is used to ensure that `source/index.html.haml` will match `/source\/(.+?\.html).*/` instead of `/source\/(.*)/`, and will result in a public path of `index.html`, instead of `index.html.haml`.
|
||||||
|
|
||||||
|
|
|
@ -6,16 +6,16 @@ module Gitlab
|
||||||
begin
|
begin
|
||||||
entries = YAML.safe_load(data)
|
entries = YAML.safe_load(data)
|
||||||
rescue
|
rescue
|
||||||
raise FormatError, 'Route map needs to be valid YAML'
|
raise FormatError, 'Route map is not valid YAML'
|
||||||
end
|
end
|
||||||
|
|
||||||
raise FormatError, 'Route map needs to be an array' unless entries.is_a?(Array)
|
raise FormatError, 'Route map is not an array' unless entries.is_a?(Array)
|
||||||
|
|
||||||
@map = entries.map { |entry| parse_entry(entry) }
|
@map = entries.map { |entry| parse_entry(entry) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def public_path_for_source_path(path)
|
def public_path_for_source_path(path)
|
||||||
mapping = @map.find { |mapping| path =~ mapping[:source] }
|
mapping = @map.find { |mapping| mapping[:source] === path }
|
||||||
return unless mapping
|
return unless mapping
|
||||||
|
|
||||||
path.sub(mapping[:source], mapping[:public])
|
path.sub(mapping[:source], mapping[:public])
|
||||||
|
@ -24,27 +24,25 @@ module Gitlab
|
||||||
private
|
private
|
||||||
|
|
||||||
def parse_entry(entry)
|
def parse_entry(entry)
|
||||||
raise FormatError, 'Route map entry needs to be a hash' unless entry.is_a?(Hash)
|
raise FormatError, 'Route map entry is not a hash' unless entry.is_a?(Hash)
|
||||||
raise FormatError, 'Route map entry requires a source key' unless entry.has_key?('source')
|
raise FormatError, 'Route map entry does not have a source key' unless entry.has_key?('source')
|
||||||
raise FormatError, 'Route map entry requires a public key' unless entry.has_key?('public')
|
raise FormatError, 'Route map entry does not have a public key' unless entry.has_key?('public')
|
||||||
|
|
||||||
source_regexp = entry['source']
|
source_pattern = entry['source']
|
||||||
public_path = entry['public']
|
public_path = entry['public']
|
||||||
|
|
||||||
unless source_regexp.start_with?('/') && source_regexp.end_with?('/')
|
if source_pattern.start_with?('/') && source_pattern.end_with?('/')
|
||||||
raise FormatError, 'Route map entry source needs to start and end in a slash (/)'
|
source_pattern = source_pattern[1...-1].gsub('\/', '/')
|
||||||
end
|
|
||||||
|
|
||||||
source_regexp = source_regexp[1...-1].gsub('\/', '/')
|
begin
|
||||||
|
source_pattern = Regexp.new("^#{source_pattern}$")
|
||||||
begin
|
rescue RegexpError => e
|
||||||
source_regexp = Regexp.new("^#{source_regexp}$")
|
raise FormatError, "Route map entry source is not a valid regular expression: #{e}"
|
||||||
rescue RegexpError => e
|
end
|
||||||
raise FormatError, "Route map entry source needs to be a valid regular expression: #{e}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
{
|
{
|
||||||
source: source_regexp,
|
source: source_pattern,
|
||||||
public: public_path
|
public: public_path
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -37,13 +37,6 @@ describe Gitlab::RouteMap, lib: true do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when an entry source does not start and end with a slash' do
|
|
||||||
it 'raises an error' do
|
|
||||||
expect { described_class.new(YAML.dump([{ 'source' => 'index.html', 'public' => 'index.html' }])) }.
|
|
||||||
to raise_error(Gitlab::RouteMap::FormatError, /a slash/)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when an entry source is not a valid regex' do
|
context 'when an entry source is not a valid regex' do
|
||||||
it 'raises an error' do
|
it 'raises an error' do
|
||||||
expect { described_class.new(YAML.dump([{ 'source' => '/[/', 'public' => 'index.html' }])) }.
|
expect { described_class.new(YAML.dump([{ 'source' => '/[/', 'public' => 'index.html' }])) }.
|
||||||
|
@ -53,9 +46,10 @@ describe Gitlab::RouteMap, lib: true do
|
||||||
|
|
||||||
context 'when all is good' do
|
context 'when all is good' do
|
||||||
it 'returns a route map' do
|
it 'returns a route map' do
|
||||||
route_map = described_class.new(YAML.dump([{ 'source' => '/index\.html/', 'public' => 'index.html' }]))
|
route_map = described_class.new(YAML.dump([{ 'source' => 'index.haml', 'public' => 'index.html' }, { 'source' => '/(.*)\.md/', 'public' => '\1.html' }]))
|
||||||
|
|
||||||
expect(route_map.public_path_for_source_path('index.html')).to eq('index.html')
|
expect(route_map.public_path_for_source_path('index.haml')).to eq('index.html')
|
||||||
|
expect(route_map.public_path_for_source_path('foo.md')).to eq('foo.html')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -63,6 +57,10 @@ describe Gitlab::RouteMap, lib: true do
|
||||||
describe '#public_path_for_source_path' do
|
describe '#public_path_for_source_path' do
|
||||||
subject do
|
subject do
|
||||||
described_class.new(<<-'MAP'.strip_heredoc)
|
described_class.new(<<-'MAP'.strip_heredoc)
|
||||||
|
# Team data
|
||||||
|
- source: 'data/team.yml'
|
||||||
|
public: 'team/'
|
||||||
|
|
||||||
# Blogposts
|
# Blogposts
|
||||||
- source: /source/posts/([0-9]{4})-([0-9]{2})-([0-9]{2})-(.+?)\..*/ # source/posts/2017-01-30-around-the-world-in-6-releases.html.md.erb
|
- source: /source/posts/([0-9]{4})-([0-9]{2})-([0-9]{2})-(.+?)\..*/ # source/posts/2017-01-30-around-the-world-in-6-releases.html.md.erb
|
||||||
public: '\1/\2/\3/\4/' # 2017/01/30/around-the-world-in-6-releases/
|
public: '\1/\2/\3/\4/' # 2017/01/30/around-the-world-in-6-releases/
|
||||||
|
@ -78,6 +76,8 @@ describe Gitlab::RouteMap, lib: true do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns the public path for a provided source path' do
|
it 'returns the public path for a provided source path' do
|
||||||
|
expect(subject.public_path_for_source_path('data/team.yml')).to eq('team/')
|
||||||
|
|
||||||
expect(subject.public_path_for_source_path('source/posts/2017-01-30-around-the-world-in-6-releases.html.md.erb')).to eq('2017/01/30/around-the-world-in-6-releases/')
|
expect(subject.public_path_for_source_path('source/posts/2017-01-30-around-the-world-in-6-releases.html.md.erb')).to eq('2017/01/30/around-the-world-in-6-releases/')
|
||||||
|
|
||||||
expect(subject.public_path_for_source_path('source/index.html.haml')).to eq('index.html')
|
expect(subject.public_path_for_source_path('source/index.html.haml')).to eq('index.html')
|
||||||
|
|
Loading…
Reference in New Issue