Skip to content
Snippets Groups Projects
Commit 925dc592 authored by Douwe Maan's avatar Douwe Maan
Browse files

Cache rendered contents of issues, MRs and notes

parent 539de0dd
No related branches found
No related tags found
2 merge requests!2051[Second try] Implement different Markdown rendering pipelines and cache Markdown,!1602Implement different Markdown rendering pipelines and cache Markdown
Pipeline #
Loading
@@ -46,7 +46,8 @@ module Issuable
Loading
@@ -46,7 +46,8 @@ module Issuable
allow_nil: true, allow_nil: true,
prefix: true prefix: true
   
attr_mentionable :title, :description attr_mentionable :title
attr_mentionable :description, cache: true
participant :author, :assignee, :notes participant :author, :assignee, :notes
end end
   
Loading
Loading
Loading
@@ -10,8 +10,9 @@ module Mentionable
Loading
@@ -10,8 +10,9 @@ module Mentionable
   
module ClassMethods module ClassMethods
# Indicate which attributes of the Mentionable to search for GFM references. # Indicate which attributes of the Mentionable to search for GFM references.
def attr_mentionable(*attrs) def attr_mentionable(attr, options = {})
mentionable_attrs.concat(attrs.map(&:to_s)) attr = attr.to_s
mentionable_attrs << [attr, options]
end end
   
# Accessor for attributes marked mentionable. # Accessor for attributes marked mentionable.
Loading
@@ -37,11 +38,6 @@ module Mentionable
Loading
@@ -37,11 +38,6 @@ module Mentionable
"#{friendly_name} #{to_reference(from_project)}" "#{friendly_name} #{to_reference(from_project)}"
end end
   
# Construct a String that contains possible GFM references.
def mentionable_text
self.class.mentionable_attrs.map { |attr| send(attr) }.compact.join("\n\n")
end
# The GFM reference to this Mentionable, which shouldn't be included in its #references. # The GFM reference to this Mentionable, which shouldn't be included in its #references.
def local_reference def local_reference
self self
Loading
@@ -54,20 +50,33 @@ module Mentionable
Loading
@@ -54,20 +50,33 @@ module Mentionable
end end
   
def mentioned_users(current_user = nil, load_lazy_references: true) def mentioned_users(current_user = nil, load_lazy_references: true)
return [] if mentionable_text.blank? # TODO: Douwe: Will be simplified when the "Simplify ..." MR is merged.
ext = Gitlab::ReferenceExtractor.new(self.project, current_user, load_lazy_references: load_lazy_references) ext = Gitlab::ReferenceExtractor.new(self.project, current_user, load_lazy_references: load_lazy_references)
ext.analyze(mentionable_text) self.class.mentionable_attrs.each do |attr, options|
ext.users.uniq text = send(attr)
cache_key = [self, attr] if options[:cache]
ext.analyze(text, cache_key: cache_key, pipeline: options[:pipeline])
end
ext.users
end end
   
# Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference. # Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
def references(p = project, current_user = self.author, text = mentionable_text, load_lazy_references: true) def references(p = project, current_user = self.author, text = nil, load_lazy_references: true)
return [] if text.blank? return [] if text.blank?
   
ext = Gitlab::ReferenceExtractor.new(p, current_user, load_lazy_references: load_lazy_references) ext = Gitlab::ReferenceExtractor.new(p, current_user, load_lazy_references: load_lazy_references)
if text
ext.analyze(text) ext.analyze(text)
(ext.issues + ext.merge_requests + ext.commits).uniq - [local_reference] else
self.class.mentionable_attrs.each do |attr, options|
text = send(attr)
cache_key = [self, attr] if options[:cache]
ext.analyze(text, cache_key: cache_key)
end
end
(ext.issues + ext.merge_requests + ext.commits) - [local_reference]
end end
   
# Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+. # Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
Loading
@@ -111,7 +120,7 @@ module Mentionable
Loading
@@ -111,7 +120,7 @@ module Mentionable
def detect_mentionable_changes def detect_mentionable_changes
source = (changes.present? ? changes : previous_changes).dup source = (changes.present? ? changes : previous_changes).dup
   
mentionable = self.class.mentionable_attrs mentionable = self.class.mentionable_attrs.map { |attr, options| attr }
   
# Only include changed fields that are mentionable # Only include changed fields that are mentionable
source.select { |key, val| mentionable.include?(key) } source.select { |key, val| mentionable.include?(key) }
Loading
Loading
Loading
@@ -28,7 +28,7 @@ class Note < ActiveRecord::Base
Loading
@@ -28,7 +28,7 @@ class Note < ActiveRecord::Base
   
default_value_for :system, false default_value_for :system, false
   
attr_mentionable :note attr_mentionable :note, cache: true, pipeline: :note
participant :author participant :author
   
belongs_to :project belongs_to :project
Loading
Loading
Loading
@@ -43,7 +43,7 @@
Loading
@@ -43,7 +43,7 @@
.description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''} .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''}
.wiki .wiki
= preserve do = preserve do
= markdown(@issue.description) = markdown(@issue.description, cache_key: [@issue, "description"])
%textarea.hidden.js-task-list-field %textarea.hidden.js-task-list-field
= @issue.description = @issue.description
   
Loading
Loading
Loading
@@ -7,6 +7,6 @@
Loading
@@ -7,6 +7,6 @@
.description{class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : ''} .description{class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : ''}
.wiki .wiki
= preserve do = preserve do
= markdown(@merge_request.description) = markdown(@merge_request.description, cache_key: [@merge_request, "description"])
%textarea.hidden.js-task-list-field %textarea.hidden.js-task-list-field
= @merge_request.description = @merge_request.description
Loading
@@ -58,7 +58,7 @@
Loading
@@ -58,7 +58,7 @@
.note-body{class: note_editable?(note) ? 'js-task-list-container' : ''} .note-body{class: note_editable?(note) ? 'js-task-list-container' : ''}
.note-text .note-text
= preserve do = preserve do
= markdown(note.note, {no_header_anchors: true}) = markdown(note.note, pipeline: :note, cache_key: [note, "note"])
- unless note.system? - unless note.system?
-# System notes can't be edited -# System notes can't be edited
= render 'projects/notes/edit_form', note: note = render 'projects/notes/edit_form', note: note
Loading
Loading
Loading
@@ -20,6 +20,8 @@ module Gitlab
Loading
@@ -20,6 +20,8 @@ module Gitlab
# #
# Returns an HTML-safe String # Returns an HTML-safe String
def self.render(text, context = {}) def self.render(text, context = {})
context[:pipeline] ||= :full
cache_key = context.delete(:cache_key) cache_key = context.delete(:cache_key)
cache_key = full_cache_key(cache_key, context[:pipeline]) cache_key = full_cache_key(cache_key, context[:pipeline])
   
Loading
@@ -33,7 +35,7 @@ module Gitlab
Loading
@@ -33,7 +35,7 @@ module Gitlab
end end
   
def self.render_result(text, context = {}) def self.render_result(text, context = {})
pipeline = context[:pipeline] || :full pipeline = context[:pipeline] ||= :full
   
html_pipeline = html_pipelines[pipeline] html_pipeline = html_pipelines[pipeline]
   
Loading
@@ -129,6 +131,7 @@ module Gitlab
Loading
@@ -129,6 +131,7 @@ module Gitlab
atom: :full, atom: :full,
email: :full, email: :full,
description: :full, description: :full,
note: :full,
single_line: :gfm, single_line: :gfm,
   
asciidoc: [ asciidoc: [
Loading
@@ -170,6 +173,13 @@ module Gitlab
Loading
@@ -170,6 +173,13 @@ module Gitlab
only_path: false only_path: false
} }
], ],
note: [
:full,
{
# TableOfContentsFilter
no_header_anchors: true
}
],
description: [ description: [
:full, :full,
{ {
Loading
Loading
Loading
@@ -9,13 +9,12 @@ module Gitlab
Loading
@@ -9,13 +9,12 @@ module Gitlab
@project = project @project = project
@current_user = current_user @current_user = current_user
@load_lazy_references = load_lazy_references @load_lazy_references = load_lazy_references
end
   
def analyze(text, cache_key: nil) @texts = []
references.clear end
   
@pipeline = Gitlab::Markdown.cached?(cache_key, pipeline: :full) ? :full : :plain_markdown def analyze(text, options = {})
@html = Gitlab::Markdown.render(text, project: project, cache_key: cache_key, pipeline: @pipeline) @texts << Gitlab::Markdown.render(text, options.merge(project: project))
end end
   
%i(user label issue merge_request snippet commit commit_range).each do |type| %i(user label issue merge_request snippet commit commit_range).each do |type|
Loading
@@ -46,7 +45,7 @@ module Gitlab
Loading
@@ -46,7 +45,7 @@ module Gitlab
filter = Gitlab::Markdown.const_get(klass) filter = Gitlab::Markdown.const_get(klass)
   
context = { context = {
pipeline: [:reference_extraction], pipeline: :reference_extraction,
   
project: project, project: project,
current_user: current_user, current_user: current_user,
Loading
@@ -56,10 +55,11 @@ module Gitlab
Loading
@@ -56,10 +55,11 @@ module Gitlab
reference_filter: filter reference_filter: filter
} }
   
context[:pipeline].unshift(filter) unless @pipeline == :full values = @texts.flat_map do |html|
text_context = context.dup
result = Gitlab::Markdown.render_result(@html, context) result = Gitlab::Markdown.render_result(html, text_context)
values = result[:references][filter_type].uniq result[:references][filter_type]
end.uniq
   
if @load_lazy_references if @load_lazy_references
values = Gitlab::Markdown::ReferenceFilter::LazyReference.load(values).uniq values = Gitlab::Markdown::ReferenceFilter::LazyReference.load(values).uniq
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment