Cache the rendered README, but post-process on show
Because the post-processing of the rendered README is dependent on the context (i.e. the current user), do the post-processing when the README is being displayed.
This commit is contained in:
parent
ef4d4446e9
commit
05e0f50453
11 changed files with 74 additions and 57 deletions
|
@ -60,12 +60,17 @@ module MarkupHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def markdown(text, context = {})
|
def markdown(text, context = {})
|
||||||
|
html = markdown_render(text, context)
|
||||||
|
|
||||||
|
markup_postprocess(html, context)
|
||||||
|
end
|
||||||
|
|
||||||
|
def markdown_render(text, context = {})
|
||||||
return "" unless text.present?
|
return "" unless text.present?
|
||||||
|
|
||||||
context[:project] ||= @project
|
context[:project] ||= @project
|
||||||
|
|
||||||
html = Banzai.render(text, context)
|
Banzai.render(text, context)
|
||||||
banzai_postprocess(html, context)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def markdown_field(object, field)
|
def markdown_field(object, field)
|
||||||
|
@ -76,7 +81,7 @@ module MarkupHelper
|
||||||
banzai_postprocess(html, object.banzai_render_context(field))
|
banzai_postprocess(html, object.banzai_render_context(field))
|
||||||
end
|
end
|
||||||
|
|
||||||
def asciidoc(text)
|
def asciidoc_render(text)
|
||||||
Gitlab::Asciidoc.render(
|
Gitlab::Asciidoc.render(
|
||||||
text,
|
text,
|
||||||
project: @project,
|
project: @project,
|
||||||
|
@ -90,7 +95,7 @@ module MarkupHelper
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def other_markup(file_name, text)
|
def other_markup_render(file_name, text)
|
||||||
Gitlab::OtherMarkup.render(
|
Gitlab::OtherMarkup.render(
|
||||||
file_name,
|
file_name,
|
||||||
text,
|
text,
|
||||||
|
@ -105,6 +110,14 @@ module MarkupHelper
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def markup_postprocess(html, context = {})
|
||||||
|
return "" unless html.present?
|
||||||
|
|
||||||
|
context[:project] ||= @project
|
||||||
|
|
||||||
|
banzai_postprocess(html, context)
|
||||||
|
end
|
||||||
|
|
||||||
# Return the first line of +text+, up to +max_chars+, after parsing the line
|
# Return the first line of +text+, up to +max_chars+, after parsing the line
|
||||||
# as Markdown. HTML tags in the parsed output are not counted toward the
|
# as Markdown. HTML tags in the parsed output are not counted toward the
|
||||||
# +max_chars+ limit. If the length limit falls within a tag's contents, then
|
# +max_chars+ limit. If the length limit falls within a tag's contents, then
|
||||||
|
@ -116,27 +129,34 @@ module MarkupHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_wiki_content(wiki_page)
|
def render_wiki_content(wiki_page)
|
||||||
|
context = { pipeline: :wiki, project_wiki: @project_wiki, page_slug: wiki_page.slug }
|
||||||
case wiki_page.format
|
case wiki_page.format
|
||||||
when :markdown
|
when :markdown
|
||||||
markdown(wiki_page.content, pipeline: :wiki, project_wiki: @project_wiki, page_slug: wiki_page.slug)
|
html = markdown_render(wiki_page.content, context)
|
||||||
when :asciidoc
|
when :asciidoc
|
||||||
asciidoc(wiki_page.content)
|
html = asciidoc_render(wiki_page.content)
|
||||||
else
|
else
|
||||||
wiki_page.formatted_content.html_safe
|
return wiki_page.formatted_content.html_safe
|
||||||
end
|
end
|
||||||
|
markup_postprocess(html, context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_markup(file_name, file_content)
|
def render_markup(file_name, file_content)
|
||||||
|
html = markup_render(file_name, file_content)
|
||||||
|
markup_postprocess(html)
|
||||||
|
end
|
||||||
|
|
||||||
|
def markup_render(file_name, file_content)
|
||||||
if gitlab_markdown?(file_name)
|
if gitlab_markdown?(file_name)
|
||||||
Hamlit::RailsHelpers.preserve(markdown(file_content))
|
Hamlit::RailsHelpers.preserve(markdown_render(file_content))
|
||||||
elsif asciidoc?(file_name)
|
elsif asciidoc?(file_name)
|
||||||
asciidoc(file_content)
|
asciidoc_render(file_content)
|
||||||
elsif plain?(file_name)
|
elsif plain?(file_name)
|
||||||
content_tag :pre, class: 'plain-readme' do
|
content_tag :pre, class: 'plain-readme' do
|
||||||
file_content
|
file_content
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
other_markup(file_name, file_content)
|
other_markup_render(file_name, file_content)
|
||||||
end
|
end
|
||||||
rescue RuntimeError
|
rescue RuntimeError
|
||||||
simple_format(file_content)
|
simple_format(file_content)
|
||||||
|
|
|
@ -12,10 +12,6 @@ module TreeHelper
|
||||||
tree.html_safe
|
tree.html_safe
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_readme(readme)
|
|
||||||
render_markup(readme.name, readme.data)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Return an image icon depending on the file type and mode
|
# Return an image icon depending on the file type and mode
|
||||||
#
|
#
|
||||||
# type - String type of the tree item; either 'folder' or 'file'
|
# type - String type of the tree item; either 'folder' or 'file'
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
require 'securerandom'
|
require 'securerandom'
|
||||||
|
|
||||||
class Repository
|
class Repository
|
||||||
|
include MarkupHelper
|
||||||
include Gitlab::ShellAdapter
|
include Gitlab::ShellAdapter
|
||||||
include RepositoryMirroring
|
include RepositoryMirroring
|
||||||
|
|
||||||
|
@ -17,9 +18,9 @@ class Repository
|
||||||
# same name. The cache key used by those methods must also match method's
|
# same name. The cache key used by those methods must also match method's
|
||||||
# name.
|
# name.
|
||||||
#
|
#
|
||||||
# For example, for entry `:readme` there's a method called `readme` which
|
# For example, for entry `:commit_count` there's a method called `commit_count` which
|
||||||
# stores its data in the `readme` cache key.
|
# stores its data in the `commit_count` cache key.
|
||||||
CACHED_METHODS = %i(size commit_count readme contribution_guide
|
CACHED_METHODS = %i(size commit_count rendered_readme contribution_guide
|
||||||
changelog license_blob license_key gitignore koding_yml
|
changelog license_blob license_key gitignore koding_yml
|
||||||
gitlab_ci_yml branch_names tag_names branch_count
|
gitlab_ci_yml branch_names tag_names branch_count
|
||||||
tag_count avatar exists? empty? root_ref).freeze
|
tag_count avatar exists? empty? root_ref).freeze
|
||||||
|
@ -28,7 +29,7 @@ class Repository
|
||||||
# changed. This Hash maps file types (as returned by Gitlab::FileDetector) to
|
# changed. This Hash maps file types (as returned by Gitlab::FileDetector) to
|
||||||
# the corresponding methods to call for refreshing caches.
|
# the corresponding methods to call for refreshing caches.
|
||||||
METHOD_CACHES_FOR_FILE_TYPES = {
|
METHOD_CACHES_FOR_FILE_TYPES = {
|
||||||
readme: :readme,
|
readme: :rendered_readme,
|
||||||
changelog: :changelog,
|
changelog: :changelog,
|
||||||
license: %i(license_blob license_key),
|
license: %i(license_blob license_key),
|
||||||
contributing: :contribution_guide,
|
contributing: :contribution_guide,
|
||||||
|
@ -527,7 +528,11 @@ class Repository
|
||||||
head.readme
|
head.readme
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
cache_method :readme
|
|
||||||
|
def rendered_readme
|
||||||
|
markup_render(readme.name, readme.data) if readme
|
||||||
|
end
|
||||||
|
cache_method :rendered_readme
|
||||||
|
|
||||||
def contribution_guide
|
def contribution_guide
|
||||||
file_on_head(:contributing)
|
file_on_head(:contributing)
|
||||||
|
|
|
@ -4,8 +4,7 @@
|
||||||
- if can?(current_user, :push_code, @project)
|
- if can?(current_user, :push_code, @project)
|
||||||
= link_to icon('pencil'), namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)), class: 'light edit-project-readme'
|
= link_to icon('pencil'), namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)), class: 'light edit-project-readme'
|
||||||
.file-content.wiki
|
.file-content.wiki
|
||||||
= cache(readme_cache_key) do
|
= markup_postprocess(@repository.rendered_readme)
|
||||||
= render_readme(readme)
|
|
||||||
- else
|
- else
|
||||||
.row-content-block.second-block.center
|
.row-content-block.second-block.center
|
||||||
%h3.page-title
|
%h3.page-title
|
||||||
|
|
|
@ -5,4 +5,4 @@
|
||||||
%strong
|
%strong
|
||||||
= readme.name
|
= readme.name
|
||||||
.file-content.wiki
|
.file-content.wiki
|
||||||
= render_readme(readme)
|
= render_markup(readme.name, readme.data)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: 'Remove view fragment caching for project READMEs'
|
||||||
|
merge_request: 8838
|
||||||
|
author:
|
|
@ -34,8 +34,6 @@ module Gitlab
|
||||||
|
|
||||||
html = ::Asciidoctor.convert(input, asciidoc_opts)
|
html = ::Asciidoctor.convert(input, asciidoc_opts)
|
||||||
|
|
||||||
html = Banzai.post_process(html, context)
|
|
||||||
|
|
||||||
filter = Banzai::Filter::SanitizationFilter.new(html)
|
filter = Banzai::Filter::SanitizationFilter.new(html)
|
||||||
html = filter.call.to_s
|
html = filter.call.to_s
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,6 @@ module Gitlab
|
||||||
html = GitHub::Markup.render(file_name, input).
|
html = GitHub::Markup.render(file_name, input).
|
||||||
force_encoding(input.encoding)
|
force_encoding(input.encoding)
|
||||||
|
|
||||||
html = Banzai.post_process(html, context)
|
|
||||||
|
|
||||||
filter = Banzai::Filter::SanitizationFilter.new(html)
|
filter = Banzai::Filter::SanitizationFilter.new(html)
|
||||||
html = filter.call.to_s
|
html = filter.call.to_s
|
||||||
|
|
||||||
|
|
|
@ -239,33 +239,6 @@ describe ApplicationHelper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'render_markup' do
|
|
||||||
let(:content) { 'Noël' }
|
|
||||||
let(:user) { create(:user) }
|
|
||||||
before do
|
|
||||||
allow(helper).to receive(:current_user).and_return(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'preserves encoding' do
|
|
||||||
expect(content.encoding.name).to eq('UTF-8')
|
|
||||||
expect(helper.render_markup('foo.rst', content).encoding.name).to eq('UTF-8')
|
|
||||||
end
|
|
||||||
|
|
||||||
it "delegates to #markdown when file name corresponds to Markdown" do
|
|
||||||
expect(helper).to receive(:gitlab_markdown?).with('foo.md').and_return(true)
|
|
||||||
expect(helper).to receive(:markdown).and_return('NOEL')
|
|
||||||
|
|
||||||
expect(helper.render_markup('foo.md', content)).to eq('NOEL')
|
|
||||||
end
|
|
||||||
|
|
||||||
it "delegates to #asciidoc when file name corresponds to AsciiDoc" do
|
|
||||||
expect(helper).to receive(:asciidoc?).with('foo.adoc').and_return(true)
|
|
||||||
expect(helper).to receive(:asciidoc).and_return('NOEL')
|
|
||||||
|
|
||||||
expect(helper.render_markup('foo.adoc', content)).to eq('NOEL')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#active_when' do
|
describe '#active_when' do
|
||||||
it { expect(helper.active_when(true)).to eq('active') }
|
it { expect(helper.active_when(true)).to eq('active') }
|
||||||
it { expect(helper.active_when(false)).to eq(nil) }
|
it { expect(helper.active_when(false)).to eq(nil) }
|
||||||
|
|
|
@ -126,15 +126,16 @@ describe MarkupHelper do
|
||||||
it "uses Wiki pipeline for markdown files" do
|
it "uses Wiki pipeline for markdown files" do
|
||||||
allow(@wiki).to receive(:format).and_return(:markdown)
|
allow(@wiki).to receive(:format).and_return(:markdown)
|
||||||
|
|
||||||
expect(helper).to receive(:markdown).with('wiki content', pipeline: :wiki, project_wiki: @wiki, page_slug: "nested/page")
|
expect(helper).to receive(:markdown_render).with('wiki content', pipeline: :wiki, project_wiki: @wiki, page_slug: "nested/page")
|
||||||
|
|
||||||
helper.render_wiki_content(@wiki)
|
helper.render_wiki_content(@wiki)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "uses Asciidoctor for asciidoc files" do
|
it "uses Asciidoctor for asciidoc files" do
|
||||||
|
allow_any_instance_of(ApplicationSetting).to receive(:current).and_return(::ApplicationSetting.create_from_defaults)
|
||||||
allow(@wiki).to receive(:format).and_return(:asciidoc)
|
allow(@wiki).to receive(:format).and_return(:asciidoc)
|
||||||
|
|
||||||
expect(helper).to receive(:asciidoc).with('wiki content')
|
expect(helper).to receive(:asciidoc_render).with('wiki content')
|
||||||
|
|
||||||
helper.render_wiki_content(@wiki)
|
helper.render_wiki_content(@wiki)
|
||||||
end
|
end
|
||||||
|
@ -149,6 +150,29 @@ describe MarkupHelper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'render_markup' do
|
||||||
|
let(:content) { 'Noël' }
|
||||||
|
|
||||||
|
it 'preserves encoding' do
|
||||||
|
expect(content.encoding.name).to eq('UTF-8')
|
||||||
|
expect(helper.render_markup('foo.rst', content).encoding.name).to eq('UTF-8')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "delegates to #markdown_render when file name corresponds to Markdown" do
|
||||||
|
expect(helper).to receive(:gitlab_markdown?).with('foo.md').and_return(true)
|
||||||
|
expect(helper).to receive(:markdown_render).and_return('NOEL')
|
||||||
|
|
||||||
|
expect(helper.render_markup('foo.md', content)).to eq('NOEL')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "delegates to #asciidoc_render when file name corresponds to AsciiDoc" do
|
||||||
|
expect(helper).to receive(:asciidoc?).with('foo.adoc').and_return(true)
|
||||||
|
expect(helper).to receive(:asciidoc_render).and_return('NOEL')
|
||||||
|
|
||||||
|
expect(helper.render_markup('foo.adoc', content)).to eq('NOEL')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#first_line_in_markdown' do
|
describe '#first_line_in_markdown' do
|
||||||
it 'truncates Markdown properly' do
|
it 'truncates Markdown properly' do
|
||||||
text = "@#{user.username}, can you look at this?\nHello world\n"
|
text = "@#{user.username}, can you look at this?\nHello world\n"
|
||||||
|
|
|
@ -1803,9 +1803,9 @@ describe Repository, models: true do
|
||||||
describe '#refresh_method_caches' do
|
describe '#refresh_method_caches' do
|
||||||
it 'refreshes the caches of the given types' do
|
it 'refreshes the caches of the given types' do
|
||||||
expect(repository).to receive(:expire_method_caches).
|
expect(repository).to receive(:expire_method_caches).
|
||||||
with(%i(readme license_blob license_key))
|
with(%i(rendered_readme license_blob license_key))
|
||||||
|
|
||||||
expect(repository).to receive(:readme)
|
expect(repository).to receive(:rendered_readme)
|
||||||
expect(repository).to receive(:license_blob)
|
expect(repository).to receive(:license_blob)
|
||||||
expect(repository).to receive(:license_key)
|
expect(repository).to receive(:license_key)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue