Fix image webhook rewriting for uploads
This rewrote URLs to be absolute URLs. However, for uploads (the most common case), we actually need them to point to not just the GitLab instance, but the project they're from. Thankfully, we can normally get that information from the object we're building the hook for.
This commit is contained in:
parent
c7fd95584e
commit
0bcfd0adb3
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix auto-corrected upload URLs in webhooks
|
||||
merge_request: 22361
|
||||
author:
|
||||
type: fixed
|
|
@ -73,8 +73,8 @@ Below are described the supported events.
|
|||
|
||||
Triggered when you push to the repository except when pushing tags.
|
||||
|
||||
> **Note:** When more than 20 commits are pushed at once, the `commits` web hook
|
||||
attribute will only contain the first 20 for performance reasons. Loading
|
||||
> **Note:** When more than 20 commits are pushed at once, the `commits` web hook
|
||||
attribute will only contain the first 20 for performance reasons. Loading
|
||||
detailed commit data is expensive. Note that despite only 20 commits being
|
||||
present in the `commits` attribute, the `total_commits_count` attribute will
|
||||
contain the actual total.
|
||||
|
@ -1157,10 +1157,11 @@ its description:
|
|||
```
|
||||
|
||||
It will appear in the webhook body as the below (assuming that GitLab is
|
||||
installed at gitlab.example.com):
|
||||
installed at gitlab.example.com, and the project is at
|
||||
example-group/example-project):
|
||||
|
||||
```markdown
|
||||
![image](https://gitlab.example.com/uploads/$sha/image.png)
|
||||
![image](https://gitlab.example.com/example-group/example-project/uploads/$sha/image.png)
|
||||
```
|
||||
|
||||
This will not rewrite URLs that already are pointing to HTTP, HTTPS, or
|
||||
|
|
|
@ -25,6 +25,7 @@ module Gitlab
|
|||
markdown_text.gsub(MARKDOWN_SIMPLE_IMAGE) do
|
||||
if $~[:image]
|
||||
url = $~[:url]
|
||||
url = "#{uploads_prefix}#{url}" if url.start_with?('/uploads')
|
||||
url = "/#{url}" unless url.start_with?('/')
|
||||
|
||||
"![#{$~[:title]}](#{Gitlab.config.gitlab.url}#{url})"
|
||||
|
@ -33,6 +34,16 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def uploads_prefix
|
||||
project&.full_path || ''
|
||||
end
|
||||
|
||||
def project
|
||||
return unless object.respond_to?(:project)
|
||||
|
||||
object.project
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,57 +8,94 @@ describe Gitlab::HookData::BaseBuilder do
|
|||
end
|
||||
end
|
||||
|
||||
subject { subclass.new(nil) }
|
||||
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where do
|
||||
{
|
||||
'relative image URL' => {
|
||||
input: '![an image](foo.png)',
|
||||
output: "![an image](#{Gitlab.config.gitlab.url}/foo.png)"
|
||||
},
|
||||
'HTTP URL' => {
|
||||
input: '![an image](http://example.com/foo.png)',
|
||||
output: '![an image](http://example.com/foo.png)'
|
||||
},
|
||||
'HTTPS URL' => {
|
||||
input: '![an image](https://example.com/foo.png)',
|
||||
output: '![an image](https://example.com/foo.png)'
|
||||
},
|
||||
'protocol-relative URL' => {
|
||||
input: '![an image](//example.com/foo.png)',
|
||||
output: '![an image](//example.com/foo.png)'
|
||||
},
|
||||
'URL reference by title' => {
|
||||
input: "![foo]\n\n[foo]: foo.png",
|
||||
output: "![foo]\n\n[foo]: foo.png"
|
||||
},
|
||||
'URL reference by label' => {
|
||||
input: "![][foo]\n\n[foo]: foo.png",
|
||||
output: "![][foo]\n\n[foo]: foo.png"
|
||||
},
|
||||
'in Markdown inline code block' => {
|
||||
input: '`![an image](foo.png)`',
|
||||
output: "`![an image](#{Gitlab.config.gitlab.url}/foo.png)`"
|
||||
},
|
||||
'in HTML tag on the same line' => {
|
||||
input: '<p>![an image](foo.png)</p>',
|
||||
output: "<p>![an image](#{Gitlab.config.gitlab.url}/foo.png)</p>"
|
||||
},
|
||||
'in Markdown multi-line code block' => {
|
||||
input: "```\n![an image](foo.png)\n```",
|
||||
output: "```\n![an image](foo.png)\n```"
|
||||
},
|
||||
'in HTML tag on different lines' => {
|
||||
input: "<p>\n![an image](foo.png)\n</p>",
|
||||
output: "<p>\n![an image](foo.png)\n</p>"
|
||||
context 'with an upload prefix specified' do
|
||||
let(:project_with_path) { double(full_path: 'baz/bar') }
|
||||
let(:object_with_project) { double(project: project_with_path) }
|
||||
subject { subclass.new(object_with_project) }
|
||||
|
||||
where do
|
||||
{
|
||||
'relative image URL' => {
|
||||
input: '![an image](foo.png)',
|
||||
output: "![an image](#{Gitlab.config.gitlab.url}/foo.png)"
|
||||
},
|
||||
'absolute upload URL' => {
|
||||
input: '![an image](/uploads/foo.png)',
|
||||
output: "![an image](#{Gitlab.config.gitlab.url}/baz/bar/uploads/foo.png)"
|
||||
},
|
||||
'absolute non-upload URL' => {
|
||||
input: '![an image](/downloads/foo.png)',
|
||||
output: "![an image](#{Gitlab.config.gitlab.url}/downloads/foo.png)"
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
with_them do
|
||||
it { expect(subject.absolute_image_urls(input)).to eq(output) }
|
||||
end
|
||||
end
|
||||
|
||||
with_them do
|
||||
it { expect(subject.absolute_image_urls(input)).to eq(output) }
|
||||
context 'without an upload prefix specified' do
|
||||
subject { subclass.new(nil) }
|
||||
|
||||
where do
|
||||
{
|
||||
'relative image URL' => {
|
||||
input: '![an image](foo.png)',
|
||||
output: "![an image](#{Gitlab.config.gitlab.url}/foo.png)"
|
||||
},
|
||||
'absolute upload URL' => {
|
||||
input: '![an image](/uploads/foo.png)',
|
||||
output: "![an image](#{Gitlab.config.gitlab.url}/uploads/foo.png)"
|
||||
},
|
||||
'absolute non-upload URL' => {
|
||||
input: '![an image](/downloads/foo.png)',
|
||||
output: "![an image](#{Gitlab.config.gitlab.url}/downloads/foo.png)"
|
||||
},
|
||||
'HTTP URL' => {
|
||||
input: '![an image](http://example.com/foo.png)',
|
||||
output: '![an image](http://example.com/foo.png)'
|
||||
},
|
||||
'HTTPS URL' => {
|
||||
input: '![an image](https://example.com/foo.png)',
|
||||
output: '![an image](https://example.com/foo.png)'
|
||||
},
|
||||
'protocol-relative URL' => {
|
||||
input: '![an image](//example.com/foo.png)',
|
||||
output: '![an image](//example.com/foo.png)'
|
||||
},
|
||||
'URL reference by title' => {
|
||||
input: "![foo]\n\n[foo]: foo.png",
|
||||
output: "![foo]\n\n[foo]: foo.png"
|
||||
},
|
||||
'URL reference by label' => {
|
||||
input: "![][foo]\n\n[foo]: foo.png",
|
||||
output: "![][foo]\n\n[foo]: foo.png"
|
||||
},
|
||||
'in Markdown inline code block' => {
|
||||
input: '`![an image](foo.png)`',
|
||||
output: "`![an image](#{Gitlab.config.gitlab.url}/foo.png)`"
|
||||
},
|
||||
'in HTML tag on the same line' => {
|
||||
input: '<p>![an image](foo.png)</p>',
|
||||
output: "<p>![an image](#{Gitlab.config.gitlab.url}/foo.png)</p>"
|
||||
},
|
||||
'in Markdown multi-line code block' => {
|
||||
input: "```\n![an image](foo.png)\n```",
|
||||
output: "```\n![an image](foo.png)\n```"
|
||||
},
|
||||
'in HTML tag on different lines' => {
|
||||
input: "<p>\n![an image](foo.png)\n</p>",
|
||||
output: "<p>\n![an image](foo.png)\n</p>"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
with_them do
|
||||
it { expect(subject.absolute_image_urls(input)).to eq(output) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -46,7 +46,10 @@ describe Gitlab::HookData::IssueBuilder do
|
|||
let(:builder) { described_class.new(issue_with_description) }
|
||||
|
||||
it 'sets the image to use an absolute URL' do
|
||||
expect(data[:description]).to eq("test![Issue_Image](#{Settings.gitlab.url}/uploads/abc/Issue_Image.png)")
|
||||
expected_path = "#{issue_with_description.project.path_with_namespace}/uploads/abc/Issue_Image.png"
|
||||
|
||||
expect(data[:description])
|
||||
.to eq("test![Issue_Image](#{Settings.gitlab.url}/#{expected_path})")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,11 +58,14 @@ describe Gitlab::HookData::MergeRequestBuilder do
|
|||
end
|
||||
|
||||
context 'when the MR has an image in the description' do
|
||||
let(:mr_with_description) { create(:merge_request, description: 'test![Issue_Image](/uploads/abc/Issue_Image.png)') }
|
||||
let(:mr_with_description) { create(:merge_request, description: 'test![MR_Image](/uploads/abc/MR_Image.png)') }
|
||||
let(:builder) { described_class.new(mr_with_description) }
|
||||
|
||||
it 'sets the image to use an absolute URL' do
|
||||
expect(data[:description]).to eq("test![Issue_Image](#{Settings.gitlab.url}/uploads/abc/Issue_Image.png)")
|
||||
expected_path = "#{mr_with_description.project.path_with_namespace}/uploads/abc/MR_Image.png"
|
||||
|
||||
expect(data[:description])
|
||||
.to eq("test![MR_Image](#{Settings.gitlab.url}/#{expected_path})")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue