From 7a8a892efdf59925a95cdf6504f7c74c31b87eeb Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 25 Sep 2015 17:12:41 +0200 Subject: Add "rake gitlab:list_repos" task --- lib/tasks/gitlab/list_repos.rake | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 lib/tasks/gitlab/list_repos.rake (limited to 'lib') diff --git a/lib/tasks/gitlab/list_repos.rake b/lib/tasks/gitlab/list_repos.rake new file mode 100644 index 00000000000..1377e1ea910 --- /dev/null +++ b/lib/tasks/gitlab/list_repos.rake @@ -0,0 +1,16 @@ +namespace :gitlab do + task list_repos: :environment do + scope = Project + if ENV['SINCE'] + date = Time.parse(ENV['SINCE']) + warn "Listing repositories with activity since #{date}" + project_ids = Project.where(['last_activity_at > ?', date]).pluck(:id) + scope = scope.where(id: project_ids) + end + scope.find_each do |project| + base = File.join(Gitlab.config.gitlab_shell.repos_path, project.path_with_namespace) + puts base + '.git' + puts base + '.wiki.git' + end + end +end -- cgit v1.2.1 From 54e6c0045bb13c05cc5478cbdf47d3246bd9fe2b Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Tue, 22 Sep 2015 14:04:14 +0200 Subject: Added three rake tasks for repository maintainance Tasks added: gitlab:git:repack gitlab:git:gc gitlab:git:prune --- lib/tasks/gitlab/git.rake | 52 ++++++++++++++++++++++++++++++++++++++ lib/tasks/gitlab/task_helpers.rake | 4 +++ 2 files changed, 56 insertions(+) create mode 100644 lib/tasks/gitlab/git.rake (limited to 'lib') diff --git a/lib/tasks/gitlab/git.rake b/lib/tasks/gitlab/git.rake new file mode 100644 index 00000000000..4fbf5a9393c --- /dev/null +++ b/lib/tasks/gitlab/git.rake @@ -0,0 +1,52 @@ +namespace :gitlab do + namespace :git do + + desc "GitLab | Git | Repack" + task repack: :environment do + failures = perform_git_cmd('git repack -a --quiet', 'Git repack') + if failures.empty? + puts "Done".green + else + output_failures(failures) + end + end + + desc "GitLab | Git | Run gits garbage collection on all repo's" + task gc: :environment do + failures = perform_git_cmd('git gc --auto --quiet', "Garbage Collection") + if failures.empty? + puts "Done".green + else + output_failures(failures) + end + end + + desc "GitLab | Git | Git prune all repo's" + task prune: :environment do + failures = perform_git_cmd('git prune', 'Git Prune') + if failures.empty? + puts "Done".green + else + output_failures(failures) + end + end + + def perform_git_cmd(cmd, message) + puts "Starting #{message} on all repositories" + + failures = [] + all_repos.each do |r| + puts "Performing #{message} at #{r}" + failures << r unless system(*%w(#{cmd}), chdir: r) + end + + failures + end + + def output_failures(failures) + puts "The following repositories reported errors:".red + failures.each { |f| puts "- #{f}" } + end + + end +end diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake index c95b6540ebc..77c41bf61cb 100644 --- a/lib/tasks/gitlab/task_helpers.rake +++ b/lib/tasks/gitlab/task_helpers.rake @@ -128,4 +128,8 @@ namespace :gitlab do false end end + + def all_repos + Dir.glob(File.join(Gitlab.config.gitlab_shell.repos_path, '**/*\.git')) + end end -- cgit v1.2.1 From 8db063b579322238af43f6d04b5968d9c6ea935d Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Thu, 1 Oct 2015 13:34:41 +0200 Subject: Scalable way of requesting all repos --- lib/tasks/gitlab/git.rake | 19 +++++++++++-------- lib/tasks/gitlab/task_helpers.rake | 6 +++++- 2 files changed, 16 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/tasks/gitlab/git.rake b/lib/tasks/gitlab/git.rake index 4fbf5a9393c..65ee430d550 100644 --- a/lib/tasks/gitlab/git.rake +++ b/lib/tasks/gitlab/git.rake @@ -3,7 +3,7 @@ namespace :gitlab do desc "GitLab | Git | Repack" task repack: :environment do - failures = perform_git_cmd('git repack -a --quiet', 'Git repack') + failures = perform_git_cmd(%W(git repack -a --quiet), "Repacking repo") if failures.empty? puts "Done".green else @@ -11,9 +11,9 @@ namespace :gitlab do end end - desc "GitLab | Git | Run gits garbage collection on all repo's" + desc "GitLab | Git | Run garbage collection on all repos" task gc: :environment do - failures = perform_git_cmd('git gc --auto --quiet', "Garbage Collection") + failures = perform_git_cmd(%W(git gc --auto --quiet), "Garbage Collecting") if failures.empty? puts "Done".green else @@ -21,9 +21,9 @@ namespace :gitlab do end end - desc "GitLab | Git | Git prune all repo's" + desc "GitLab | Git | Prune all repos" task prune: :environment do - failures = perform_git_cmd('git prune', 'Git Prune') + failures = perform_git_cmd(%W(git prune), "Git Prune") if failures.empty? puts "Done".green else @@ -35,9 +35,12 @@ namespace :gitlab do puts "Starting #{message} on all repositories" failures = [] - all_repos.each do |r| - puts "Performing #{message} at #{r}" - failures << r unless system(*%w(#{cmd}), chdir: r) + all_repos do |repo| + if system(*cmd, chdir: repo) + puts "Performed #{message} at #{repo}" + else + failures << repo + end end failures diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake index 77c41bf61cb..e35fd47c5c4 100644 --- a/lib/tasks/gitlab/task_helpers.rake +++ b/lib/tasks/gitlab/task_helpers.rake @@ -130,6 +130,10 @@ namespace :gitlab do end def all_repos - Dir.glob(File.join(Gitlab.config.gitlab_shell.repos_path, '**/*\.git')) + IO.popen(%W(find #{Gitlab.config.gitlab_shell.repos_path} -mindepth 2 -maxdepth 2 -type d -name *.git)) do |find| + find.each_line do |path| + yield path.chomp + end + end end end -- cgit v1.2.1 From ed41333a6ecbfcc04781a47a3dc71064c92d837b Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 14 Oct 2015 19:27:23 +0200 Subject: Use Gitlab::Markdown.render with :pipeline option rather than different methods --- lib/gitlab/markdown.rb | 236 +++++++++++++--------------- lib/gitlab/markdown/markdown_filter.rb | 39 +++++ lib/gitlab/markdown/relative_link_filter.rb | 2 +- lib/gitlab/markdown/sanitization_filter.rb | 6 +- lib/gitlab/reference_extractor.rb | 20 ++- 5 files changed, 162 insertions(+), 141 deletions(-) create mode 100644 lib/gitlab/markdown/markdown_filter.rb (limited to 'lib') diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index d5b0060dd56..773ebddba2b 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -19,51 +19,15 @@ module Gitlab # context - Hash of context options passed to our HTML Pipeline # # Returns an HTML-safe String - def self.render(markdown, context = {}) - html = renderer.render(markdown) - html = gfm(html, context) + def self.render(text, context = {}) + pipeline = context[:pipeline] || :full - html.html_safe - end + html_pipeline = html_pipelines[pipeline] - # Convert a Markdown String into HTML without going through the HTML - # Pipeline. - # - # Note that because the pipeline is skipped, SanitizationFilter is as well. - # Do not output the result of this method to the user. - # - # markdown - Markdown String - # - # Returns a String - def self.render_without_gfm(markdown) - renderer.render(markdown) - end + transformers = get_context_transformers(pipeline) + context = transformers.reduce(context) { |context, transformer| transformer.call(context) } - # Perform post-processing on an HTML String - # - # This method is used to perform state-dependent changes to a String of - # HTML, such as removing references that the current user doesn't have - # permission to make (`RedactorFilter`). - # - # html - String to process - # options - Hash of options to customize output - # :pipeline - Symbol pipeline type - # :project - Project - # :user - User object - # - # Returns an HTML-safe String - def self.post_process(html, options) - context = { - project: options[:project], - current_user: options[:user] - } - doc = post_processor.to_document(html, context) - - if options[:pipeline] == :atom - doc.to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML) - else - doc.to_html - end.html_safe + html_pipeline.to_html(text, context) end # Provide autoload paths for filters to prevent a circular dependency error @@ -75,6 +39,7 @@ module Gitlab autoload :ExternalLinkFilter, 'gitlab/markdown/external_link_filter' autoload :IssueReferenceFilter, 'gitlab/markdown/issue_reference_filter' autoload :LabelReferenceFilter, 'gitlab/markdown/label_reference_filter' + autoload :MarkdownFilter, 'gitlab/markdown/markdown_filter' autoload :MergeRequestReferenceFilter, 'gitlab/markdown/merge_request_reference_filter' autoload :RedactorFilter, 'gitlab/markdown/redactor_filter' autoload :RelativeLinkFilter, 'gitlab/markdown/relative_link_filter' @@ -85,98 +50,38 @@ module Gitlab autoload :TaskListFilter, 'gitlab/markdown/task_list_filter' autoload :UserReferenceFilter, 'gitlab/markdown/user_reference_filter' - # Public: Parse the provided HTML with GitLab-Flavored Markdown + # Perform post-processing on an HTML String + # + # This method is used to perform state-dependent changes to a String of + # HTML, such as removing references that the current user doesn't have + # permission to make (`RedactorFilter`). # - # html - HTML String - # options - A Hash of options used to customize output (default: {}) - # :no_header_anchors - Disable header anchors in TableOfContentsFilter - # :path - Current path String - # :pipeline - Symbol pipeline type - # :project - Current Project object - # :project_wiki - Current ProjectWiki object - # :ref - Current ref String + # html - String to process + # context - Hash of options to customize output + # :pipeline - Symbol pipeline type + # :project - Project + # :user - User object # # Returns an HTML-safe String - def self.gfm(html, options = {}) - return '' unless html.present? - - @pipeline ||= HTML::Pipeline.new(filters) - - context = { - # SanitizationFilter - pipeline: options[:pipeline], - - # EmojiFilter - asset_host: Gitlab::Application.config.asset_host, - asset_root: Gitlab.config.gitlab.base_url, - - # ReferenceFilter - only_path: only_path_pipeline?(options[:pipeline]), - project: options[:project], - - # RelativeLinkFilter - project_wiki: options[:project_wiki], - ref: options[:ref], - requested_path: options[:path], - - # TableOfContentsFilter - no_header_anchors: options[:no_header_anchors] - } + def self.post_process(html, context) + doc = html_pipelines[:post_process].to_document(html, context) - @pipeline.to_html(html, context).html_safe - end - - private - - # Check if a pipeline enables the `only_path` context option - # - # Returns Boolean - def self.only_path_pipeline?(pipeline) - case pipeline - when :atom, :email - false + if context[:xhtml] + doc.to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML) else - true - end - end - - def self.redcarpet_options - # https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use - @redcarpet_options ||= { - fenced_code_blocks: true, - footnotes: true, - lax_spacing: true, - no_intra_emphasis: true, - space_after_headers: true, - strikethrough: true, - superscript: true, - tables: true - }.freeze - end - - def self.renderer - @markdown ||= begin - renderer = Redcarpet::Render::HTML.new - Redcarpet::Markdown.new(renderer, redcarpet_options) - end - end - - def self.post_processor - @post_processor ||= HTML::Pipeline.new([Gitlab::Markdown::RedactorFilter]) + doc.to_html + end.html_safe end - # Filters used in our pipeline - # - # SanitizationFilter should come first so that all generated reference HTML - # goes through untouched. - # - # See https://github.com/jch/html-pipeline#filters for more filters. - def self.filters - [ + private + FILTERS = { + plain_markdown: [ + Gitlab::Markdown::MarkdownFilter + ], + gfm: [ Gitlab::Markdown::SyntaxHighlightFilter, Gitlab::Markdown::SanitizationFilter, - Gitlab::Markdown::RelativeLinkFilter, Gitlab::Markdown::EmojiFilter, Gitlab::Markdown::TableOfContentsFilter, Gitlab::Markdown::AutolinkFilter, @@ -192,7 +97,90 @@ module Gitlab Gitlab::Markdown::LabelReferenceFilter, Gitlab::Markdown::TaskListFilter + ], + + full: [:plain_markdown, :gfm], + atom: :full, + email: :full, + description: :full, + single_line: :gfm, + + post_process: [ + Gitlab::Markdown::RelativeLinkFilter, + Gitlab::Markdown::RedactorFilter ] + } + + CONTEXT_TRANSFORMERS = { + gfm: { + only_path: true, + + # EmojiFilter + asset_host: Gitlab::Application.config.asset_host, + asset_root: Gitlab.config.gitlab.base_url + }, + full: :gfm, + + atom: [ + :full, + { + only_path: false, + xhtml: true + } + ], + email: [ + :full, + { + only_path: false + } + ], + description: [ + :full, + { + # SanitizationFilter + inline_sanitization: true + } + ], + single_line: :gfm, + + post_process: { + post_process: true + } + } + + def self.html_pipelines + @html_pipelines ||= Hash.new do |hash, pipeline| + filters = get_filters(pipeline) + HTML::Pipeline.new(filters) + end + end + + def self.get_filters(pipelines) + Array.wrap(pipelines).flat_map do |pipeline| + case pipeline + when Class + pipeline + when Symbol + get_filters(FILTERS[pipeline]) + when Array + get_filters(pipeline) + end + end.compact + end + + def self.get_context_transformers(pipelines) + Array.wrap(pipelines).flat_map do |pipeline| + case pipeline + when Hash + ->(context) { context.merge(pipeline) } + when Proc + pipeline + when Symbol + get_context_transformers(CONTEXT_TRANSFORMERS[pipeline]) + when Array + get_context_transformers(pipeline) + end + end.compact end end end diff --git a/lib/gitlab/markdown/markdown_filter.rb b/lib/gitlab/markdown/markdown_filter.rb new file mode 100644 index 00000000000..921e2a0794e --- /dev/null +++ b/lib/gitlab/markdown/markdown_filter.rb @@ -0,0 +1,39 @@ +module Gitlab + module Markdown + class MarkdownFilter < HTML::Pipeline::TextFilter + def initialize(text, context = nil, result = nil) + super text, context, result + @text = @text.gsub "\r", '' + end + + def call + html = self.class.renderer.render(@text) + html.rstrip! + html + end + + private + + def self.redcarpet_options + # https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use + @redcarpet_options ||= { + fenced_code_blocks: true, + footnotes: true, + lax_spacing: true, + no_intra_emphasis: true, + space_after_headers: true, + strikethrough: true, + superscript: true, + tables: true + }.freeze + end + + def self.renderer + @renderer ||= begin + renderer = Redcarpet::Render::HTML.new + Redcarpet::Markdown.new(renderer, redcarpet_options) + end + end + end + end +end diff --git a/lib/gitlab/markdown/relative_link_filter.rb b/lib/gitlab/markdown/relative_link_filter.rb index 6ee3d1ce039..3e9909d2f33 100644 --- a/lib/gitlab/markdown/relative_link_filter.rb +++ b/lib/gitlab/markdown/relative_link_filter.rb @@ -16,7 +16,7 @@ module Gitlab def call return doc unless linkable_files? - doc.search('a').each do |el| + doc.search('a:not(.gfm)').each do |el| process_link_attr el.attribute('href') end diff --git a/lib/gitlab/markdown/sanitization_filter.rb b/lib/gitlab/markdown/sanitization_filter.rb index e368de7d848..550dfafca85 100644 --- a/lib/gitlab/markdown/sanitization_filter.rb +++ b/lib/gitlab/markdown/sanitization_filter.rb @@ -11,7 +11,7 @@ module Gitlab def whitelist # Descriptions are more heavily sanitized, allowing only a few elements. # See http://git.io/vkuAN - if pipeline == :description + if context[:inline_sanitization] whitelist = LIMITED whitelist[:elements] -= %w(pre code img ol ul li) else @@ -25,10 +25,6 @@ module Gitlab private - def pipeline - context[:pipeline] || :default - end - def customized?(transformers) transformers.last.source_location[0] == __FILE__ end diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index 66016ecc877..633c988d025 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -13,7 +13,8 @@ module Gitlab def analyze(text) references.clear - @text = Gitlab::Markdown.render_without_gfm(text) + + @document = Gitlab::Markdown.render(text, project: project) end %i(user label issue merge_request snippet commit commit_range).each do |type| @@ -44,20 +45,13 @@ module Gitlab filter = Gitlab::Markdown.const_get(klass) context = { - project: project, - current_user: current_user, - - # We don't actually care about the links generated - only_path: true, - ignore_blockquotes: true, - - # ReferenceGathererFilter + project: project, + current_user: current_user, load_lazy_references: false, reference_filter: filter } - pipeline = HTML::Pipeline.new([filter, Gitlab::Markdown::ReferenceGathererFilter], context) - result = pipeline.call(@text) + result = self.class.pipeline.call(@document, context) values = result[:references][filter_type].uniq @@ -67,5 +61,9 @@ module Gitlab values end + + def self.pipeline + @pipeline ||= HTML::Pipeline.new([Gitlab::Markdown::ReferenceGathererFilter]) + end end end -- cgit v1.2.1 From da9746e59a46005a0948d34bfd94ae715143c3f7 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 14 Oct 2015 19:28:46 +0200 Subject: Enable caching of Gitlab::Markdown rendered result --- lib/gitlab/markdown.rb | 35 +++++++++++++++++++++++++---------- lib/gitlab/reference_extractor.rb | 4 ++-- 2 files changed, 27 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 773ebddba2b..21416f0fa02 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -20,14 +20,16 @@ module Gitlab # # Returns an HTML-safe String def self.render(text, context = {}) - pipeline = context[:pipeline] || :full - - html_pipeline = html_pipelines[pipeline] - - transformers = get_context_transformers(pipeline) - context = transformers.reduce(context) { |context, transformer| transformer.call(context) } + cache_key = context.delete(:cache_key) - html_pipeline.to_html(text, context) + if cache_key + cache_key = full_cache_key(cache_key, context[:pipeline]) + Rails.cache.fetch(cache_key) do + cacheless_render(text, context) + end + else + cacheless_render(text, context) + end end # Provide autoload paths for filters to prevent a circular dependency error @@ -130,9 +132,7 @@ module Gitlab ], email: [ :full, - { - only_path: false - } + { only_path: false } ], description: [ :full, @@ -155,6 +155,17 @@ module Gitlab end end + def self.cacheless_render(text, context = {}) + pipeline = context[:pipeline] || :full + + html_pipeline = html_pipelines[pipeline] + + transformers = get_context_transformers(pipeline) + context = transformers.reduce(context) { |context, transformer| transformer.call(context) } + + html_pipeline.to_html(text, context) + end + def self.get_filters(pipelines) Array.wrap(pipelines).flat_map do |pipeline| case pipeline @@ -182,5 +193,9 @@ module Gitlab end end.compact end + + def self.full_cache_key(cache_key, pipeline = :full) + ["markdown", *cache_key, pipeline] + end end end diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index 633c988d025..2262e5a168a 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -11,10 +11,10 @@ module Gitlab @load_lazy_references = load_lazy_references end - def analyze(text) + def analyze(text, cache_key: nil) references.clear - @document = Gitlab::Markdown.render(text, project: project) + @document = Gitlab::Markdown.render(text, project: project, cache_key: cache_key) end %i(user label issue merge_request snippet commit commit_range).each do |type| -- cgit v1.2.1 From b093cb35d1614a48e980c5ccfca3a8d307d732f7 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 14 Oct 2015 20:18:49 +0200 Subject: Use Gitlab::Markdown for Asciidoc and ReferenceExtractor pipelines --- lib/gitlab/asciidoc.rb | 27 +---- lib/gitlab/markdown.rb | 226 +++++++++++++++++++++++--------------- lib/gitlab/reference_extractor.rb | 18 +-- 3 files changed, 154 insertions(+), 117 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/asciidoc.rb b/lib/gitlab/asciidoc.rb index bf33e5b1b1e..330d3342dd1 100644 --- a/lib/gitlab/asciidoc.rb +++ b/lib/gitlab/asciidoc.rb @@ -1,14 +1,10 @@ require 'asciidoctor' -require 'html/pipeline' module Gitlab # Parser/renderer for the AsciiDoc format that uses Asciidoctor and filters # the resulting HTML through HTML pipeline filters. module Asciidoc - # Provide autoload paths for filters to prevent a circular dependency error - autoload :RelativeLinkFilter, 'gitlab/markdown/relative_link_filter' - DEFAULT_ADOC_ATTRS = [ 'showtitle', 'idprefix=user-content-', 'idseparator=-', 'env=gitlab', 'env-gitlab', 'source-highlighter=html-pipeline' @@ -24,13 +20,11 @@ module Gitlab # :requested_path # :ref # asciidoc_opts - a Hash of options to pass to the Asciidoctor converter - # html_opts - a Hash of options for HTML output: - # :xhtml - output XHTML instead of HTML # - def self.render(input, context, asciidoc_opts = {}, html_opts = {}) - asciidoc_opts = asciidoc_opts.reverse_merge( + def self.render(input, context, asciidoc_opts = {}) + asciidoc_opts.reverse_merge!( safe: :secure, - backend: html_opts[:xhtml] ? :xhtml5 : :html5, + backend: :html5, attributes: [] ) asciidoc_opts[:attributes].unshift(*DEFAULT_ADOC_ATTRS) @@ -38,23 +32,10 @@ module Gitlab html = ::Asciidoctor.convert(input, asciidoc_opts) if context[:project] - result = HTML::Pipeline.new(filters).call(html, context) - - save_opts = html_opts[:xhtml] ? - Nokogiri::XML::Node::SaveOptions::AS_XHTML : 0 - - html = result[:output].to_html(save_with: save_opts) + html = Gitlab::Markdown.render(html, context.merge(pipeline: :asciidoc)) end html.html_safe end - - private - - def self.filters - [ - Gitlab::Markdown::RelativeLinkFilter - ] - end end end diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 21416f0fa02..dc6751fa1c2 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -21,9 +21,9 @@ module Gitlab # Returns an HTML-safe String def self.render(text, context = {}) cache_key = context.delete(:cache_key) + cache_key = full_cache_key(cache_key, context[:pipeline]) if cache_key - cache_key = full_cache_key(cache_key, context[:pipeline]) Rails.cache.fetch(cache_key) do cacheless_render(text, context) end @@ -32,25 +32,21 @@ module Gitlab end end - # Provide autoload paths for filters to prevent a circular dependency error - autoload :AutolinkFilter, 'gitlab/markdown/autolink_filter' - autoload :CommitRangeReferenceFilter, 'gitlab/markdown/commit_range_reference_filter' - autoload :CommitReferenceFilter, 'gitlab/markdown/commit_reference_filter' - autoload :EmojiFilter, 'gitlab/markdown/emoji_filter' - autoload :ExternalIssueReferenceFilter, 'gitlab/markdown/external_issue_reference_filter' - autoload :ExternalLinkFilter, 'gitlab/markdown/external_link_filter' - autoload :IssueReferenceFilter, 'gitlab/markdown/issue_reference_filter' - autoload :LabelReferenceFilter, 'gitlab/markdown/label_reference_filter' - autoload :MarkdownFilter, 'gitlab/markdown/markdown_filter' - autoload :MergeRequestReferenceFilter, 'gitlab/markdown/merge_request_reference_filter' - autoload :RedactorFilter, 'gitlab/markdown/redactor_filter' - autoload :RelativeLinkFilter, 'gitlab/markdown/relative_link_filter' - autoload :SanitizationFilter, 'gitlab/markdown/sanitization_filter' - autoload :SnippetReferenceFilter, 'gitlab/markdown/snippet_reference_filter' - autoload :SyntaxHighlightFilter, 'gitlab/markdown/syntax_highlight_filter' - autoload :TableOfContentsFilter, 'gitlab/markdown/table_of_contents_filter' - autoload :TaskListFilter, 'gitlab/markdown/task_list_filter' - autoload :UserReferenceFilter, 'gitlab/markdown/user_reference_filter' + def self.render_result(text, context = {}) + pipeline = context[:pipeline] || :full + + html_pipeline = html_pipelines[pipeline] + + transformers = context_transformers[pipeline] + context = transformers.reduce(context) { |context, transformer| transformer.call(context) } + + html_pipeline.call(text, context) + end + + def self.cached?(cache_key, pipeline: :full) + cache_key = full_cache_key(cache_key, pipeline) + cache_key ? Rails.cache.exist?(cache_key) : false + end # Perform post-processing on an HTML String # @@ -66,21 +62,39 @@ module Gitlab # # Returns an HTML-safe String def self.post_process(html, context) - doc = html_pipelines[:post_process].to_document(html, context) + html_pipeline = html_pipelines[:post_process] if context[:xhtml] - doc.to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML) + html_pipeline.to_document(html, context).to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML) else - doc.to_html + html_pipeline.to_html(html, context) end.html_safe end private - FILTERS = { - plain_markdown: [ - Gitlab::Markdown::MarkdownFilter - ], - gfm: [ + + # Provide autoload paths for filters to prevent a circular dependency error + autoload :AutolinkFilter, 'gitlab/markdown/autolink_filter' + autoload :CommitRangeReferenceFilter, 'gitlab/markdown/commit_range_reference_filter' + autoload :CommitReferenceFilter, 'gitlab/markdown/commit_reference_filter' + autoload :EmojiFilter, 'gitlab/markdown/emoji_filter' + autoload :ExternalIssueReferenceFilter, 'gitlab/markdown/external_issue_reference_filter' + autoload :ExternalLinkFilter, 'gitlab/markdown/external_link_filter' + autoload :IssueReferenceFilter, 'gitlab/markdown/issue_reference_filter' + autoload :LabelReferenceFilter, 'gitlab/markdown/label_reference_filter' + autoload :MarkdownFilter, 'gitlab/markdown/markdown_filter' + autoload :MergeRequestReferenceFilter, 'gitlab/markdown/merge_request_reference_filter' + autoload :RedactorFilter, 'gitlab/markdown/redactor_filter' + autoload :RelativeLinkFilter, 'gitlab/markdown/relative_link_filter' + autoload :SanitizationFilter, 'gitlab/markdown/sanitization_filter' + autoload :SnippetReferenceFilter, 'gitlab/markdown/snippet_reference_filter' + autoload :SyntaxHighlightFilter, 'gitlab/markdown/syntax_highlight_filter' + autoload :TableOfContentsFilter, 'gitlab/markdown/table_of_contents_filter' + autoload :TaskListFilter, 'gitlab/markdown/task_list_filter' + autoload :UserReferenceFilter, 'gitlab/markdown/user_reference_filter' + + def self.gfm_filters + @gfm_filters ||= [ Gitlab::Markdown::SyntaxHighlightFilter, Gitlab::Markdown::SanitizationFilter, @@ -99,71 +113,99 @@ module Gitlab Gitlab::Markdown::LabelReferenceFilter, Gitlab::Markdown::TaskListFilter - ], + ] + end - full: [:plain_markdown, :gfm], - atom: :full, - email: :full, - description: :full, - single_line: :gfm, + def self.all_filters + @all_filters ||= { + plain_markdown: [ + Gitlab::Markdown::MarkdownFilter + ], + gfm: gfm_filters, + + full: [:plain_markdown, :gfm], + atom: :full, + email: :full, + description: :full, + single_line: :gfm, + + asciidoc: [ + Gitlab::Markdown::RelativeLinkFilter + ], + + post_process: [ + Gitlab::Markdown::RelativeLinkFilter, + Gitlab::Markdown::RedactorFilter + ], + + reference_extraction: [ + Gitlab::Markdown::ReferenceGathererFilter + ] + } + end - post_process: [ - Gitlab::Markdown::RelativeLinkFilter, - Gitlab::Markdown::RedactorFilter - ] - } - - CONTEXT_TRANSFORMERS = { - gfm: { - only_path: true, - - # EmojiFilter - asset_host: Gitlab::Application.config.asset_host, - asset_root: Gitlab.config.gitlab.base_url - }, - full: :gfm, - - atom: [ - :full, - { - only_path: false, - xhtml: true - } - ], - email: [ - :full, - { only_path: false } - ], - description: [ - :full, - { - # SanitizationFilter - inline_sanitization: true + def self.all_context_transformers + @all_context_transformers ||= { + gfm: { + only_path: true, + + # EmojiFilter + asset_host: Gitlab::Application.config.asset_host, + asset_root: Gitlab.config.gitlab.base_url + }, + full: :gfm, + + atom: [ + :full, + { + only_path: false, + xhtml: true + } + ], + email: [ + :full, + { + only_path: false + } + ], + description: [ + :full, + { + # SanitizationFilter + inline_sanitization: true + } + ], + single_line: :gfm, + + post_process: { + post_process: true } - ], - single_line: :gfm, - - post_process: { - post_process: true } - } + end + + def self.html_filters + @html_filters ||= Hash.new do |hash, pipeline| + filters = get_filters(pipeline) + hash[pipeline] = filters if pipeline.is_a?(Symbol) + filters + end + end def self.html_pipelines @html_pipelines ||= Hash.new do |hash, pipeline| filters = get_filters(pipeline) - HTML::Pipeline.new(filters) + html_pipeline = HTML::Pipeline.new(filters) + hash[pipeline] = html_pipeline if pipeline.is_a?(Symbol) + html_pipeline end end - def self.cacheless_render(text, context = {}) - pipeline = context[:pipeline] || :full - - html_pipeline = html_pipelines[pipeline] - - transformers = get_context_transformers(pipeline) - context = transformers.reduce(context) { |context, transformer| transformer.call(context) } - - html_pipeline.to_html(text, context) + def self.context_transformers + @context_transformers ||= Hash.new do |hash, pipeline| + transformers = get_context_transformers(pipeline) + hash[pipeline] = transformers if pipeline.is_a?(Symbol) + transformers + end end def self.get_filters(pipelines) @@ -172,9 +214,9 @@ module Gitlab when Class pipeline when Symbol - get_filters(FILTERS[pipeline]) + html_filters[all_filters[pipeline]] when Array - get_filters(pipeline) + html_filters[pipeline] end end.compact end @@ -187,14 +229,26 @@ module Gitlab when Proc pipeline when Symbol - get_context_transformers(CONTEXT_TRANSFORMERS[pipeline]) + context_transformers[all_context_transformers[pipeline]] when Array - get_context_transformers(pipeline) + context_transformers[pipeline] end end.compact end + def self.cacheless_render(text, context = {}) + result = render_result(text, context) + output = result[:output] + if output.respond_to?(:to_html) + output.to_html + else + output.to_s + end + end + def self.full_cache_key(cache_key, pipeline = :full) + return unless cache_key && pipeline.is_a?(Symbol) + ["markdown", *cache_key, pipeline] end end diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index 2262e5a168a..f34bf7d1d0e 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -14,7 +14,8 @@ module Gitlab def analyze(text, cache_key: nil) references.clear - @document = Gitlab::Markdown.render(text, project: project, cache_key: cache_key) + @pipeline = Gitlab::Markdown.cached?(cache_key, pipeline: :full) ? :full : :plain_markdown + @html = Gitlab::Markdown.render(text, project: project, cache_key: cache_key, pipeline: @pipeline) end %i(user label issue merge_request snippet commit commit_range).each do |type| @@ -45,14 +46,19 @@ module Gitlab filter = Gitlab::Markdown.const_get(klass) context = { - project: project, - current_user: current_user, + pipeline: [:reference_extraction], + + project: project, + current_user: current_user, + + # ReferenceGathererFilter load_lazy_references: false, reference_filter: filter } - result = self.class.pipeline.call(@document, context) + context[:pipeline].unshift(filter) unless @pipeline == :full + result = Gitlab::Markdown.render_result(@html, context) values = result[:references][filter_type].uniq if @load_lazy_references @@ -61,9 +67,5 @@ module Gitlab values end - - def self.pipeline - @pipeline ||= HTML::Pipeline.new([Gitlab::Markdown::ReferenceGathererFilter]) - end end end -- cgit v1.2.1 From 925dc5925b672718ea1f0f08c5bdd492b5ab3e5d Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 14 Oct 2015 21:29:35 +0200 Subject: Cache rendered contents of issues, MRs and notes --- lib/gitlab/markdown.rb | 12 +++++++++++- lib/gitlab/reference_extractor.rb | 20 ++++++++++---------- 2 files changed, 21 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index d1f22070cba..b9615f95012 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -20,6 +20,8 @@ module Gitlab # # Returns an HTML-safe String def self.render(text, context = {}) + context[:pipeline] ||= :full + cache_key = context.delete(:cache_key) cache_key = full_cache_key(cache_key, context[:pipeline]) @@ -33,7 +35,7 @@ module Gitlab end def self.render_result(text, context = {}) - pipeline = context[:pipeline] || :full + pipeline = context[:pipeline] ||= :full html_pipeline = html_pipelines[pipeline] @@ -129,6 +131,7 @@ module Gitlab atom: :full, email: :full, description: :full, + note: :full, single_line: :gfm, asciidoc: [ @@ -170,6 +173,13 @@ module Gitlab only_path: false } ], + note: [ + :full, + { + # TableOfContentsFilter + no_header_anchors: true + } + ], description: [ :full, { diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index f34bf7d1d0e..37141efb4c3 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -9,13 +9,12 @@ module Gitlab @project = project @current_user = current_user @load_lazy_references = load_lazy_references - end - def analyze(text, cache_key: nil) - references.clear + @texts = [] + end - @pipeline = Gitlab::Markdown.cached?(cache_key, pipeline: :full) ? :full : :plain_markdown - @html = Gitlab::Markdown.render(text, project: project, cache_key: cache_key, pipeline: @pipeline) + def analyze(text, options = {}) + @texts << Gitlab::Markdown.render(text, options.merge(project: project)) end %i(user label issue merge_request snippet commit commit_range).each do |type| @@ -46,7 +45,7 @@ module Gitlab filter = Gitlab::Markdown.const_get(klass) context = { - pipeline: [:reference_extraction], + pipeline: :reference_extraction, project: project, current_user: current_user, @@ -56,10 +55,11 @@ module Gitlab reference_filter: filter } - context[:pipeline].unshift(filter) unless @pipeline == :full - - result = Gitlab::Markdown.render_result(@html, context) - values = result[:references][filter_type].uniq + values = @texts.flat_map do |html| + text_context = context.dup + result = Gitlab::Markdown.render_result(html, text_context) + result[:references][filter_type] + end.uniq if @load_lazy_references values = Gitlab::Markdown::ReferenceFilter::LazyReference.load(values).uniq -- cgit v1.2.1 From 528d2823e9888ae09aa03b72c2e61cd0b9a39937 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 14 Oct 2015 21:52:41 +0200 Subject: Remove unused Gitlab::Markdown#cached? method --- lib/gitlab/markdown.rb | 5 ----- 1 file changed, 5 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index b9615f95012..5c4481e6497 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -45,11 +45,6 @@ module Gitlab html_pipeline.call(text, context) end - def self.cached?(cache_key, pipeline: :full) - cache_key = full_cache_key(cache_key, pipeline) - cache_key ? Rails.cache.exist?(cache_key) : false - end - # Perform post-processing on an HTML String # # This method is used to perform state-dependent changes to a String of -- cgit v1.2.1 From abbca6151d66ebc227c883af35cd01cf4d7e24eb Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 21 Oct 2015 12:18:23 +0200 Subject: Make pipelines actually make sense --- lib/gitlab/markdown.rb | 216 ++++----------------- lib/gitlab/markdown/asciidoc_pipeline.rb | 13 ++ lib/gitlab/markdown/atom_pipeline.rb | 14 ++ lib/gitlab/markdown/combined_pipeline.rb | 25 +++ lib/gitlab/markdown/description_pipeline.rb | 14 ++ lib/gitlab/markdown/email_pipeline.rb | 13 ++ lib/gitlab/markdown/full_pipeline.rb | 9 + lib/gitlab/markdown/gfm_pipeline.rb | 41 ++++ lib/gitlab/markdown/note_pipeline.rb | 14 ++ lib/gitlab/markdown/pipeline.rb | 29 +++ lib/gitlab/markdown/plain_markdown_pipeline.rb | 13 ++ lib/gitlab/markdown/post_process_pipeline.rb | 20 ++ .../markdown/reference_extraction_pipeline.rb | 13 ++ lib/gitlab/markdown/single_line_pipeline.rb | 9 + 14 files changed, 265 insertions(+), 178 deletions(-) create mode 100644 lib/gitlab/markdown/asciidoc_pipeline.rb create mode 100644 lib/gitlab/markdown/atom_pipeline.rb create mode 100644 lib/gitlab/markdown/combined_pipeline.rb create mode 100644 lib/gitlab/markdown/description_pipeline.rb create mode 100644 lib/gitlab/markdown/email_pipeline.rb create mode 100644 lib/gitlab/markdown/full_pipeline.rb create mode 100644 lib/gitlab/markdown/gfm_pipeline.rb create mode 100644 lib/gitlab/markdown/note_pipeline.rb create mode 100644 lib/gitlab/markdown/pipeline.rb create mode 100644 lib/gitlab/markdown/plain_markdown_pipeline.rb create mode 100644 lib/gitlab/markdown/post_process_pipeline.rb create mode 100644 lib/gitlab/markdown/reference_extraction_pipeline.rb create mode 100644 lib/gitlab/markdown/single_line_pipeline.rb (limited to 'lib') diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 5c4481e6497..3ae4ccfacb6 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -35,14 +35,8 @@ module Gitlab end def self.render_result(text, context = {}) - pipeline = context[:pipeline] ||= :full - - html_pipeline = html_pipelines[pipeline] - - transformers = context_transformers[pipeline] - context = transformers.reduce(context) { |context, transformer| transformer.call(context) } - - html_pipeline.call(text, context) + pipeline_type = context[:pipeline] ||= :full + pipeline_by_type(pipeline_type).call(text, context) end # Perform post-processing on an HTML String @@ -59,17 +53,37 @@ module Gitlab # # Returns an HTML-safe String def self.post_process(html, context) - html_pipeline = html_pipelines[:post_process] + pipeline = pipeline_by_type(:post_process) if context[:xhtml] - html_pipeline.to_document(html, context).to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML) + pipeline.to_document(html, context).to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML) else - html_pipeline.to_html(html, context) + pipeline.to_html(html, context) end.html_safe end private + def self.cacheless_render(text, context = {}) + result = render_result(text, context) + output = result[:output] + if output.respond_to?(:to_html) + output.to_html + else + output.to_s + end + end + + def self.full_cache_key(cache_key, pipeline = :full) + return unless cache_key + + ["markdown", *cache_key, pipeline] + end + + def self.pipeline_by_type(pipeline_type) + const_get("#{pipeline_type.to_s.camelize}Pipeline") + end + # Provide autoload paths for filters to prevent a circular dependency error autoload :AutolinkFilter, 'gitlab/markdown/autolink_filter' autoload :CommitRangeReferenceFilter, 'gitlab/markdown/commit_range_reference_filter' @@ -91,172 +105,18 @@ module Gitlab autoload :UserReferenceFilter, 'gitlab/markdown/user_reference_filter' autoload :UploadLinkFilter, 'gitlab/markdown/upload_link_filter' - def self.gfm_filters - @gfm_filters ||= [ - Gitlab::Markdown::SyntaxHighlightFilter, - Gitlab::Markdown::SanitizationFilter, - - Gitlab::Markdown::UploadLinkFilter, - Gitlab::Markdown::EmojiFilter, - Gitlab::Markdown::TableOfContentsFilter, - Gitlab::Markdown::AutolinkFilter, - Gitlab::Markdown::ExternalLinkFilter, - - Gitlab::Markdown::UserReferenceFilter, - Gitlab::Markdown::IssueReferenceFilter, - Gitlab::Markdown::ExternalIssueReferenceFilter, - Gitlab::Markdown::MergeRequestReferenceFilter, - Gitlab::Markdown::SnippetReferenceFilter, - Gitlab::Markdown::CommitRangeReferenceFilter, - Gitlab::Markdown::CommitReferenceFilter, - Gitlab::Markdown::LabelReferenceFilter, - - Gitlab::Markdown::TaskListFilter - ] - end - - def self.all_filters - @all_filters ||= { - plain_markdown: [ - Gitlab::Markdown::MarkdownFilter - ], - gfm: gfm_filters, - - full: [:plain_markdown, :gfm], - atom: :full, - email: :full, - description: :full, - note: :full, - single_line: :gfm, - - asciidoc: [ - Gitlab::Markdown::RelativeLinkFilter - ], - - post_process: [ - Gitlab::Markdown::RelativeLinkFilter, - Gitlab::Markdown::RedactorFilter - ], - - reference_extraction: [ - Gitlab::Markdown::ReferenceGathererFilter - ] - } - end - - def self.all_context_transformers - @all_context_transformers ||= { - gfm: { - only_path: true, - - # EmojiFilter - asset_host: Gitlab::Application.config.asset_host, - asset_root: Gitlab.config.gitlab.base_url - }, - full: :gfm, - - atom: [ - :full, - { - only_path: false, - xhtml: true - } - ], - email: [ - :full, - { - only_path: false - } - ], - note: [ - :full, - { - # TableOfContentsFilter - no_header_anchors: true - } - ], - description: [ - :full, - { - # SanitizationFilter - inline_sanitization: true - } - ], - single_line: :gfm, - - post_process: { - post_process: true - } - } - end - - def self.html_filters - @html_filters ||= Hash.new do |hash, pipeline| - filters = get_filters(pipeline) - hash[pipeline] = filters if pipeline.is_a?(Symbol) - filters - end - end - - def self.html_pipelines - @html_pipelines ||= Hash.new do |hash, pipeline| - filters = get_filters(pipeline) - html_pipeline = HTML::Pipeline.new(filters) - hash[pipeline] = html_pipeline if pipeline.is_a?(Symbol) - html_pipeline - end - end - - def self.context_transformers - @context_transformers ||= Hash.new do |hash, pipeline| - transformers = get_context_transformers(pipeline) - hash[pipeline] = transformers if pipeline.is_a?(Symbol) - transformers - end - end - - def self.get_filters(pipelines) - Array.wrap(pipelines).flat_map do |pipeline| - case pipeline - when Class - pipeline - when Symbol - html_filters[all_filters[pipeline]] - when Array - html_filters[pipeline] - end - end.compact - end - - def self.get_context_transformers(pipelines) - Array.wrap(pipelines).flat_map do |pipeline| - case pipeline - when Hash - ->(context) { context.merge(pipeline) } - when Proc - pipeline - when Symbol - context_transformers[all_context_transformers[pipeline]] - when Array - context_transformers[pipeline] - end - end.compact - end - - def self.cacheless_render(text, context = {}) - result = render_result(text, context) - output = result[:output] - if output.respond_to?(:to_html) - output.to_html - else - output.to_s - end - end - - def self.full_cache_key(cache_key, pipeline = :full) - return unless cache_key && pipeline.is_a?(Symbol) - - ["markdown", *cache_key, pipeline] - end + autoload :AsciidocPipeline, 'gitlab/markdown/asciidoc_pipeline' + autoload :AtomPipeline, 'gitlab/markdown/atom_pipeline' + autoload :CombinedPipeline, 'gitlab/markdown/combined_pipeline' + autoload :DescriptionPipeline, 'gitlab/markdown/description_pipeline' + autoload :EmailPipeline, 'gitlab/markdown/email_pipeline' + autoload :FullPipeline, 'gitlab/markdown/full_pipeline' + autoload :GfmPipeline, 'gitlab/markdown/gfm_pipeline' + autoload :NotePipeline, 'gitlab/markdown/note_pipeline' + autoload :Pipeline, 'gitlab/markdown/pipeline' + autoload :PlainMarkdownPipeline, 'gitlab/markdown/plain_markdown_pipeline' + autoload :PostProcessPipeline, 'gitlab/markdown/post_process_pipeline' + autoload :ReferenceExtractionPipeline, 'gitlab/markdown/reference_extraction_pipeline' + autoload :SingleLinePipeline, 'gitlab/markdown/single_line_pipeline' end end diff --git a/lib/gitlab/markdown/asciidoc_pipeline.rb b/lib/gitlab/markdown/asciidoc_pipeline.rb new file mode 100644 index 00000000000..6829b4acb95 --- /dev/null +++ b/lib/gitlab/markdown/asciidoc_pipeline.rb @@ -0,0 +1,13 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class AsciidocPipeline < Pipeline + def self.filters + [ + Gitlab::Markdown::RelativeLinkFilter + ] + end + end + end +end diff --git a/lib/gitlab/markdown/atom_pipeline.rb b/lib/gitlab/markdown/atom_pipeline.rb new file mode 100644 index 00000000000..e151f8f5e5a --- /dev/null +++ b/lib/gitlab/markdown/atom_pipeline.rb @@ -0,0 +1,14 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class AtomPipeline < FullPipeline + def self.transform_context(context) + super(context).merge( + only_path: false, + xhtml: true + ) + end + end + end +end diff --git a/lib/gitlab/markdown/combined_pipeline.rb b/lib/gitlab/markdown/combined_pipeline.rb new file mode 100644 index 00000000000..a3d717550f5 --- /dev/null +++ b/lib/gitlab/markdown/combined_pipeline.rb @@ -0,0 +1,25 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + module CombinedPipeline + def self.new(*pipelines) + Class.new(Pipeline) do + const_set :PIPELINES, pipelines + + def self.filters + pipelines.flat_map(&:filters) + end + + def self.transform_context(context) + pipelines.reduce(context) { |context, pipeline| pipeline.transform_context(context) } + end + + def self.pipelines + self::PIPELINES + end + end + end + end + end +end diff --git a/lib/gitlab/markdown/description_pipeline.rb b/lib/gitlab/markdown/description_pipeline.rb new file mode 100644 index 00000000000..76f6948af8f --- /dev/null +++ b/lib/gitlab/markdown/description_pipeline.rb @@ -0,0 +1,14 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class DescriptionPipeline < FullPipeline + def self.transform_context(context) + super(context).merge( + # SanitizationFilter + inline_sanitization: true + ) + end + end + end +end diff --git a/lib/gitlab/markdown/email_pipeline.rb b/lib/gitlab/markdown/email_pipeline.rb new file mode 100644 index 00000000000..b88cb790270 --- /dev/null +++ b/lib/gitlab/markdown/email_pipeline.rb @@ -0,0 +1,13 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class EmailPipeline < FullPipeline + def self.transform_context(context) + super(context).merge( + only_path: false + ) + end + end + end +end diff --git a/lib/gitlab/markdown/full_pipeline.rb b/lib/gitlab/markdown/full_pipeline.rb new file mode 100644 index 00000000000..553e9367c1c --- /dev/null +++ b/lib/gitlab/markdown/full_pipeline.rb @@ -0,0 +1,9 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class FullPipeline < CombinedPipeline.new(PlainMarkdownPipeline, GfmPipeline) + + end + end +end diff --git a/lib/gitlab/markdown/gfm_pipeline.rb b/lib/gitlab/markdown/gfm_pipeline.rb new file mode 100644 index 00000000000..ca90bd75d77 --- /dev/null +++ b/lib/gitlab/markdown/gfm_pipeline.rb @@ -0,0 +1,41 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class GfmPipeline < Pipeline + def self.filters + @filters ||= [ + Gitlab::Markdown::SyntaxHighlightFilter, + Gitlab::Markdown::SanitizationFilter, + + Gitlab::Markdown::UploadLinkFilter, + Gitlab::Markdown::EmojiFilter, + Gitlab::Markdown::TableOfContentsFilter, + Gitlab::Markdown::AutolinkFilter, + Gitlab::Markdown::ExternalLinkFilter, + + Gitlab::Markdown::UserReferenceFilter, + Gitlab::Markdown::IssueReferenceFilter, + Gitlab::Markdown::ExternalIssueReferenceFilter, + Gitlab::Markdown::MergeRequestReferenceFilter, + Gitlab::Markdown::SnippetReferenceFilter, + Gitlab::Markdown::CommitRangeReferenceFilter, + Gitlab::Markdown::CommitReferenceFilter, + Gitlab::Markdown::LabelReferenceFilter, + + Gitlab::Markdown::TaskListFilter + ] + end + + def self.transform_context(context) + context.merge( + only_path: true, + + # EmojiFilter + asset_host: Gitlab::Application.config.asset_host, + asset_root: Gitlab.config.gitlab.base_url + ) + end + end + end +end diff --git a/lib/gitlab/markdown/note_pipeline.rb b/lib/gitlab/markdown/note_pipeline.rb new file mode 100644 index 00000000000..a8bf5f42d8e --- /dev/null +++ b/lib/gitlab/markdown/note_pipeline.rb @@ -0,0 +1,14 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class NotePipeline < FullPipeline + def self.transform_context(context) + super(context).merge( + # TableOfContentsFilter + no_header_anchors: true + ) + end + end + end +end diff --git a/lib/gitlab/markdown/pipeline.rb b/lib/gitlab/markdown/pipeline.rb new file mode 100644 index 00000000000..3c0b676a073 --- /dev/null +++ b/lib/gitlab/markdown/pipeline.rb @@ -0,0 +1,29 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class Pipeline + def self.filters + [] + end + + def self.transform_context(context) + context + end + + def self.html_pipeline + @html_pipeline ||= HTML::Pipeline.new(filters) + end + + class << self + %i(call to_document to_html).each do |meth| + define_method(meth) do |text, context| + context = transform_context(context) + + html_pipeline.send(meth, text, context) + end + end + end + end + end +end diff --git a/lib/gitlab/markdown/plain_markdown_pipeline.rb b/lib/gitlab/markdown/plain_markdown_pipeline.rb new file mode 100644 index 00000000000..0abb93f8a03 --- /dev/null +++ b/lib/gitlab/markdown/plain_markdown_pipeline.rb @@ -0,0 +1,13 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class PlainMarkdownPipeline < Pipeline + def self.filters + [ + Gitlab::Markdown::MarkdownFilter + ] + end + end + end +end diff --git a/lib/gitlab/markdown/post_process_pipeline.rb b/lib/gitlab/markdown/post_process_pipeline.rb new file mode 100644 index 00000000000..60cc32f490e --- /dev/null +++ b/lib/gitlab/markdown/post_process_pipeline.rb @@ -0,0 +1,20 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class PostProcessPipeline < Pipeline + def self.filters + [ + Gitlab::Markdown::RelativeLinkFilter, + Gitlab::Markdown::RedactorFilter + ] + end + + def self.transform_context(context) + context.merge( + post_process: true + ) + end + end + end +end diff --git a/lib/gitlab/markdown/reference_extraction_pipeline.rb b/lib/gitlab/markdown/reference_extraction_pipeline.rb new file mode 100644 index 00000000000..a89ab462bac --- /dev/null +++ b/lib/gitlab/markdown/reference_extraction_pipeline.rb @@ -0,0 +1,13 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class ReferenceExtractionPipeline < Pipeline + def self.filters + [ + Gitlab::Markdown::ReferenceGathererFilter + ] + end + end + end +end diff --git a/lib/gitlab/markdown/single_line_pipeline.rb b/lib/gitlab/markdown/single_line_pipeline.rb new file mode 100644 index 00000000000..2f24927b879 --- /dev/null +++ b/lib/gitlab/markdown/single_line_pipeline.rb @@ -0,0 +1,9 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class SingleLinePipeline < GfmPipeline + + end + end +end -- cgit v1.2.1 From f65840bc842b86cd71e70af8b9acdb1a786d9054 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 22 Oct 2015 11:00:34 +0200 Subject: Fix Markdown XHTML context param --- lib/gitlab/markdown.rb | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 3ae4ccfacb6..5f1a6c8ceec 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -20,8 +20,6 @@ module Gitlab # # Returns an HTML-safe String def self.render(text, context = {}) - context[:pipeline] ||= :full - cache_key = context.delete(:cache_key) cache_key = full_cache_key(cache_key, context[:pipeline]) @@ -35,8 +33,7 @@ module Gitlab end def self.render_result(text, context = {}) - pipeline_type = context[:pipeline] ||= :full - pipeline_by_type(pipeline_type).call(text, context) + pipeline_by_name(context[:pipeline]).call(text, context) end # Perform post-processing on an HTML String @@ -53,7 +50,10 @@ module Gitlab # # Returns an HTML-safe String def self.post_process(html, context) - pipeline = pipeline_by_type(:post_process) + pipeline = pipeline_by_name(context[:pipeline]) + context = pipeline.transform_context(context) + + pipeline = pipeline_by_name(:post_process) if context[:xhtml] pipeline.to_document(html, context).to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML) @@ -74,14 +74,15 @@ module Gitlab end end - def self.full_cache_key(cache_key, pipeline = :full) + def self.full_cache_key(cache_key, pipeline_name) return unless cache_key - + pipeline_name ||= :full ["markdown", *cache_key, pipeline] end - def self.pipeline_by_type(pipeline_type) - const_get("#{pipeline_type.to_s.camelize}Pipeline") + def self.pipeline_by_name(pipeline_name) + pipeline_name ||= :full + const_get("#{pipeline_name.to_s.camelize}Pipeline") end # Provide autoload paths for filters to prevent a circular dependency error -- cgit v1.2.1 From 51ed8fd706802fe0fffe7a2db0b5adc1f2196e50 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 22 Oct 2015 15:40:21 +0200 Subject: Use correct var name --- lib/gitlab/markdown.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 5f1a6c8ceec..969607558ef 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -77,7 +77,7 @@ module Gitlab def self.full_cache_key(cache_key, pipeline_name) return unless cache_key pipeline_name ||= :full - ["markdown", *cache_key, pipeline] + ["markdown", *cache_key, pipeline_name] end def self.pipeline_by_name(pipeline_name) -- cgit v1.2.1 From aa4007a597ea6c7de11a8f37de2fd889aa6e6646 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 22 Oct 2015 15:40:36 +0200 Subject: Slight refactoring --- lib/gitlab/reference_extractor.rb | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index 69c7a0f4779..e5cafebdbc0 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -11,6 +11,7 @@ module Gitlab @load_lazy_references = load_lazy_references @texts = [] + @references = {} end def analyze(text, options = {}) @@ -19,21 +20,12 @@ module Gitlab %i(user label issue merge_request snippet commit commit_range).each do |type| define_method("#{type}s") do - references[type] + @references[type] ||= pipeline_result(type) end end private - def references - @references ||= Hash.new do |references, type| - type = type.to_sym - next references[type] if references.has_key?(type) - - references[type] = pipeline_result(type) - end - end - # Instantiate and call HTML::Pipeline with a single reference filter type, # returning the result # -- cgit v1.2.1 From 2f048df4a4a83ff009d2ef2d14ee04e5a2798618 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Wed, 18 Nov 2015 11:17:41 +0100 Subject: API support, incorporated feedback --- lib/api/merge_requests.rb | 68 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 22 deletions(-) (limited to 'lib') diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 6eb84baf9cb..f981432db36 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -179,9 +179,10 @@ module API # Merge MR # # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - ID of MR - # merge_commit_message (optional) - Custom merge commit message + # id (required) - The ID of a project + # merge_request_id (required) - ID of MR + # merge_commit_message (optional) - Custom merge commit message + # merge_when_build_succeeds (optional) - truethy when this MR should be merged when the build is succesfull # Example: # PUT /projects/:id/merge_request/:merge_request_id/merge # @@ -191,34 +192,57 @@ module API allowed = ::Gitlab::GitAccess.new(current_user, user_project). can_push_to_branch?(merge_request.target_branch) - if allowed - if merge_request.unchecked? - merge_request.check_if_can_be_merged - end + # Merge request can not be merged + # because user dont have permissions to push into target branch + unauthorized! unless allowed + + not_allowed! unless merge_request.open? - if merge_request.open? && !merge_request.work_in_progress? - if merge_request.can_be_merged? - commit_message = params[:merge_commit_message] || merge_request.merge_commit_message + merge_request.check_if_can_be_merged if merge_request.unchecked? - ::MergeRequests::MergeService.new(merge_request.target_project, current_user). - execute(merge_request, commit_message) + merge_params = { + commit_message: params[:merge_commit_message], + should_remove_source_branch: params[:should_remove_source_branch] + } - present merge_request, with: Entities::MergeRequest - else - render_api_error!('Branch cannot be merged', 405) - end + if !merge_request.work_in_progress? + if parse_boolean(params[:merge_when_build_succeeds]) + ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). + execute(merge_request) else - # Merge request can not be merged - # because it is already closed/merged or marked as WIP - not_allowed! + ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params). + execute(merge_request, merge_params) end else - # Merge request can not be merged - # because user dont have permissions to push into target branch - unauthorized! + render_api_error!('Branch cannot be merged', 405) end + + present merge_request, with: Entities::MergeRequest end + # Cancel Merge if Merge When build succeeds is enabled + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - ID of MR + # + post ":id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds" do + merge_request = user_project.merge_requests.find(params[:merge_request_id]) + + allowed = ::Gitlab::GitAccess.new(current_user, user_project). + can_push_to_branch?(merge_request.target_branch) + + # Merge request can not be merged + # because user dont have permissions to push into target branch + unauthorized! unless allowed + + if merge_request.merged? || !merge_request.open? || !merge_request.merge_when_build_succeeds? + not_allowed! + end + + merge_request.reset_merge_when_build_succeeds + + present merge_request, with: Entities::MergeRequest + end # Get a merge request's comments # -- cgit v1.2.1 From 3cc2b48a82aae8b535ddf11e9057a29f2242524c Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Wed, 18 Nov 2015 11:39:26 +0100 Subject: Backup LFS objects same as any upload. --- lib/backup/lfs.rb | 13 +++++++++++++ lib/backup/manager.rb | 2 +- lib/tasks/gitlab/backup.rake | 21 +++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 lib/backup/lfs.rb (limited to 'lib') diff --git a/lib/backup/lfs.rb b/lib/backup/lfs.rb new file mode 100644 index 00000000000..4153467fbee --- /dev/null +++ b/lib/backup/lfs.rb @@ -0,0 +1,13 @@ +require 'backup/files' + +module Backup + class Lfs < Files + def initialize + super('lfs', Settings.lfs.storage_path) + end + + def create_files_dir + Dir.mkdir(app_files_dir, 0700) + end + end +end diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb index e7eda7c6f45..099062eeb8b 100644 --- a/lib/backup/manager.rb +++ b/lib/backup/manager.rb @@ -154,7 +154,7 @@ module Backup end def archives_to_backup - %w{uploads builds artifacts}.map{ |name| (name + ".tar.gz") unless skipped?(name) }.compact + %w{uploads builds artifacts lfs}.map{ |name| (name + ".tar.gz") unless skipped?(name) }.compact end def folders_to_backup diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index 3c46bcea40e..cb4abe13799 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -13,6 +13,7 @@ namespace :gitlab do Rake::Task["gitlab:backup:uploads:create"].invoke Rake::Task["gitlab:backup:builds:create"].invoke Rake::Task["gitlab:backup:artifacts:create"].invoke + Rake::Task["gitlab:backup:lfs:create"].invoke backup = Backup::Manager.new backup.pack @@ -34,6 +35,7 @@ namespace :gitlab do Rake::Task["gitlab:backup:uploads:restore"].invoke unless backup.skipped?("uploads") Rake::Task["gitlab:backup:builds:restore"].invoke unless backup.skipped?("builds") Rake::Task["gitlab:backup:artifacts:restore"].invoke unless backup.skipped?("artifacts") + Rake::Task["gitlab:backup:lfs:restore"].invoke unless backup.skipped?("lfs") Rake::Task["gitlab:shell:setup"].invoke backup.cleanup @@ -134,6 +136,25 @@ namespace :gitlab do end end + namespace :lfs do + task create: :environment do + $progress.puts "Dumping lfs objects ... ".blue + + if ENV["SKIP"] && ENV["SKIP"].include?("lfs") + $progress.puts "[SKIPPED]".cyan + else + Backup::Lfs.new.dump + $progress.puts "done".green + end + end + + task restore: :environment do + $progress.puts "Restoring lfs objects ... ".blue + Backup::Lfs.new.restore + $progress.puts "done".green + end + end + def configure_cron_mode if ENV['CRON'] # We need an object we can say 'puts' and 'print' to; let's use a -- cgit v1.2.1 From e1e67d383e4b56c9e1848aebc175402a71502e82 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 19 Nov 2015 16:18:13 +0100 Subject: Move Markdown filters and pipelines into folders. --- lib/gitlab/markdown.rb | 80 +++++------ lib/gitlab/markdown/asciidoc_pipeline.rb | 13 -- lib/gitlab/markdown/atom_pipeline.rb | 14 -- lib/gitlab/markdown/autolink_filter.rb | 107 -------------- .../markdown/commit_range_reference_filter.rb | 92 ------------ lib/gitlab/markdown/commit_reference_filter.rb | 88 ------------ lib/gitlab/markdown/description_pipeline.rb | 14 -- lib/gitlab/markdown/email_pipeline.rb | 13 -- lib/gitlab/markdown/emoji_filter.rb | 80 ----------- .../markdown/external_issue_reference_filter.rb | 63 --------- lib/gitlab/markdown/external_link_filter.rb | 34 ----- lib/gitlab/markdown/filter/autolink_filter.rb | 107 ++++++++++++++ .../filter/commit_range_reference_filter.rb | 92 ++++++++++++ .../markdown/filter/commit_reference_filter.rb | 88 ++++++++++++ lib/gitlab/markdown/filter/emoji_filter.rb | 80 +++++++++++ .../filter/external_issue_reference_filter.rb | 63 +++++++++ lib/gitlab/markdown/filter/external_link_filter.rb | 34 +++++ .../markdown/filter/issue_reference_filter.rb | 23 +++ .../markdown/filter/label_reference_filter.rb | 87 ++++++++++++ lib/gitlab/markdown/filter/markdown_filter.rb | 39 +++++ .../filter/merge_request_reference_filter.rb | 25 ++++ lib/gitlab/markdown/filter/redactor_filter.rb | 40 ++++++ .../markdown/filter/reference_gatherer_filter.rb | 63 +++++++++ lib/gitlab/markdown/filter/relative_link_filter.rb | 157 +++++++++++++++++++++ lib/gitlab/markdown/filter/sanitization_filter.rb | 99 +++++++++++++ .../markdown/filter/snippet_reference_filter.rb | 25 ++++ .../markdown/filter/syntax_highlight_filter.rb | 45 ++++++ .../markdown/filter/table_of_contents_filter.rb | 63 +++++++++ lib/gitlab/markdown/filter/task_list_filter.rb | 24 ++++ lib/gitlab/markdown/filter/upload_link_filter.rb | 47 ++++++ .../markdown/filter/user_reference_filter.rb | 125 ++++++++++++++++ lib/gitlab/markdown/full_pipeline.rb | 9 -- lib/gitlab/markdown/gfm_pipeline.rb | 41 ------ lib/gitlab/markdown/issue_reference_filter.rb | 23 --- lib/gitlab/markdown/label_reference_filter.rb | 87 ------------ lib/gitlab/markdown/markdown_filter.rb | 39 ----- .../markdown/merge_request_reference_filter.rb | 25 ---- lib/gitlab/markdown/note_pipeline.rb | 14 -- lib/gitlab/markdown/pipeline.rb | 5 + lib/gitlab/markdown/pipeline/asciidoc_pipeline.rb | 13 ++ lib/gitlab/markdown/pipeline/atom_pipeline.rb | 14 ++ .../markdown/pipeline/description_pipeline.rb | 14 ++ lib/gitlab/markdown/pipeline/email_pipeline.rb | 13 ++ lib/gitlab/markdown/pipeline/full_pipeline.rb | 9 ++ lib/gitlab/markdown/pipeline/gfm_pipeline.rb | 41 ++++++ lib/gitlab/markdown/pipeline/note_pipeline.rb | 14 ++ .../markdown/pipeline/plain_markdown_pipeline.rb | 13 ++ .../markdown/pipeline/post_process_pipeline.rb | 20 +++ .../pipeline/reference_extraction_pipeline.rb | 13 ++ .../markdown/pipeline/single_line_pipeline.rb | 9 ++ lib/gitlab/markdown/plain_markdown_pipeline.rb | 13 -- lib/gitlab/markdown/post_process_pipeline.rb | 20 --- lib/gitlab/markdown/redactor_filter.rb | 40 ------ .../markdown/reference_extraction_pipeline.rb | 13 -- lib/gitlab/markdown/reference_filter.rb | 4 + lib/gitlab/markdown/reference_gatherer_filter.rb | 63 --------- lib/gitlab/markdown/relative_link_filter.rb | 157 --------------------- lib/gitlab/markdown/sanitization_filter.rb | 99 ------------- lib/gitlab/markdown/single_line_pipeline.rb | 9 -- lib/gitlab/markdown/snippet_reference_filter.rb | 25 ---- lib/gitlab/markdown/syntax_highlight_filter.rb | 45 ------ lib/gitlab/markdown/table_of_contents_filter.rb | 63 --------- lib/gitlab/markdown/task_list_filter.rb | 24 ---- lib/gitlab/markdown/upload_link_filter.rb | 47 ------ lib/gitlab/markdown/user_reference_filter.rb | 125 ---------------- lib/gitlab/reference_extractor.rb | 3 +- 66 files changed, 1545 insertions(+), 1545 deletions(-) delete mode 100644 lib/gitlab/markdown/asciidoc_pipeline.rb delete mode 100644 lib/gitlab/markdown/atom_pipeline.rb delete mode 100644 lib/gitlab/markdown/autolink_filter.rb delete mode 100644 lib/gitlab/markdown/commit_range_reference_filter.rb delete mode 100644 lib/gitlab/markdown/commit_reference_filter.rb delete mode 100644 lib/gitlab/markdown/description_pipeline.rb delete mode 100644 lib/gitlab/markdown/email_pipeline.rb delete mode 100644 lib/gitlab/markdown/emoji_filter.rb delete mode 100644 lib/gitlab/markdown/external_issue_reference_filter.rb delete mode 100644 lib/gitlab/markdown/external_link_filter.rb create mode 100644 lib/gitlab/markdown/filter/autolink_filter.rb create mode 100644 lib/gitlab/markdown/filter/commit_range_reference_filter.rb create mode 100644 lib/gitlab/markdown/filter/commit_reference_filter.rb create mode 100644 lib/gitlab/markdown/filter/emoji_filter.rb create mode 100644 lib/gitlab/markdown/filter/external_issue_reference_filter.rb create mode 100644 lib/gitlab/markdown/filter/external_link_filter.rb create mode 100644 lib/gitlab/markdown/filter/issue_reference_filter.rb create mode 100644 lib/gitlab/markdown/filter/label_reference_filter.rb create mode 100644 lib/gitlab/markdown/filter/markdown_filter.rb create mode 100644 lib/gitlab/markdown/filter/merge_request_reference_filter.rb create mode 100644 lib/gitlab/markdown/filter/redactor_filter.rb create mode 100644 lib/gitlab/markdown/filter/reference_gatherer_filter.rb create mode 100644 lib/gitlab/markdown/filter/relative_link_filter.rb create mode 100644 lib/gitlab/markdown/filter/sanitization_filter.rb create mode 100644 lib/gitlab/markdown/filter/snippet_reference_filter.rb create mode 100644 lib/gitlab/markdown/filter/syntax_highlight_filter.rb create mode 100644 lib/gitlab/markdown/filter/table_of_contents_filter.rb create mode 100644 lib/gitlab/markdown/filter/task_list_filter.rb create mode 100644 lib/gitlab/markdown/filter/upload_link_filter.rb create mode 100644 lib/gitlab/markdown/filter/user_reference_filter.rb delete mode 100644 lib/gitlab/markdown/full_pipeline.rb delete mode 100644 lib/gitlab/markdown/gfm_pipeline.rb delete mode 100644 lib/gitlab/markdown/issue_reference_filter.rb delete mode 100644 lib/gitlab/markdown/label_reference_filter.rb delete mode 100644 lib/gitlab/markdown/markdown_filter.rb delete mode 100644 lib/gitlab/markdown/merge_request_reference_filter.rb delete mode 100644 lib/gitlab/markdown/note_pipeline.rb create mode 100644 lib/gitlab/markdown/pipeline/asciidoc_pipeline.rb create mode 100644 lib/gitlab/markdown/pipeline/atom_pipeline.rb create mode 100644 lib/gitlab/markdown/pipeline/description_pipeline.rb create mode 100644 lib/gitlab/markdown/pipeline/email_pipeline.rb create mode 100644 lib/gitlab/markdown/pipeline/full_pipeline.rb create mode 100644 lib/gitlab/markdown/pipeline/gfm_pipeline.rb create mode 100644 lib/gitlab/markdown/pipeline/note_pipeline.rb create mode 100644 lib/gitlab/markdown/pipeline/plain_markdown_pipeline.rb create mode 100644 lib/gitlab/markdown/pipeline/post_process_pipeline.rb create mode 100644 lib/gitlab/markdown/pipeline/reference_extraction_pipeline.rb create mode 100644 lib/gitlab/markdown/pipeline/single_line_pipeline.rb delete mode 100644 lib/gitlab/markdown/plain_markdown_pipeline.rb delete mode 100644 lib/gitlab/markdown/post_process_pipeline.rb delete mode 100644 lib/gitlab/markdown/redactor_filter.rb delete mode 100644 lib/gitlab/markdown/reference_extraction_pipeline.rb delete mode 100644 lib/gitlab/markdown/reference_gatherer_filter.rb delete mode 100644 lib/gitlab/markdown/relative_link_filter.rb delete mode 100644 lib/gitlab/markdown/sanitization_filter.rb delete mode 100644 lib/gitlab/markdown/single_line_pipeline.rb delete mode 100644 lib/gitlab/markdown/snippet_reference_filter.rb delete mode 100644 lib/gitlab/markdown/syntax_highlight_filter.rb delete mode 100644 lib/gitlab/markdown/table_of_contents_filter.rb delete mode 100644 lib/gitlab/markdown/task_list_filter.rb delete mode 100644 lib/gitlab/markdown/upload_link_filter.rb delete mode 100644 lib/gitlab/markdown/user_reference_filter.rb (limited to 'lib') diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 969607558ef..f4e2cefca51 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -33,7 +33,7 @@ module Gitlab end def self.render_result(text, context = {}) - pipeline_by_name(context[:pipeline]).call(text, context) + Pipeline[context[:pipeline]].call(text, context) end # Perform post-processing on an HTML String @@ -50,11 +50,9 @@ module Gitlab # # Returns an HTML-safe String def self.post_process(html, context) - pipeline = pipeline_by_name(context[:pipeline]) - context = pipeline.transform_context(context) - - pipeline = pipeline_by_name(:post_process) + context = Pipeline[context[:pipeline]].transform_context(context) + pipeline = Pipeline[:post_process] if context[:xhtml] pipeline.to_document(html, context).to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML) else @@ -66,6 +64,7 @@ module Gitlab def self.cacheless_render(text, context = {}) result = render_result(text, context) + output = result[:output] if output.respond_to?(:to_html) output.to_html @@ -76,48 +75,41 @@ module Gitlab def self.full_cache_key(cache_key, pipeline_name) return unless cache_key - pipeline_name ||= :full - ["markdown", *cache_key, pipeline_name] - end - - def self.pipeline_by_name(pipeline_name) - pipeline_name ||= :full - const_get("#{pipeline_name.to_s.camelize}Pipeline") + ["markdown", *cache_key, pipeline_name || :full] end # Provide autoload paths for filters to prevent a circular dependency error - autoload :AutolinkFilter, 'gitlab/markdown/autolink_filter' - autoload :CommitRangeReferenceFilter, 'gitlab/markdown/commit_range_reference_filter' - autoload :CommitReferenceFilter, 'gitlab/markdown/commit_reference_filter' - autoload :EmojiFilter, 'gitlab/markdown/emoji_filter' - autoload :ExternalIssueReferenceFilter, 'gitlab/markdown/external_issue_reference_filter' - autoload :ExternalLinkFilter, 'gitlab/markdown/external_link_filter' - autoload :IssueReferenceFilter, 'gitlab/markdown/issue_reference_filter' - autoload :LabelReferenceFilter, 'gitlab/markdown/label_reference_filter' - autoload :MarkdownFilter, 'gitlab/markdown/markdown_filter' - autoload :MergeRequestReferenceFilter, 'gitlab/markdown/merge_request_reference_filter' - autoload :RedactorFilter, 'gitlab/markdown/redactor_filter' - autoload :RelativeLinkFilter, 'gitlab/markdown/relative_link_filter' - autoload :SanitizationFilter, 'gitlab/markdown/sanitization_filter' - autoload :SnippetReferenceFilter, 'gitlab/markdown/snippet_reference_filter' - autoload :SyntaxHighlightFilter, 'gitlab/markdown/syntax_highlight_filter' - autoload :TableOfContentsFilter, 'gitlab/markdown/table_of_contents_filter' - autoload :TaskListFilter, 'gitlab/markdown/task_list_filter' - autoload :UserReferenceFilter, 'gitlab/markdown/user_reference_filter' - autoload :UploadLinkFilter, 'gitlab/markdown/upload_link_filter' + autoload :AutolinkFilter, 'gitlab/markdown/filter/autolink_filter' + autoload :CommitRangeReferenceFilter, 'gitlab/markdown/filter/commit_range_reference_filter' + autoload :CommitReferenceFilter, 'gitlab/markdown/filter/commit_reference_filter' + autoload :EmojiFilter, 'gitlab/markdown/filter/emoji_filter' + autoload :ExternalIssueReferenceFilter, 'gitlab/markdown/filter/external_issue_reference_filter' + autoload :ExternalLinkFilter, 'gitlab/markdown/filter/external_link_filter' + autoload :IssueReferenceFilter, 'gitlab/markdown/filter/issue_reference_filter' + autoload :LabelReferenceFilter, 'gitlab/markdown/filter/label_reference_filter' + autoload :MarkdownFilter, 'gitlab/markdown/filter/markdown_filter' + autoload :MergeRequestReferenceFilter, 'gitlab/markdown/filter/merge_request_reference_filter' + autoload :RedactorFilter, 'gitlab/markdown/filter/redactor_filter' + autoload :ReferenceGathererFilter, 'gitlab/markdown/filter/reference_gatherer_filter' + autoload :RelativeLinkFilter, 'gitlab/markdown/filter/relative_link_filter' + autoload :SanitizationFilter, 'gitlab/markdown/filter/sanitization_filter' + autoload :SnippetReferenceFilter, 'gitlab/markdown/filter/snippet_reference_filter' + autoload :SyntaxHighlightFilter, 'gitlab/markdown/filter/syntax_highlight_filter' + autoload :TableOfContentsFilter, 'gitlab/markdown/filter/table_of_contents_filter' + autoload :TaskListFilter, 'gitlab/markdown/filter/task_list_filter' + autoload :UserReferenceFilter, 'gitlab/markdown/filter/user_reference_filter' + autoload :UploadLinkFilter, 'gitlab/markdown/filter/upload_link_filter' - autoload :AsciidocPipeline, 'gitlab/markdown/asciidoc_pipeline' - autoload :AtomPipeline, 'gitlab/markdown/atom_pipeline' - autoload :CombinedPipeline, 'gitlab/markdown/combined_pipeline' - autoload :DescriptionPipeline, 'gitlab/markdown/description_pipeline' - autoload :EmailPipeline, 'gitlab/markdown/email_pipeline' - autoload :FullPipeline, 'gitlab/markdown/full_pipeline' - autoload :GfmPipeline, 'gitlab/markdown/gfm_pipeline' - autoload :NotePipeline, 'gitlab/markdown/note_pipeline' - autoload :Pipeline, 'gitlab/markdown/pipeline' - autoload :PlainMarkdownPipeline, 'gitlab/markdown/plain_markdown_pipeline' - autoload :PostProcessPipeline, 'gitlab/markdown/post_process_pipeline' - autoload :ReferenceExtractionPipeline, 'gitlab/markdown/reference_extraction_pipeline' - autoload :SingleLinePipeline, 'gitlab/markdown/single_line_pipeline' + autoload :AsciidocPipeline, 'gitlab/markdown/pipeline/asciidoc_pipeline' + autoload :AtomPipeline, 'gitlab/markdown/pipeline/atom_pipeline' + autoload :DescriptionPipeline, 'gitlab/markdown/pipeline/description_pipeline' + autoload :EmailPipeline, 'gitlab/markdown/pipeline/email_pipeline' + autoload :FullPipeline, 'gitlab/markdown/pipeline/full_pipeline' + autoload :GfmPipeline, 'gitlab/markdown/pipeline/gfm_pipeline' + autoload :NotePipeline, 'gitlab/markdown/pipeline/note_pipeline' + autoload :PlainMarkdownPipeline, 'gitlab/markdown/pipeline/plain_markdown_pipeline' + autoload :PostProcessPipeline, 'gitlab/markdown/pipeline/post_process_pipeline' + autoload :ReferenceExtractionPipeline, 'gitlab/markdown/pipeline/reference_extraction_pipeline' + autoload :SingleLinePipeline, 'gitlab/markdown/pipeline/single_line_pipeline' end end diff --git a/lib/gitlab/markdown/asciidoc_pipeline.rb b/lib/gitlab/markdown/asciidoc_pipeline.rb deleted file mode 100644 index 6829b4acb95..00000000000 --- a/lib/gitlab/markdown/asciidoc_pipeline.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - class AsciidocPipeline < Pipeline - def self.filters - [ - Gitlab::Markdown::RelativeLinkFilter - ] - end - end - end -end diff --git a/lib/gitlab/markdown/atom_pipeline.rb b/lib/gitlab/markdown/atom_pipeline.rb deleted file mode 100644 index e151f8f5e5a..00000000000 --- a/lib/gitlab/markdown/atom_pipeline.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - class AtomPipeline < FullPipeline - def self.transform_context(context) - super(context).merge( - only_path: false, - xhtml: true - ) - end - end - end -end diff --git a/lib/gitlab/markdown/autolink_filter.rb b/lib/gitlab/markdown/autolink_filter.rb deleted file mode 100644 index c37c3bc55bf..00000000000 --- a/lib/gitlab/markdown/autolink_filter.rb +++ /dev/null @@ -1,107 +0,0 @@ -require 'gitlab/markdown' -require 'html/pipeline/filter' -require 'uri' - -module Gitlab - module Markdown - # HTML Filter for auto-linking URLs in HTML. - # - # Based on HTML::Pipeline::AutolinkFilter - # - # Context options: - # :autolink - Boolean, skips all processing done by this filter when false - # :link_attr - Hash of attributes for the generated links - # - class AutolinkFilter < HTML::Pipeline::Filter - include ActionView::Helpers::TagHelper - - # Pattern to match text that should be autolinked. - # - # A URI scheme begins with a letter and may contain letters, numbers, - # plus, period and hyphen. Schemes are case-insensitive but we're being - # picky here and allowing only lowercase for autolinks. - # - # See http://en.wikipedia.org/wiki/URI_scheme - # - # The negative lookbehind ensures that users can paste a URL followed by a - # period or comma for punctuation without those characters being included - # in the generated link. - # - # Rubular: http://rubular.com/r/cxjPyZc7Sb - LINK_PATTERN = %r{([a-z][a-z0-9\+\.-]+://\S+)(?#{commit_range}" - # end - # - # text - String text to search. - # - # Yields the String match, the String commit range, and an optional String - # of the external project reference. - # - # Returns a String replaced with the return of the block. - def self.references_in(text) - text.gsub(CommitRange.reference_pattern) do |match| - yield match, $~[:commit_range], $~[:project] - end - end - - def self.referenced_by(node) - project = Project.find(node.attr("data-project")) rescue nil - return unless project - - id = node.attr("data-commit-range") - range = CommitRange.new(id, project) - - return unless range.valid_commits? - - { commit_range: range } - end - - def initialize(*args) - super - - @commit_map = {} - end - - def call - replace_text_nodes_matching(CommitRange.reference_pattern) do |content| - commit_range_link_filter(content) - end - end - - # Replace commit range references in text with links to compare the commit - # ranges. - # - # text - String text to replace references in. - # - # Returns a String with commit range references replaced with links. All - # links have `gfm` and `gfm-commit_range` class names attached for - # styling. - def commit_range_link_filter(text) - self.class.references_in(text) do |match, id, project_ref| - project = self.project_from_ref(project_ref) - - range = CommitRange.new(id, project) - - if range.valid_commits? - url = url_for_commit_range(project, range) - - title = range.reference_title - klass = reference_class(:commit_range) - data = data_attribute(project: project.id, commit_range: id) - - project_ref += '@' if project_ref - - %(#{project_ref}#{range}) - else - match - end - end - end - - def url_for_commit_range(project, range) - h = Gitlab::Application.routes.url_helpers - h.namespace_project_compare_url(project.namespace, project, - range.to_param.merge(only_path: context[:only_path])) - end - end - end -end diff --git a/lib/gitlab/markdown/commit_reference_filter.rb b/lib/gitlab/markdown/commit_reference_filter.rb deleted file mode 100644 index 8cdbeb1f9cf..00000000000 --- a/lib/gitlab/markdown/commit_reference_filter.rb +++ /dev/null @@ -1,88 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - # HTML filter that replaces commit references with links. - # - # This filter supports cross-project references. - class CommitReferenceFilter < ReferenceFilter - include CrossProjectReference - - # Public: Find commit references in text - # - # CommitReferenceFilter.references_in(text) do |match, commit, project_ref| - # "#{commit}" - # end - # - # text - String text to search. - # - # Yields the String match, the String commit identifier, and an optional - # String of the external project reference. - # - # Returns a String replaced with the return of the block. - def self.references_in(text) - text.gsub(Commit.reference_pattern) do |match| - yield match, $~[:commit], $~[:project] - end - end - - def self.referenced_by(node) - project = Project.find(node.attr("data-project")) rescue nil - return unless project - - id = node.attr("data-commit") - commit = commit_from_ref(project, id) - - return unless commit - - { commit: commit } - end - - def call - replace_text_nodes_matching(Commit.reference_pattern) do |content| - commit_link_filter(content) - end - end - - # Replace commit references in text with links to the commit specified. - # - # text - String text to replace references in. - # - # Returns a String with commit references replaced with links. All links - # have `gfm` and `gfm-commit` class names attached for styling. - def commit_link_filter(text) - self.class.references_in(text) do |match, id, project_ref| - project = self.project_from_ref(project_ref) - - if commit = self.class.commit_from_ref(project, id) - url = url_for_commit(project, commit) - - title = escape_once(commit.link_title) - klass = reference_class(:commit) - data = data_attribute(project: project.id, commit: id) - - project_ref += '@' if project_ref - - %(#{project_ref}#{commit.short_id}) - else - match - end - end - end - - def self.commit_from_ref(project, id) - if project && project.valid_repo? - project.commit(id) - end - end - - def url_for_commit(project, commit) - h = Gitlab::Application.routes.url_helpers - h.namespace_project_commit_url(project.namespace, project, commit, - only_path: context[:only_path]) - end - end - end -end diff --git a/lib/gitlab/markdown/description_pipeline.rb b/lib/gitlab/markdown/description_pipeline.rb deleted file mode 100644 index 76f6948af8f..00000000000 --- a/lib/gitlab/markdown/description_pipeline.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - class DescriptionPipeline < FullPipeline - def self.transform_context(context) - super(context).merge( - # SanitizationFilter - inline_sanitization: true - ) - end - end - end -end diff --git a/lib/gitlab/markdown/email_pipeline.rb b/lib/gitlab/markdown/email_pipeline.rb deleted file mode 100644 index b88cb790270..00000000000 --- a/lib/gitlab/markdown/email_pipeline.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - class EmailPipeline < FullPipeline - def self.transform_context(context) - super(context).merge( - only_path: false - ) - end - end - end -end diff --git a/lib/gitlab/markdown/emoji_filter.rb b/lib/gitlab/markdown/emoji_filter.rb deleted file mode 100644 index da10e4d3760..00000000000 --- a/lib/gitlab/markdown/emoji_filter.rb +++ /dev/null @@ -1,80 +0,0 @@ -require 'action_controller' -require 'gitlab/markdown' -require 'gitlab_emoji' -require 'html/pipeline/filter' - -module Gitlab - module Markdown - # HTML filter that replaces :emoji: with images. - # - # Based on HTML::Pipeline::EmojiFilter - # - # Context options: - # :asset_root - # :asset_host - class EmojiFilter < HTML::Pipeline::Filter - IGNORED_ANCESTOR_TAGS = %w(pre code tt).to_set - - def call - search_text_nodes(doc).each do |node| - content = node.to_html - next unless content.include?(':') - next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS) - - html = emoji_image_filter(content) - - next if html == content - - node.replace(html) - end - - doc - end - - # Replace :emoji: with corresponding images. - # - # text - String text to replace :emoji: in. - # - # Returns a String with :emoji: replaced with images. - def emoji_image_filter(text) - text.gsub(emoji_pattern) do |match| - name = $1 - ":#{name}:" - end - end - - private - - def emoji_url(name) - emoji_path = "emoji/#{emoji_filename(name)}" - if context[:asset_host] - # Asset host is specified. - url_to_image(emoji_path) - elsif context[:asset_root] - # Gitlab url is specified - File.join(context[:asset_root], url_to_image(emoji_path)) - else - # All other cases - url_to_image(emoji_path) - end - end - - def url_to_image(image) - ActionController::Base.helpers.url_to_image(image) - end - - # Build a regexp that matches all valid :emoji: names. - def self.emoji_pattern - @emoji_pattern ||= /:(#{Emoji.emojis_names.map { |name| Regexp.escape(name) }.join('|')}):/ - end - - def emoji_pattern - self.class.emoji_pattern - end - - def emoji_filename(name) - "#{Emoji.emoji_filename(name)}.png" - end - end - end -end diff --git a/lib/gitlab/markdown/external_issue_reference_filter.rb b/lib/gitlab/markdown/external_issue_reference_filter.rb deleted file mode 100644 index 8f86f13976a..00000000000 --- a/lib/gitlab/markdown/external_issue_reference_filter.rb +++ /dev/null @@ -1,63 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - # HTML filter that replaces external issue tracker references with links. - # References are ignored if the project doesn't use an external issue - # tracker. - class ExternalIssueReferenceFilter < ReferenceFilter - # Public: Find `JIRA-123` issue references in text - # - # ExternalIssueReferenceFilter.references_in(text) do |match, issue| - # "##{issue}" - # end - # - # text - String text to search. - # - # Yields the String match and the String issue reference. - # - # Returns a String replaced with the return of the block. - def self.references_in(text) - text.gsub(ExternalIssue.reference_pattern) do |match| - yield match, $~[:issue] - end - end - - def call - # Early return if the project isn't using an external tracker - return doc if project.nil? || project.default_issues_tracker? - - replace_text_nodes_matching(ExternalIssue.reference_pattern) do |content| - issue_link_filter(content) - end - end - - # Replace `JIRA-123` issue references in text with links to the referenced - # issue's details page. - # - # text - String text to replace references in. - # - # Returns a String with `JIRA-123` references replaced with links. All - # links have `gfm` and `gfm-issue` class names attached for styling. - def issue_link_filter(text) - project = context[:project] - - self.class.references_in(text) do |match, issue| - url = url_for_issue(issue, project, only_path: context[:only_path]) - - title = escape_once("Issue in #{project.external_issue_tracker.title}") - klass = reference_class(:issue) - data = data_attribute(project: project.id) - - %(#{match}) - end - end - - def url_for_issue(*args) - IssuesHelper.url_for_issue(*args) - end - end - end -end diff --git a/lib/gitlab/markdown/external_link_filter.rb b/lib/gitlab/markdown/external_link_filter.rb deleted file mode 100644 index 29e51b6ade6..00000000000 --- a/lib/gitlab/markdown/external_link_filter.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'gitlab/markdown' -require 'html/pipeline/filter' - -module Gitlab - module Markdown - # HTML Filter to add a `rel="nofollow"` attribute to external links - # - class ExternalLinkFilter < HTML::Pipeline::Filter - def call - doc.search('a').each do |node| - next unless node.has_attribute?('href') - - link = node.attribute('href').value - - # Skip non-HTTP(S) links - next unless link.start_with?('http') - - # Skip internal links - next if link.start_with?(internal_url) - - node.set_attribute('rel', 'nofollow') - end - - doc - end - - private - - def internal_url - @internal_url ||= Gitlab.config.gitlab.url - end - end - end -end diff --git a/lib/gitlab/markdown/filter/autolink_filter.rb b/lib/gitlab/markdown/filter/autolink_filter.rb new file mode 100644 index 00000000000..c37c3bc55bf --- /dev/null +++ b/lib/gitlab/markdown/filter/autolink_filter.rb @@ -0,0 +1,107 @@ +require 'gitlab/markdown' +require 'html/pipeline/filter' +require 'uri' + +module Gitlab + module Markdown + # HTML Filter for auto-linking URLs in HTML. + # + # Based on HTML::Pipeline::AutolinkFilter + # + # Context options: + # :autolink - Boolean, skips all processing done by this filter when false + # :link_attr - Hash of attributes for the generated links + # + class AutolinkFilter < HTML::Pipeline::Filter + include ActionView::Helpers::TagHelper + + # Pattern to match text that should be autolinked. + # + # A URI scheme begins with a letter and may contain letters, numbers, + # plus, period and hyphen. Schemes are case-insensitive but we're being + # picky here and allowing only lowercase for autolinks. + # + # See http://en.wikipedia.org/wiki/URI_scheme + # + # The negative lookbehind ensures that users can paste a URL followed by a + # period or comma for punctuation without those characters being included + # in the generated link. + # + # Rubular: http://rubular.com/r/cxjPyZc7Sb + LINK_PATTERN = %r{([a-z][a-z0-9\+\.-]+://\S+)(?#{commit_range}" + # end + # + # text - String text to search. + # + # Yields the String match, the String commit range, and an optional String + # of the external project reference. + # + # Returns a String replaced with the return of the block. + def self.references_in(text) + text.gsub(CommitRange.reference_pattern) do |match| + yield match, $~[:commit_range], $~[:project] + end + end + + def self.referenced_by(node) + project = Project.find(node.attr("data-project")) rescue nil + return unless project + + id = node.attr("data-commit-range") + range = CommitRange.new(id, project) + + return unless range.valid_commits? + + { commit_range: range } + end + + def initialize(*args) + super + + @commit_map = {} + end + + def call + replace_text_nodes_matching(CommitRange.reference_pattern) do |content| + commit_range_link_filter(content) + end + end + + # Replace commit range references in text with links to compare the commit + # ranges. + # + # text - String text to replace references in. + # + # Returns a String with commit range references replaced with links. All + # links have `gfm` and `gfm-commit_range` class names attached for + # styling. + def commit_range_link_filter(text) + self.class.references_in(text) do |match, id, project_ref| + project = self.project_from_ref(project_ref) + + range = CommitRange.new(id, project) + + if range.valid_commits? + url = url_for_commit_range(project, range) + + title = range.reference_title + klass = reference_class(:commit_range) + data = data_attribute(project: project.id, commit_range: id) + + project_ref += '@' if project_ref + + %(#{project_ref}#{range}) + else + match + end + end + end + + def url_for_commit_range(project, range) + h = Gitlab::Application.routes.url_helpers + h.namespace_project_compare_url(project.namespace, project, + range.to_param.merge(only_path: context[:only_path])) + end + end + end +end diff --git a/lib/gitlab/markdown/filter/commit_reference_filter.rb b/lib/gitlab/markdown/filter/commit_reference_filter.rb new file mode 100644 index 00000000000..8cdbeb1f9cf --- /dev/null +++ b/lib/gitlab/markdown/filter/commit_reference_filter.rb @@ -0,0 +1,88 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + # HTML filter that replaces commit references with links. + # + # This filter supports cross-project references. + class CommitReferenceFilter < ReferenceFilter + include CrossProjectReference + + # Public: Find commit references in text + # + # CommitReferenceFilter.references_in(text) do |match, commit, project_ref| + # "#{commit}" + # end + # + # text - String text to search. + # + # Yields the String match, the String commit identifier, and an optional + # String of the external project reference. + # + # Returns a String replaced with the return of the block. + def self.references_in(text) + text.gsub(Commit.reference_pattern) do |match| + yield match, $~[:commit], $~[:project] + end + end + + def self.referenced_by(node) + project = Project.find(node.attr("data-project")) rescue nil + return unless project + + id = node.attr("data-commit") + commit = commit_from_ref(project, id) + + return unless commit + + { commit: commit } + end + + def call + replace_text_nodes_matching(Commit.reference_pattern) do |content| + commit_link_filter(content) + end + end + + # Replace commit references in text with links to the commit specified. + # + # text - String text to replace references in. + # + # Returns a String with commit references replaced with links. All links + # have `gfm` and `gfm-commit` class names attached for styling. + def commit_link_filter(text) + self.class.references_in(text) do |match, id, project_ref| + project = self.project_from_ref(project_ref) + + if commit = self.class.commit_from_ref(project, id) + url = url_for_commit(project, commit) + + title = escape_once(commit.link_title) + klass = reference_class(:commit) + data = data_attribute(project: project.id, commit: id) + + project_ref += '@' if project_ref + + %(#{project_ref}#{commit.short_id}) + else + match + end + end + end + + def self.commit_from_ref(project, id) + if project && project.valid_repo? + project.commit(id) + end + end + + def url_for_commit(project, commit) + h = Gitlab::Application.routes.url_helpers + h.namespace_project_commit_url(project.namespace, project, commit, + only_path: context[:only_path]) + end + end + end +end diff --git a/lib/gitlab/markdown/filter/emoji_filter.rb b/lib/gitlab/markdown/filter/emoji_filter.rb new file mode 100644 index 00000000000..da10e4d3760 --- /dev/null +++ b/lib/gitlab/markdown/filter/emoji_filter.rb @@ -0,0 +1,80 @@ +require 'action_controller' +require 'gitlab/markdown' +require 'gitlab_emoji' +require 'html/pipeline/filter' + +module Gitlab + module Markdown + # HTML filter that replaces :emoji: with images. + # + # Based on HTML::Pipeline::EmojiFilter + # + # Context options: + # :asset_root + # :asset_host + class EmojiFilter < HTML::Pipeline::Filter + IGNORED_ANCESTOR_TAGS = %w(pre code tt).to_set + + def call + search_text_nodes(doc).each do |node| + content = node.to_html + next unless content.include?(':') + next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS) + + html = emoji_image_filter(content) + + next if html == content + + node.replace(html) + end + + doc + end + + # Replace :emoji: with corresponding images. + # + # text - String text to replace :emoji: in. + # + # Returns a String with :emoji: replaced with images. + def emoji_image_filter(text) + text.gsub(emoji_pattern) do |match| + name = $1 + ":#{name}:" + end + end + + private + + def emoji_url(name) + emoji_path = "emoji/#{emoji_filename(name)}" + if context[:asset_host] + # Asset host is specified. + url_to_image(emoji_path) + elsif context[:asset_root] + # Gitlab url is specified + File.join(context[:asset_root], url_to_image(emoji_path)) + else + # All other cases + url_to_image(emoji_path) + end + end + + def url_to_image(image) + ActionController::Base.helpers.url_to_image(image) + end + + # Build a regexp that matches all valid :emoji: names. + def self.emoji_pattern + @emoji_pattern ||= /:(#{Emoji.emojis_names.map { |name| Regexp.escape(name) }.join('|')}):/ + end + + def emoji_pattern + self.class.emoji_pattern + end + + def emoji_filename(name) + "#{Emoji.emoji_filename(name)}.png" + end + end + end +end diff --git a/lib/gitlab/markdown/filter/external_issue_reference_filter.rb b/lib/gitlab/markdown/filter/external_issue_reference_filter.rb new file mode 100644 index 00000000000..8f86f13976a --- /dev/null +++ b/lib/gitlab/markdown/filter/external_issue_reference_filter.rb @@ -0,0 +1,63 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + # HTML filter that replaces external issue tracker references with links. + # References are ignored if the project doesn't use an external issue + # tracker. + class ExternalIssueReferenceFilter < ReferenceFilter + # Public: Find `JIRA-123` issue references in text + # + # ExternalIssueReferenceFilter.references_in(text) do |match, issue| + # "##{issue}" + # end + # + # text - String text to search. + # + # Yields the String match and the String issue reference. + # + # Returns a String replaced with the return of the block. + def self.references_in(text) + text.gsub(ExternalIssue.reference_pattern) do |match| + yield match, $~[:issue] + end + end + + def call + # Early return if the project isn't using an external tracker + return doc if project.nil? || project.default_issues_tracker? + + replace_text_nodes_matching(ExternalIssue.reference_pattern) do |content| + issue_link_filter(content) + end + end + + # Replace `JIRA-123` issue references in text with links to the referenced + # issue's details page. + # + # text - String text to replace references in. + # + # Returns a String with `JIRA-123` references replaced with links. All + # links have `gfm` and `gfm-issue` class names attached for styling. + def issue_link_filter(text) + project = context[:project] + + self.class.references_in(text) do |match, issue| + url = url_for_issue(issue, project, only_path: context[:only_path]) + + title = escape_once("Issue in #{project.external_issue_tracker.title}") + klass = reference_class(:issue) + data = data_attribute(project: project.id) + + %(#{match}) + end + end + + def url_for_issue(*args) + IssuesHelper.url_for_issue(*args) + end + end + end +end diff --git a/lib/gitlab/markdown/filter/external_link_filter.rb b/lib/gitlab/markdown/filter/external_link_filter.rb new file mode 100644 index 00000000000..29e51b6ade6 --- /dev/null +++ b/lib/gitlab/markdown/filter/external_link_filter.rb @@ -0,0 +1,34 @@ +require 'gitlab/markdown' +require 'html/pipeline/filter' + +module Gitlab + module Markdown + # HTML Filter to add a `rel="nofollow"` attribute to external links + # + class ExternalLinkFilter < HTML::Pipeline::Filter + def call + doc.search('a').each do |node| + next unless node.has_attribute?('href') + + link = node.attribute('href').value + + # Skip non-HTTP(S) links + next unless link.start_with?('http') + + # Skip internal links + next if link.start_with?(internal_url) + + node.set_attribute('rel', 'nofollow') + end + + doc + end + + private + + def internal_url + @internal_url ||= Gitlab.config.gitlab.url + end + end + end +end diff --git a/lib/gitlab/markdown/filter/issue_reference_filter.rb b/lib/gitlab/markdown/filter/issue_reference_filter.rb new file mode 100644 index 00000000000..1ed69e2f431 --- /dev/null +++ b/lib/gitlab/markdown/filter/issue_reference_filter.rb @@ -0,0 +1,23 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + # HTML filter that replaces issue references with links. References to + # issues that do not exist are ignored. + # + # This filter supports cross-project references. + class IssueReferenceFilter < AbstractReferenceFilter + def self.object_class + Issue + end + + def find_object(project, id) + project.get_issue(id) + end + + def url_for_object(issue, project) + IssuesHelper.url_for_issue(issue.iid, project, only_path: context[:only_path]) + end + end + end +end diff --git a/lib/gitlab/markdown/filter/label_reference_filter.rb b/lib/gitlab/markdown/filter/label_reference_filter.rb new file mode 100644 index 00000000000..618acb7a578 --- /dev/null +++ b/lib/gitlab/markdown/filter/label_reference_filter.rb @@ -0,0 +1,87 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + # HTML filter that replaces label references with links. + class LabelReferenceFilter < ReferenceFilter + # Public: Find label references in text + # + # LabelReferenceFilter.references_in(text) do |match, id, name| + # "#{Label.find(id)}" + # end + # + # text - String text to search. + # + # Yields the String match, an optional Integer label ID, and an optional + # String label name. + # + # Returns a String replaced with the return of the block. + def self.references_in(text) + text.gsub(Label.reference_pattern) do |match| + yield match, $~[:label_id].to_i, $~[:label_name] + end + end + + def self.referenced_by(node) + { label: LazyReference.new(Label, node.attr("data-label")) } + end + + def call + replace_text_nodes_matching(Label.reference_pattern) do |content| + label_link_filter(content) + end + end + + # Replace label references in text with links to the label specified. + # + # text - String text to replace references in. + # + # Returns a String with label references replaced with links. All links + # have `gfm` and `gfm-label` class names attached for styling. + def label_link_filter(text) + project = context[:project] + + self.class.references_in(text) do |match, id, name| + params = label_params(id, name) + + if label = project.labels.find_by(params) + url = url_for_label(project, label) + klass = reference_class(:label) + data = data_attribute(project: project.id, label: label.id) + + %(#{render_colored_label(label)}) + else + match + end + end + end + + def url_for_label(project, label) + h = Gitlab::Application.routes.url_helpers + h.namespace_project_issues_path(project.namespace, project, + label_name: label.name, + only_path: context[:only_path]) + end + + def render_colored_label(label) + LabelsHelper.render_colored_label(label) + end + + # Parameters to pass to `Label.find_by` based on the given arguments + # + # id - Integer ID to pass. If present, returns {id: id} + # name - String name to pass. If `id` is absent, finds by name without + # surrounding quotes. + # + # Returns a Hash. + def label_params(id, name) + if name + { name: name.tr('"', '') } + else + { id: id } + end + end + end + end +end diff --git a/lib/gitlab/markdown/filter/markdown_filter.rb b/lib/gitlab/markdown/filter/markdown_filter.rb new file mode 100644 index 00000000000..921e2a0794e --- /dev/null +++ b/lib/gitlab/markdown/filter/markdown_filter.rb @@ -0,0 +1,39 @@ +module Gitlab + module Markdown + class MarkdownFilter < HTML::Pipeline::TextFilter + def initialize(text, context = nil, result = nil) + super text, context, result + @text = @text.gsub "\r", '' + end + + def call + html = self.class.renderer.render(@text) + html.rstrip! + html + end + + private + + def self.redcarpet_options + # https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use + @redcarpet_options ||= { + fenced_code_blocks: true, + footnotes: true, + lax_spacing: true, + no_intra_emphasis: true, + space_after_headers: true, + strikethrough: true, + superscript: true, + tables: true + }.freeze + end + + def self.renderer + @renderer ||= begin + renderer = Redcarpet::Render::HTML.new + Redcarpet::Markdown.new(renderer, redcarpet_options) + end + end + end + end +end diff --git a/lib/gitlab/markdown/filter/merge_request_reference_filter.rb b/lib/gitlab/markdown/filter/merge_request_reference_filter.rb new file mode 100644 index 00000000000..1f47f03c94e --- /dev/null +++ b/lib/gitlab/markdown/filter/merge_request_reference_filter.rb @@ -0,0 +1,25 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + # HTML filter that replaces merge request references with links. References + # to merge requests that do not exist are ignored. + # + # This filter supports cross-project references. + class MergeRequestReferenceFilter < AbstractReferenceFilter + def self.object_class + MergeRequest + end + + def find_object(project, id) + project.merge_requests.find_by(iid: id) + end + + def url_for_object(mr, project) + h = Gitlab::Application.routes.url_helpers + h.namespace_project_merge_request_url(project.namespace, project, mr, + only_path: context[:only_path]) + end + end + end +end diff --git a/lib/gitlab/markdown/filter/redactor_filter.rb b/lib/gitlab/markdown/filter/redactor_filter.rb new file mode 100644 index 00000000000..a1f3a8a8ebf --- /dev/null +++ b/lib/gitlab/markdown/filter/redactor_filter.rb @@ -0,0 +1,40 @@ +require 'gitlab/markdown' +require 'html/pipeline/filter' + +module Gitlab + module Markdown + # HTML filter that removes references to records that the current user does + # not have permission to view. + # + # Expected to be run in its own post-processing pipeline. + # + class RedactorFilter < HTML::Pipeline::Filter + def call + doc.css('a.gfm').each do |node| + unless user_can_reference?(node) + node.replace(node.text) + end + end + + doc + end + + private + + def user_can_reference?(node) + if node.has_attribute?('data-reference-filter') + reference_type = node.attr('data-reference-filter') + reference_filter = reference_type.constantize + + reference_filter.user_can_reference?(current_user, node, context) + else + true + end + end + + def current_user + context[:current_user] + end + end + end +end diff --git a/lib/gitlab/markdown/filter/reference_gatherer_filter.rb b/lib/gitlab/markdown/filter/reference_gatherer_filter.rb new file mode 100644 index 00000000000..00f983675e6 --- /dev/null +++ b/lib/gitlab/markdown/filter/reference_gatherer_filter.rb @@ -0,0 +1,63 @@ +require 'gitlab/markdown' +require 'html/pipeline/filter' + +module Gitlab + module Markdown + # HTML filter that gathers all referenced records that the current user has + # permission to view. + # + # Expected to be run in its own post-processing pipeline. + # + class ReferenceGathererFilter < HTML::Pipeline::Filter + def initialize(*) + super + + result[:references] ||= Hash.new { |hash, type| hash[type] = [] } + end + + def call + doc.css('a.gfm').each do |node| + gather_references(node) + end + + load_lazy_references unless context[:load_lazy_references] == false + + doc + end + + private + + def gather_references(node) + return unless node.has_attribute?('data-reference-filter') + + reference_type = node.attr('data-reference-filter') + reference_filter = reference_type.constantize + + return if context[:reference_filter] && reference_filter != context[:reference_filter] + + return unless reference_filter.user_can_reference?(current_user, node, context) + + references = reference_filter.referenced_by(node) + return unless references + + references.each do |type, values| + Array.wrap(values).each do |value| + result[:references][type] << value + end + end + end + + # Will load all references of one type using one query. + def load_lazy_references + refs = result[:references] + refs.each do |type, values| + refs[type] = ReferenceFilter::LazyReference.load(values) + end + end + + def current_user + context[:current_user] + end + end + end +end diff --git a/lib/gitlab/markdown/filter/relative_link_filter.rb b/lib/gitlab/markdown/filter/relative_link_filter.rb new file mode 100644 index 00000000000..81f60120fcd --- /dev/null +++ b/lib/gitlab/markdown/filter/relative_link_filter.rb @@ -0,0 +1,157 @@ +require 'gitlab/markdown' +require 'html/pipeline/filter' +require 'uri' + +module Gitlab + module Markdown + # HTML filter that "fixes" relative links to files in a repository. + # + # Context options: + # :commit + # :project + # :project_wiki + # :ref + # :requested_path + class RelativeLinkFilter < HTML::Pipeline::Filter + def call + return doc unless linkable_files? + + doc.search('a:not(.gfm)').each do |el| + process_link_attr el.attribute('href') + end + + doc.search('img').each do |el| + process_link_attr el.attribute('src') + end + + doc + end + + protected + + def linkable_files? + context[:project_wiki].nil? && repository.try(:exists?) && !repository.empty? + end + + def process_link_attr(html_attr) + return if html_attr.blank? + + uri = URI(html_attr.value) + if uri.relative? && uri.path.present? + html_attr.value = rebuild_relative_uri(uri).to_s + end + rescue URI::Error + # noop + end + + def rebuild_relative_uri(uri) + file_path = relative_file_path(uri.path) + + uri.path = [ + relative_url_root, + context[:project].path_with_namespace, + path_type(file_path), + ref || context[:project].default_branch, # if no ref exists, point to the default branch + file_path + ].compact.join('/').squeeze('/').chomp('/') + + uri + end + + def relative_file_path(path) + nested_path = build_relative_path(path, context[:requested_path]) + file_exists?(nested_path) ? nested_path : path + end + + # Convert a relative path into its correct location based on the currently + # requested path + # + # path - Relative path String + # request_path - Currently-requested path String + # + # Examples: + # + # # File in the same directory as the current 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 path unless request_path + + parts = request_path.split('/') + parts.pop if path_type(request_path) != 'tree' + + while parts.length > 1 && path.start_with?('../') + parts.pop + path.sub!('../', '') + end + + parts.push(path).join('/') + end + + def file_exists?(path) + return false if path.nil? + repository.blob_at(current_sha, path).present? || + repository.tree(current_sha, path).entries.any? + end + + # Get the type of the given path + # + # path - String path to check + # + # Examples: + # + # path_type('doc/README.md') # => 'blob' + # path_type('doc/logo.png') # => 'raw' + # path_type('doc/api') # => 'tree' + # + # Returns a String + def path_type(path) + unescaped_path = Addressable::URI.unescape(path) + + if tree?(unescaped_path) + 'tree' + elsif image?(unescaped_path) + 'raw' + else + 'blob' + end + end + + def tree?(path) + repository.tree(current_sha, path).entries.any? + end + + def image?(path) + repository.blob_at(current_sha, path).try(:image?) + end + + def current_sha + context[:commit].try(:id) || + ref ? repository.commit(ref).try(:sha) : repository.head_commit.sha + end + + def relative_url_root + Gitlab.config.gitlab.relative_url_root.presence || '/' + end + + def ref + context[:ref] + end + + def repository + context[:project].try(:repository) + end + end + end +end diff --git a/lib/gitlab/markdown/filter/sanitization_filter.rb b/lib/gitlab/markdown/filter/sanitization_filter.rb new file mode 100644 index 00000000000..cf153f30622 --- /dev/null +++ b/lib/gitlab/markdown/filter/sanitization_filter.rb @@ -0,0 +1,99 @@ +require 'gitlab/markdown' +require 'html/pipeline/filter' +require 'html/pipeline/sanitization_filter' + +module Gitlab + module Markdown + # Sanitize HTML + # + # Extends HTML::Pipeline::SanitizationFilter with a custom whitelist. + class SanitizationFilter < HTML::Pipeline::SanitizationFilter + def whitelist + # Descriptions are more heavily sanitized, allowing only a few elements. + # See http://git.io/vkuAN + if context[:inline_sanitization] + whitelist = LIMITED + whitelist[:elements] -= %w(pre code img ol ul li) + else + whitelist = super + end + + customize_whitelist(whitelist) + + whitelist + end + + private + + def customized?(transformers) + transformers.last.source_location[0] == __FILE__ + end + + def customize_whitelist(whitelist) + # Only push these customizations once + return if customized?(whitelist[:transformers]) + + # Allow code highlighting + whitelist[:attributes]['pre'] = %w(class) + whitelist[:attributes]['span'] = %w(class) + + # Allow table alignment + whitelist[:attributes]['th'] = %w(style) + whitelist[:attributes]['td'] = %w(style) + + # Allow span elements + whitelist[:elements].push('span') + + # Allow any protocol in `a` elements... + whitelist[:protocols].delete('a') + + # ...but then remove links with the `javascript` protocol + whitelist[:transformers].push(remove_javascript_links) + + # Remove `rel` attribute from `a` elements + whitelist[:transformers].push(remove_rel) + + # Remove `class` attribute from non-highlight spans + whitelist[:transformers].push(clean_spans) + + whitelist + end + + def remove_javascript_links + lambda do |env| + node = env[:node] + + return unless node.name == 'a' + return unless node.has_attribute?('href') + + if node['href'].start_with?('javascript', ':javascript') + node.remove_attribute('href') + end + end + end + + def remove_rel + lambda do |env| + if env[:node_name] == 'a' + env[:node].remove_attribute('rel') + end + end + end + + def clean_spans + lambda do |env| + node = env[:node] + + return unless node.name == 'span' + return unless node.has_attribute?('class') + + unless has_ancestor?(node, 'pre') + node.remove_attribute('class') + end + + { node_whitelist: [node] } + end + end + end + end +end diff --git a/lib/gitlab/markdown/filter/snippet_reference_filter.rb b/lib/gitlab/markdown/filter/snippet_reference_filter.rb new file mode 100644 index 00000000000..f7bd07c2a34 --- /dev/null +++ b/lib/gitlab/markdown/filter/snippet_reference_filter.rb @@ -0,0 +1,25 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + # HTML filter that replaces snippet references with links. References to + # snippets that do not exist are ignored. + # + # This filter supports cross-project references. + class SnippetReferenceFilter < AbstractReferenceFilter + def self.object_class + Snippet + end + + def find_object(project, id) + project.snippets.find_by(id: id) + end + + def url_for_object(snippet, project) + h = Gitlab::Application.routes.url_helpers + h.namespace_project_snippet_url(project.namespace, project, snippet, + only_path: context[:only_path]) + end + end + end +end diff --git a/lib/gitlab/markdown/filter/syntax_highlight_filter.rb b/lib/gitlab/markdown/filter/syntax_highlight_filter.rb new file mode 100644 index 00000000000..8597e02f0de --- /dev/null +++ b/lib/gitlab/markdown/filter/syntax_highlight_filter.rb @@ -0,0 +1,45 @@ +require 'gitlab/markdown' +require 'html/pipeline/filter' +require 'rouge/plugins/redcarpet' + +module Gitlab + module Markdown + # HTML Filter to highlight fenced code blocks + # + class SyntaxHighlightFilter < HTML::Pipeline::Filter + include Rouge::Plugins::Redcarpet + + def call + doc.search('pre > code').each do |node| + highlight_node(node) + end + + doc + end + + def highlight_node(node) + language = node.attr('class') + code = node.text + + begin + highlighted = block_code(code, language) + rescue + # Gracefully handle syntax highlighter bugs/errors to ensure + # users can still access an issue/comment/etc. + highlighted = "
#{code}
" + end + + # Replace the parent `pre` element with the entire highlighted block + node.parent.replace(highlighted) + end + + private + + # Override Rouge::Plugins::Redcarpet#rouge_formatter + def rouge_formatter(lexer) + Rouge::Formatters::HTMLGitlab.new( + cssclass: "code highlight js-syntax-highlight #{lexer.tag}") + end + end + end +end diff --git a/lib/gitlab/markdown/filter/table_of_contents_filter.rb b/lib/gitlab/markdown/filter/table_of_contents_filter.rb new file mode 100644 index 00000000000..bbb3bf7fc8b --- /dev/null +++ b/lib/gitlab/markdown/filter/table_of_contents_filter.rb @@ -0,0 +1,63 @@ +require 'gitlab/markdown' +require 'html/pipeline/filter' + +module Gitlab + module Markdown + # HTML filter that adds an anchor child element to all Headers in a + # document, so that they can be linked to. + # + # Generates the Table of Contents with links to each header. See Results. + # + # Based on HTML::Pipeline::TableOfContentsFilter. + # + # Context options: + # :no_header_anchors - Skips all processing done by this filter. + # + # Results: + # :toc - String containing Table of Contents data as a `ul` element with + # `li` child elements. + class TableOfContentsFilter < HTML::Pipeline::Filter + PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u + + def call + return doc if context[:no_header_anchors] + + result[:toc] = "" + + headers = Hash.new(0) + + doc.css('h1, h2, h3, h4, h5, h6').each do |node| + text = node.text + + id = text.downcase + id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation + id.gsub!(' ', '-') # replace spaces with dash + id.squeeze!('-') # replace multiple dashes with one + + uniq = (headers[id] > 0) ? "-#{headers[id]}" : '' + headers[id] += 1 + + if header_content = node.children.first + href = "#{id}#{uniq}" + push_toc(href, text) + header_content.add_previous_sibling(anchor_tag(href)) + end + end + + result[:toc] = %Q{
    \n#{result[:toc]}
} unless result[:toc].empty? + + doc + end + + private + + def anchor_tag(href) + %Q{} + end + + def push_toc(href, text) + result[:toc] << %Q{
  • #{text}
  • \n} + end + end + end +end diff --git a/lib/gitlab/markdown/filter/task_list_filter.rb b/lib/gitlab/markdown/filter/task_list_filter.rb new file mode 100644 index 00000000000..2f133ae8500 --- /dev/null +++ b/lib/gitlab/markdown/filter/task_list_filter.rb @@ -0,0 +1,24 @@ +require 'gitlab/markdown' +require 'task_list/filter' + +module Gitlab + module Markdown + # Work around a bug in the default TaskList::Filter that adds a `task-list` + # class to every list element, regardless of whether or not it contains a + # task list. + # + # This is a (hopefully) temporary fix, pending a new release of the + # task_list gem. + # + # See https://github.com/github/task_list/pull/60 + class TaskListFilter < TaskList::Filter + def add_css_class(node, *new_class_names) + if new_class_names.include?('task-list') + super if node.children.any? { |c| c['class'] == 'task-list-item' } + else + super + end + end + end + end +end diff --git a/lib/gitlab/markdown/filter/upload_link_filter.rb b/lib/gitlab/markdown/filter/upload_link_filter.rb new file mode 100644 index 00000000000..fbada73ab86 --- /dev/null +++ b/lib/gitlab/markdown/filter/upload_link_filter.rb @@ -0,0 +1,47 @@ +require 'gitlab/markdown' +require 'html/pipeline/filter' +require 'uri' + +module Gitlab + module Markdown + # HTML filter that "fixes" relative upload links to files. + # Context options: + # :project (required) - Current project + # + class UploadLinkFilter < HTML::Pipeline::Filter + def call + doc.search('a').each do |el| + process_link_attr el.attribute('href') + end + + doc.search('img').each do |el| + process_link_attr el.attribute('src') + end + + doc + end + + protected + + def process_link_attr(html_attr) + return if html_attr.blank? + + uri = html_attr.value + if uri.starts_with?("/uploads/") + html_attr.value = build_url(uri).to_s + end + end + + def build_url(uri) + File.join(Gitlab.config.gitlab.url, context[:project].path_with_namespace, uri) + end + + # Ensure that a :project key exists in context + # + # Note that while the key might exist, its value could be nil! + def validate + needs :project + end + end + end +end diff --git a/lib/gitlab/markdown/filter/user_reference_filter.rb b/lib/gitlab/markdown/filter/user_reference_filter.rb new file mode 100644 index 00000000000..ab5e1f6fe9e --- /dev/null +++ b/lib/gitlab/markdown/filter/user_reference_filter.rb @@ -0,0 +1,125 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + # HTML filter that replaces user or group references with links. + # + # A special `@all` reference is also supported. + class UserReferenceFilter < ReferenceFilter + # Public: Find `@user` user references in text + # + # UserReferenceFilter.references_in(text) do |match, username| + # "@#{user}" + # end + # + # text - String text to search. + # + # Yields the String match, and the String user name. + # + # Returns a String replaced with the return of the block. + def self.references_in(text) + text.gsub(User.reference_pattern) do |match| + yield match, $~[:user] + end + end + + def self.referenced_by(node) + if node.has_attribute?('data-group') + group = Group.find(node.attr('data-group')) rescue nil + return unless group + + { user: group.users } + elsif node.has_attribute?('data-user') + { user: LazyReference.new(User, node.attr('data-user')) } + elsif node.has_attribute?('data-project') + project = Project.find(node.attr('data-project')) rescue nil + return unless project + + { user: project.team.members.flatten } + end + end + + def self.user_can_reference?(user, node, context) + if node.has_attribute?('data-group') + group = Group.find(node.attr('data-group')) rescue nil + Ability.abilities.allowed?(user, :read_group, group) + else + super + end + end + + def call + replace_text_nodes_matching(User.reference_pattern) do |content| + user_link_filter(content) + end + end + + # Replace `@user` user references in text with links to the referenced + # user's profile page. + # + # text - String text to replace references in. + # + # Returns a String with `@user` references replaced with links. All links + # have `gfm` and `gfm-project_member` class names attached for styling. + def user_link_filter(text) + self.class.references_in(text) do |match, username| + if username == 'all' + link_to_all + elsif namespace = Namespace.find_by(path: username) + link_to_namespace(namespace) || match + else + match + end + end + end + + private + + def urls + Gitlab::Application.routes.url_helpers + end + + def link_class + reference_class(:project_member) + end + + def link_to_all + project = context[:project] + url = urls.namespace_project_url(project.namespace, project, + only_path: context[:only_path]) + data = data_attribute(project: project.id) + text = User.reference_prefix + 'all' + + link_tag(url, data, text) + end + + def link_to_namespace(namespace) + if namespace.is_a?(Group) + link_to_group(namespace.path, namespace) + else + link_to_user(namespace.path, namespace) + end + end + + def link_to_group(group, namespace) + url = urls.group_url(group, only_path: context[:only_path]) + data = data_attribute(group: namespace.id) + text = Group.reference_prefix + group + + link_tag(url, data, text) + end + + def link_to_user(user, namespace) + url = urls.user_url(user, only_path: context[:only_path]) + data = data_attribute(user: namespace.owner_id) + text = User.reference_prefix + user + + link_tag(url, data, text) + end + + def link_tag(url, data, text) + %(#{text}) + end + end + end +end diff --git a/lib/gitlab/markdown/full_pipeline.rb b/lib/gitlab/markdown/full_pipeline.rb deleted file mode 100644 index 553e9367c1c..00000000000 --- a/lib/gitlab/markdown/full_pipeline.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - class FullPipeline < CombinedPipeline.new(PlainMarkdownPipeline, GfmPipeline) - - end - end -end diff --git a/lib/gitlab/markdown/gfm_pipeline.rb b/lib/gitlab/markdown/gfm_pipeline.rb deleted file mode 100644 index ca90bd75d77..00000000000 --- a/lib/gitlab/markdown/gfm_pipeline.rb +++ /dev/null @@ -1,41 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - class GfmPipeline < Pipeline - def self.filters - @filters ||= [ - Gitlab::Markdown::SyntaxHighlightFilter, - Gitlab::Markdown::SanitizationFilter, - - Gitlab::Markdown::UploadLinkFilter, - Gitlab::Markdown::EmojiFilter, - Gitlab::Markdown::TableOfContentsFilter, - Gitlab::Markdown::AutolinkFilter, - Gitlab::Markdown::ExternalLinkFilter, - - Gitlab::Markdown::UserReferenceFilter, - Gitlab::Markdown::IssueReferenceFilter, - Gitlab::Markdown::ExternalIssueReferenceFilter, - Gitlab::Markdown::MergeRequestReferenceFilter, - Gitlab::Markdown::SnippetReferenceFilter, - Gitlab::Markdown::CommitRangeReferenceFilter, - Gitlab::Markdown::CommitReferenceFilter, - Gitlab::Markdown::LabelReferenceFilter, - - Gitlab::Markdown::TaskListFilter - ] - end - - def self.transform_context(context) - context.merge( - only_path: true, - - # EmojiFilter - asset_host: Gitlab::Application.config.asset_host, - asset_root: Gitlab.config.gitlab.base_url - ) - end - end - end -end diff --git a/lib/gitlab/markdown/issue_reference_filter.rb b/lib/gitlab/markdown/issue_reference_filter.rb deleted file mode 100644 index 1ed69e2f431..00000000000 --- a/lib/gitlab/markdown/issue_reference_filter.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - # HTML filter that replaces issue references with links. References to - # issues that do not exist are ignored. - # - # This filter supports cross-project references. - class IssueReferenceFilter < AbstractReferenceFilter - def self.object_class - Issue - end - - def find_object(project, id) - project.get_issue(id) - end - - def url_for_object(issue, project) - IssuesHelper.url_for_issue(issue.iid, project, only_path: context[:only_path]) - end - end - end -end diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb deleted file mode 100644 index 618acb7a578..00000000000 --- a/lib/gitlab/markdown/label_reference_filter.rb +++ /dev/null @@ -1,87 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - # HTML filter that replaces label references with links. - class LabelReferenceFilter < ReferenceFilter - # Public: Find label references in text - # - # LabelReferenceFilter.references_in(text) do |match, id, name| - # "#{Label.find(id)}" - # end - # - # text - String text to search. - # - # Yields the String match, an optional Integer label ID, and an optional - # String label name. - # - # Returns a String replaced with the return of the block. - def self.references_in(text) - text.gsub(Label.reference_pattern) do |match| - yield match, $~[:label_id].to_i, $~[:label_name] - end - end - - def self.referenced_by(node) - { label: LazyReference.new(Label, node.attr("data-label")) } - end - - def call - replace_text_nodes_matching(Label.reference_pattern) do |content| - label_link_filter(content) - end - end - - # Replace label references in text with links to the label specified. - # - # text - String text to replace references in. - # - # Returns a String with label references replaced with links. All links - # have `gfm` and `gfm-label` class names attached for styling. - def label_link_filter(text) - project = context[:project] - - self.class.references_in(text) do |match, id, name| - params = label_params(id, name) - - if label = project.labels.find_by(params) - url = url_for_label(project, label) - klass = reference_class(:label) - data = data_attribute(project: project.id, label: label.id) - - %(#{render_colored_label(label)}) - else - match - end - end - end - - def url_for_label(project, label) - h = Gitlab::Application.routes.url_helpers - h.namespace_project_issues_path(project.namespace, project, - label_name: label.name, - only_path: context[:only_path]) - end - - def render_colored_label(label) - LabelsHelper.render_colored_label(label) - end - - # Parameters to pass to `Label.find_by` based on the given arguments - # - # id - Integer ID to pass. If present, returns {id: id} - # name - String name to pass. If `id` is absent, finds by name without - # surrounding quotes. - # - # Returns a Hash. - def label_params(id, name) - if name - { name: name.tr('"', '') } - else - { id: id } - end - end - end - end -end diff --git a/lib/gitlab/markdown/markdown_filter.rb b/lib/gitlab/markdown/markdown_filter.rb deleted file mode 100644 index 921e2a0794e..00000000000 --- a/lib/gitlab/markdown/markdown_filter.rb +++ /dev/null @@ -1,39 +0,0 @@ -module Gitlab - module Markdown - class MarkdownFilter < HTML::Pipeline::TextFilter - def initialize(text, context = nil, result = nil) - super text, context, result - @text = @text.gsub "\r", '' - end - - def call - html = self.class.renderer.render(@text) - html.rstrip! - html - end - - private - - def self.redcarpet_options - # https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use - @redcarpet_options ||= { - fenced_code_blocks: true, - footnotes: true, - lax_spacing: true, - no_intra_emphasis: true, - space_after_headers: true, - strikethrough: true, - superscript: true, - tables: true - }.freeze - end - - def self.renderer - @renderer ||= begin - renderer = Redcarpet::Render::HTML.new - Redcarpet::Markdown.new(renderer, redcarpet_options) - end - end - end - end -end diff --git a/lib/gitlab/markdown/merge_request_reference_filter.rb b/lib/gitlab/markdown/merge_request_reference_filter.rb deleted file mode 100644 index 1f47f03c94e..00000000000 --- a/lib/gitlab/markdown/merge_request_reference_filter.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - # HTML filter that replaces merge request references with links. References - # to merge requests that do not exist are ignored. - # - # This filter supports cross-project references. - class MergeRequestReferenceFilter < AbstractReferenceFilter - def self.object_class - MergeRequest - end - - def find_object(project, id) - project.merge_requests.find_by(iid: id) - end - - def url_for_object(mr, project) - h = Gitlab::Application.routes.url_helpers - h.namespace_project_merge_request_url(project.namespace, project, mr, - only_path: context[:only_path]) - end - end - end -end diff --git a/lib/gitlab/markdown/note_pipeline.rb b/lib/gitlab/markdown/note_pipeline.rb deleted file mode 100644 index a8bf5f42d8e..00000000000 --- a/lib/gitlab/markdown/note_pipeline.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - class NotePipeline < FullPipeline - def self.transform_context(context) - super(context).merge( - # TableOfContentsFilter - no_header_anchors: true - ) - end - end - end -end diff --git a/lib/gitlab/markdown/pipeline.rb b/lib/gitlab/markdown/pipeline.rb index 3c0b676a073..d683756f95a 100644 --- a/lib/gitlab/markdown/pipeline.rb +++ b/lib/gitlab/markdown/pipeline.rb @@ -3,6 +3,11 @@ require 'gitlab/markdown' module Gitlab module Markdown class Pipeline + def self.[](name) + name ||= :full + Markdown.const_get("#{name.to_s.camelize}Pipeline") + end + def self.filters [] end diff --git a/lib/gitlab/markdown/pipeline/asciidoc_pipeline.rb b/lib/gitlab/markdown/pipeline/asciidoc_pipeline.rb new file mode 100644 index 00000000000..6829b4acb95 --- /dev/null +++ b/lib/gitlab/markdown/pipeline/asciidoc_pipeline.rb @@ -0,0 +1,13 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class AsciidocPipeline < Pipeline + def self.filters + [ + Gitlab::Markdown::RelativeLinkFilter + ] + end + end + end +end diff --git a/lib/gitlab/markdown/pipeline/atom_pipeline.rb b/lib/gitlab/markdown/pipeline/atom_pipeline.rb new file mode 100644 index 00000000000..e151f8f5e5a --- /dev/null +++ b/lib/gitlab/markdown/pipeline/atom_pipeline.rb @@ -0,0 +1,14 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class AtomPipeline < FullPipeline + def self.transform_context(context) + super(context).merge( + only_path: false, + xhtml: true + ) + end + end + end +end diff --git a/lib/gitlab/markdown/pipeline/description_pipeline.rb b/lib/gitlab/markdown/pipeline/description_pipeline.rb new file mode 100644 index 00000000000..76f6948af8f --- /dev/null +++ b/lib/gitlab/markdown/pipeline/description_pipeline.rb @@ -0,0 +1,14 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class DescriptionPipeline < FullPipeline + def self.transform_context(context) + super(context).merge( + # SanitizationFilter + inline_sanitization: true + ) + end + end + end +end diff --git a/lib/gitlab/markdown/pipeline/email_pipeline.rb b/lib/gitlab/markdown/pipeline/email_pipeline.rb new file mode 100644 index 00000000000..b88cb790270 --- /dev/null +++ b/lib/gitlab/markdown/pipeline/email_pipeline.rb @@ -0,0 +1,13 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class EmailPipeline < FullPipeline + def self.transform_context(context) + super(context).merge( + only_path: false + ) + end + end + end +end diff --git a/lib/gitlab/markdown/pipeline/full_pipeline.rb b/lib/gitlab/markdown/pipeline/full_pipeline.rb new file mode 100644 index 00000000000..553e9367c1c --- /dev/null +++ b/lib/gitlab/markdown/pipeline/full_pipeline.rb @@ -0,0 +1,9 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class FullPipeline < CombinedPipeline.new(PlainMarkdownPipeline, GfmPipeline) + + end + end +end diff --git a/lib/gitlab/markdown/pipeline/gfm_pipeline.rb b/lib/gitlab/markdown/pipeline/gfm_pipeline.rb new file mode 100644 index 00000000000..ca90bd75d77 --- /dev/null +++ b/lib/gitlab/markdown/pipeline/gfm_pipeline.rb @@ -0,0 +1,41 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class GfmPipeline < Pipeline + def self.filters + @filters ||= [ + Gitlab::Markdown::SyntaxHighlightFilter, + Gitlab::Markdown::SanitizationFilter, + + Gitlab::Markdown::UploadLinkFilter, + Gitlab::Markdown::EmojiFilter, + Gitlab::Markdown::TableOfContentsFilter, + Gitlab::Markdown::AutolinkFilter, + Gitlab::Markdown::ExternalLinkFilter, + + Gitlab::Markdown::UserReferenceFilter, + Gitlab::Markdown::IssueReferenceFilter, + Gitlab::Markdown::ExternalIssueReferenceFilter, + Gitlab::Markdown::MergeRequestReferenceFilter, + Gitlab::Markdown::SnippetReferenceFilter, + Gitlab::Markdown::CommitRangeReferenceFilter, + Gitlab::Markdown::CommitReferenceFilter, + Gitlab::Markdown::LabelReferenceFilter, + + Gitlab::Markdown::TaskListFilter + ] + end + + def self.transform_context(context) + context.merge( + only_path: true, + + # EmojiFilter + asset_host: Gitlab::Application.config.asset_host, + asset_root: Gitlab.config.gitlab.base_url + ) + end + end + end +end diff --git a/lib/gitlab/markdown/pipeline/note_pipeline.rb b/lib/gitlab/markdown/pipeline/note_pipeline.rb new file mode 100644 index 00000000000..a8bf5f42d8e --- /dev/null +++ b/lib/gitlab/markdown/pipeline/note_pipeline.rb @@ -0,0 +1,14 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class NotePipeline < FullPipeline + def self.transform_context(context) + super(context).merge( + # TableOfContentsFilter + no_header_anchors: true + ) + end + end + end +end diff --git a/lib/gitlab/markdown/pipeline/plain_markdown_pipeline.rb b/lib/gitlab/markdown/pipeline/plain_markdown_pipeline.rb new file mode 100644 index 00000000000..0abb93f8a03 --- /dev/null +++ b/lib/gitlab/markdown/pipeline/plain_markdown_pipeline.rb @@ -0,0 +1,13 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class PlainMarkdownPipeline < Pipeline + def self.filters + [ + Gitlab::Markdown::MarkdownFilter + ] + end + end + end +end diff --git a/lib/gitlab/markdown/pipeline/post_process_pipeline.rb b/lib/gitlab/markdown/pipeline/post_process_pipeline.rb new file mode 100644 index 00000000000..60cc32f490e --- /dev/null +++ b/lib/gitlab/markdown/pipeline/post_process_pipeline.rb @@ -0,0 +1,20 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class PostProcessPipeline < Pipeline + def self.filters + [ + Gitlab::Markdown::RelativeLinkFilter, + Gitlab::Markdown::RedactorFilter + ] + end + + def self.transform_context(context) + context.merge( + post_process: true + ) + end + end + end +end diff --git a/lib/gitlab/markdown/pipeline/reference_extraction_pipeline.rb b/lib/gitlab/markdown/pipeline/reference_extraction_pipeline.rb new file mode 100644 index 00000000000..a89ab462bac --- /dev/null +++ b/lib/gitlab/markdown/pipeline/reference_extraction_pipeline.rb @@ -0,0 +1,13 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class ReferenceExtractionPipeline < Pipeline + def self.filters + [ + Gitlab::Markdown::ReferenceGathererFilter + ] + end + end + end +end diff --git a/lib/gitlab/markdown/pipeline/single_line_pipeline.rb b/lib/gitlab/markdown/pipeline/single_line_pipeline.rb new file mode 100644 index 00000000000..2f24927b879 --- /dev/null +++ b/lib/gitlab/markdown/pipeline/single_line_pipeline.rb @@ -0,0 +1,9 @@ +require 'gitlab/markdown' + +module Gitlab + module Markdown + class SingleLinePipeline < GfmPipeline + + end + end +end diff --git a/lib/gitlab/markdown/plain_markdown_pipeline.rb b/lib/gitlab/markdown/plain_markdown_pipeline.rb deleted file mode 100644 index 0abb93f8a03..00000000000 --- a/lib/gitlab/markdown/plain_markdown_pipeline.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - class PlainMarkdownPipeline < Pipeline - def self.filters - [ - Gitlab::Markdown::MarkdownFilter - ] - end - end - end -end diff --git a/lib/gitlab/markdown/post_process_pipeline.rb b/lib/gitlab/markdown/post_process_pipeline.rb deleted file mode 100644 index 60cc32f490e..00000000000 --- a/lib/gitlab/markdown/post_process_pipeline.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - class PostProcessPipeline < Pipeline - def self.filters - [ - Gitlab::Markdown::RelativeLinkFilter, - Gitlab::Markdown::RedactorFilter - ] - end - - def self.transform_context(context) - context.merge( - post_process: true - ) - end - end - end -end diff --git a/lib/gitlab/markdown/redactor_filter.rb b/lib/gitlab/markdown/redactor_filter.rb deleted file mode 100644 index a1f3a8a8ebf..00000000000 --- a/lib/gitlab/markdown/redactor_filter.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'gitlab/markdown' -require 'html/pipeline/filter' - -module Gitlab - module Markdown - # HTML filter that removes references to records that the current user does - # not have permission to view. - # - # Expected to be run in its own post-processing pipeline. - # - class RedactorFilter < HTML::Pipeline::Filter - def call - doc.css('a.gfm').each do |node| - unless user_can_reference?(node) - node.replace(node.text) - end - end - - doc - end - - private - - def user_can_reference?(node) - if node.has_attribute?('data-reference-filter') - reference_type = node.attr('data-reference-filter') - reference_filter = reference_type.constantize - - reference_filter.user_can_reference?(current_user, node, context) - else - true - end - end - - def current_user - context[:current_user] - end - end - end -end diff --git a/lib/gitlab/markdown/reference_extraction_pipeline.rb b/lib/gitlab/markdown/reference_extraction_pipeline.rb deleted file mode 100644 index a89ab462bac..00000000000 --- a/lib/gitlab/markdown/reference_extraction_pipeline.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - class ReferenceExtractionPipeline < Pipeline - def self.filters - [ - Gitlab::Markdown::ReferenceGathererFilter - ] - end - end - end -end diff --git a/lib/gitlab/markdown/reference_filter.rb b/lib/gitlab/markdown/reference_filter.rb index a4c560f578c..22fe4440be3 100644 --- a/lib/gitlab/markdown/reference_filter.rb +++ b/lib/gitlab/markdown/reference_filter.rb @@ -29,6 +29,10 @@ module Gitlab end end + def self.[](name) + Markdown.const_get("#{name.to_s.camelize}ReferenceFilter") + end + def self.user_can_reference?(user, node, context) if node.has_attribute?('data-project') project_id = node.attr('data-project').to_i diff --git a/lib/gitlab/markdown/reference_gatherer_filter.rb b/lib/gitlab/markdown/reference_gatherer_filter.rb deleted file mode 100644 index 00f983675e6..00000000000 --- a/lib/gitlab/markdown/reference_gatherer_filter.rb +++ /dev/null @@ -1,63 +0,0 @@ -require 'gitlab/markdown' -require 'html/pipeline/filter' - -module Gitlab - module Markdown - # HTML filter that gathers all referenced records that the current user has - # permission to view. - # - # Expected to be run in its own post-processing pipeline. - # - class ReferenceGathererFilter < HTML::Pipeline::Filter - def initialize(*) - super - - result[:references] ||= Hash.new { |hash, type| hash[type] = [] } - end - - def call - doc.css('a.gfm').each do |node| - gather_references(node) - end - - load_lazy_references unless context[:load_lazy_references] == false - - doc - end - - private - - def gather_references(node) - return unless node.has_attribute?('data-reference-filter') - - reference_type = node.attr('data-reference-filter') - reference_filter = reference_type.constantize - - return if context[:reference_filter] && reference_filter != context[:reference_filter] - - return unless reference_filter.user_can_reference?(current_user, node, context) - - references = reference_filter.referenced_by(node) - return unless references - - references.each do |type, values| - Array.wrap(values).each do |value| - result[:references][type] << value - end - end - end - - # Will load all references of one type using one query. - def load_lazy_references - refs = result[:references] - refs.each do |type, values| - refs[type] = ReferenceFilter::LazyReference.load(values) - end - end - - def current_user - context[:current_user] - end - end - end -end diff --git a/lib/gitlab/markdown/relative_link_filter.rb b/lib/gitlab/markdown/relative_link_filter.rb deleted file mode 100644 index 81f60120fcd..00000000000 --- a/lib/gitlab/markdown/relative_link_filter.rb +++ /dev/null @@ -1,157 +0,0 @@ -require 'gitlab/markdown' -require 'html/pipeline/filter' -require 'uri' - -module Gitlab - module Markdown - # HTML filter that "fixes" relative links to files in a repository. - # - # Context options: - # :commit - # :project - # :project_wiki - # :ref - # :requested_path - class RelativeLinkFilter < HTML::Pipeline::Filter - def call - return doc unless linkable_files? - - doc.search('a:not(.gfm)').each do |el| - process_link_attr el.attribute('href') - end - - doc.search('img').each do |el| - process_link_attr el.attribute('src') - end - - doc - end - - protected - - def linkable_files? - context[:project_wiki].nil? && repository.try(:exists?) && !repository.empty? - end - - def process_link_attr(html_attr) - return if html_attr.blank? - - uri = URI(html_attr.value) - if uri.relative? && uri.path.present? - html_attr.value = rebuild_relative_uri(uri).to_s - end - rescue URI::Error - # noop - end - - def rebuild_relative_uri(uri) - file_path = relative_file_path(uri.path) - - uri.path = [ - relative_url_root, - context[:project].path_with_namespace, - path_type(file_path), - ref || context[:project].default_branch, # if no ref exists, point to the default branch - file_path - ].compact.join('/').squeeze('/').chomp('/') - - uri - end - - def relative_file_path(path) - nested_path = build_relative_path(path, context[:requested_path]) - file_exists?(nested_path) ? nested_path : path - end - - # Convert a relative path into its correct location based on the currently - # requested path - # - # path - Relative path String - # request_path - Currently-requested path String - # - # Examples: - # - # # File in the same directory as the current 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 path unless request_path - - parts = request_path.split('/') - parts.pop if path_type(request_path) != 'tree' - - while parts.length > 1 && path.start_with?('../') - parts.pop - path.sub!('../', '') - end - - parts.push(path).join('/') - end - - def file_exists?(path) - return false if path.nil? - repository.blob_at(current_sha, path).present? || - repository.tree(current_sha, path).entries.any? - end - - # Get the type of the given path - # - # path - String path to check - # - # Examples: - # - # path_type('doc/README.md') # => 'blob' - # path_type('doc/logo.png') # => 'raw' - # path_type('doc/api') # => 'tree' - # - # Returns a String - def path_type(path) - unescaped_path = Addressable::URI.unescape(path) - - if tree?(unescaped_path) - 'tree' - elsif image?(unescaped_path) - 'raw' - else - 'blob' - end - end - - def tree?(path) - repository.tree(current_sha, path).entries.any? - end - - def image?(path) - repository.blob_at(current_sha, path).try(:image?) - end - - def current_sha - context[:commit].try(:id) || - ref ? repository.commit(ref).try(:sha) : repository.head_commit.sha - end - - def relative_url_root - Gitlab.config.gitlab.relative_url_root.presence || '/' - end - - def ref - context[:ref] - end - - def repository - context[:project].try(:repository) - end - end - end -end diff --git a/lib/gitlab/markdown/sanitization_filter.rb b/lib/gitlab/markdown/sanitization_filter.rb deleted file mode 100644 index cf153f30622..00000000000 --- a/lib/gitlab/markdown/sanitization_filter.rb +++ /dev/null @@ -1,99 +0,0 @@ -require 'gitlab/markdown' -require 'html/pipeline/filter' -require 'html/pipeline/sanitization_filter' - -module Gitlab - module Markdown - # Sanitize HTML - # - # Extends HTML::Pipeline::SanitizationFilter with a custom whitelist. - class SanitizationFilter < HTML::Pipeline::SanitizationFilter - def whitelist - # Descriptions are more heavily sanitized, allowing only a few elements. - # See http://git.io/vkuAN - if context[:inline_sanitization] - whitelist = LIMITED - whitelist[:elements] -= %w(pre code img ol ul li) - else - whitelist = super - end - - customize_whitelist(whitelist) - - whitelist - end - - private - - def customized?(transformers) - transformers.last.source_location[0] == __FILE__ - end - - def customize_whitelist(whitelist) - # Only push these customizations once - return if customized?(whitelist[:transformers]) - - # Allow code highlighting - whitelist[:attributes]['pre'] = %w(class) - whitelist[:attributes]['span'] = %w(class) - - # Allow table alignment - whitelist[:attributes]['th'] = %w(style) - whitelist[:attributes]['td'] = %w(style) - - # Allow span elements - whitelist[:elements].push('span') - - # Allow any protocol in `a` elements... - whitelist[:protocols].delete('a') - - # ...but then remove links with the `javascript` protocol - whitelist[:transformers].push(remove_javascript_links) - - # Remove `rel` attribute from `a` elements - whitelist[:transformers].push(remove_rel) - - # Remove `class` attribute from non-highlight spans - whitelist[:transformers].push(clean_spans) - - whitelist - end - - def remove_javascript_links - lambda do |env| - node = env[:node] - - return unless node.name == 'a' - return unless node.has_attribute?('href') - - if node['href'].start_with?('javascript', ':javascript') - node.remove_attribute('href') - end - end - end - - def remove_rel - lambda do |env| - if env[:node_name] == 'a' - env[:node].remove_attribute('rel') - end - end - end - - def clean_spans - lambda do |env| - node = env[:node] - - return unless node.name == 'span' - return unless node.has_attribute?('class') - - unless has_ancestor?(node, 'pre') - node.remove_attribute('class') - end - - { node_whitelist: [node] } - end - end - end - end -end diff --git a/lib/gitlab/markdown/single_line_pipeline.rb b/lib/gitlab/markdown/single_line_pipeline.rb deleted file mode 100644 index 2f24927b879..00000000000 --- a/lib/gitlab/markdown/single_line_pipeline.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - class SingleLinePipeline < GfmPipeline - - end - end -end diff --git a/lib/gitlab/markdown/snippet_reference_filter.rb b/lib/gitlab/markdown/snippet_reference_filter.rb deleted file mode 100644 index f7bd07c2a34..00000000000 --- a/lib/gitlab/markdown/snippet_reference_filter.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - # HTML filter that replaces snippet references with links. References to - # snippets that do not exist are ignored. - # - # This filter supports cross-project references. - class SnippetReferenceFilter < AbstractReferenceFilter - def self.object_class - Snippet - end - - def find_object(project, id) - project.snippets.find_by(id: id) - end - - def url_for_object(snippet, project) - h = Gitlab::Application.routes.url_helpers - h.namespace_project_snippet_url(project.namespace, project, snippet, - only_path: context[:only_path]) - end - end - end -end diff --git a/lib/gitlab/markdown/syntax_highlight_filter.rb b/lib/gitlab/markdown/syntax_highlight_filter.rb deleted file mode 100644 index 8597e02f0de..00000000000 --- a/lib/gitlab/markdown/syntax_highlight_filter.rb +++ /dev/null @@ -1,45 +0,0 @@ -require 'gitlab/markdown' -require 'html/pipeline/filter' -require 'rouge/plugins/redcarpet' - -module Gitlab - module Markdown - # HTML Filter to highlight fenced code blocks - # - class SyntaxHighlightFilter < HTML::Pipeline::Filter - include Rouge::Plugins::Redcarpet - - def call - doc.search('pre > code').each do |node| - highlight_node(node) - end - - doc - end - - def highlight_node(node) - language = node.attr('class') - code = node.text - - begin - highlighted = block_code(code, language) - rescue - # Gracefully handle syntax highlighter bugs/errors to ensure - # users can still access an issue/comment/etc. - highlighted = "
    #{code}
    " - end - - # Replace the parent `pre` element with the entire highlighted block - node.parent.replace(highlighted) - end - - private - - # Override Rouge::Plugins::Redcarpet#rouge_formatter - def rouge_formatter(lexer) - Rouge::Formatters::HTMLGitlab.new( - cssclass: "code highlight js-syntax-highlight #{lexer.tag}") - end - end - end -end diff --git a/lib/gitlab/markdown/table_of_contents_filter.rb b/lib/gitlab/markdown/table_of_contents_filter.rb deleted file mode 100644 index bbb3bf7fc8b..00000000000 --- a/lib/gitlab/markdown/table_of_contents_filter.rb +++ /dev/null @@ -1,63 +0,0 @@ -require 'gitlab/markdown' -require 'html/pipeline/filter' - -module Gitlab - module Markdown - # HTML filter that adds an anchor child element to all Headers in a - # document, so that they can be linked to. - # - # Generates the Table of Contents with links to each header. See Results. - # - # Based on HTML::Pipeline::TableOfContentsFilter. - # - # Context options: - # :no_header_anchors - Skips all processing done by this filter. - # - # Results: - # :toc - String containing Table of Contents data as a `ul` element with - # `li` child elements. - class TableOfContentsFilter < HTML::Pipeline::Filter - PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u - - def call - return doc if context[:no_header_anchors] - - result[:toc] = "" - - headers = Hash.new(0) - - doc.css('h1, h2, h3, h4, h5, h6').each do |node| - text = node.text - - id = text.downcase - id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation - id.gsub!(' ', '-') # replace spaces with dash - id.squeeze!('-') # replace multiple dashes with one - - uniq = (headers[id] > 0) ? "-#{headers[id]}" : '' - headers[id] += 1 - - if header_content = node.children.first - href = "#{id}#{uniq}" - push_toc(href, text) - header_content.add_previous_sibling(anchor_tag(href)) - end - end - - result[:toc] = %Q{
      \n#{result[:toc]}
    } unless result[:toc].empty? - - doc - end - - private - - def anchor_tag(href) - %Q{} - end - - def push_toc(href, text) - result[:toc] << %Q{
  • #{text}
  • \n} - end - end - end -end diff --git a/lib/gitlab/markdown/task_list_filter.rb b/lib/gitlab/markdown/task_list_filter.rb deleted file mode 100644 index 2f133ae8500..00000000000 --- a/lib/gitlab/markdown/task_list_filter.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'gitlab/markdown' -require 'task_list/filter' - -module Gitlab - module Markdown - # Work around a bug in the default TaskList::Filter that adds a `task-list` - # class to every list element, regardless of whether or not it contains a - # task list. - # - # This is a (hopefully) temporary fix, pending a new release of the - # task_list gem. - # - # See https://github.com/github/task_list/pull/60 - class TaskListFilter < TaskList::Filter - def add_css_class(node, *new_class_names) - if new_class_names.include?('task-list') - super if node.children.any? { |c| c['class'] == 'task-list-item' } - else - super - end - end - end - end -end diff --git a/lib/gitlab/markdown/upload_link_filter.rb b/lib/gitlab/markdown/upload_link_filter.rb deleted file mode 100644 index fbada73ab86..00000000000 --- a/lib/gitlab/markdown/upload_link_filter.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'gitlab/markdown' -require 'html/pipeline/filter' -require 'uri' - -module Gitlab - module Markdown - # HTML filter that "fixes" relative upload links to files. - # Context options: - # :project (required) - Current project - # - class UploadLinkFilter < HTML::Pipeline::Filter - def call - doc.search('a').each do |el| - process_link_attr el.attribute('href') - end - - doc.search('img').each do |el| - process_link_attr el.attribute('src') - end - - doc - end - - protected - - def process_link_attr(html_attr) - return if html_attr.blank? - - uri = html_attr.value - if uri.starts_with?("/uploads/") - html_attr.value = build_url(uri).to_s - end - end - - def build_url(uri) - File.join(Gitlab.config.gitlab.url, context[:project].path_with_namespace, uri) - end - - # Ensure that a :project key exists in context - # - # Note that while the key might exist, its value could be nil! - def validate - needs :project - end - end - end -end diff --git a/lib/gitlab/markdown/user_reference_filter.rb b/lib/gitlab/markdown/user_reference_filter.rb deleted file mode 100644 index ab5e1f6fe9e..00000000000 --- a/lib/gitlab/markdown/user_reference_filter.rb +++ /dev/null @@ -1,125 +0,0 @@ -require 'gitlab/markdown' - -module Gitlab - module Markdown - # HTML filter that replaces user or group references with links. - # - # A special `@all` reference is also supported. - class UserReferenceFilter < ReferenceFilter - # Public: Find `@user` user references in text - # - # UserReferenceFilter.references_in(text) do |match, username| - # "@#{user}" - # end - # - # text - String text to search. - # - # Yields the String match, and the String user name. - # - # Returns a String replaced with the return of the block. - def self.references_in(text) - text.gsub(User.reference_pattern) do |match| - yield match, $~[:user] - end - end - - def self.referenced_by(node) - if node.has_attribute?('data-group') - group = Group.find(node.attr('data-group')) rescue nil - return unless group - - { user: group.users } - elsif node.has_attribute?('data-user') - { user: LazyReference.new(User, node.attr('data-user')) } - elsif node.has_attribute?('data-project') - project = Project.find(node.attr('data-project')) rescue nil - return unless project - - { user: project.team.members.flatten } - end - end - - def self.user_can_reference?(user, node, context) - if node.has_attribute?('data-group') - group = Group.find(node.attr('data-group')) rescue nil - Ability.abilities.allowed?(user, :read_group, group) - else - super - end - end - - def call - replace_text_nodes_matching(User.reference_pattern) do |content| - user_link_filter(content) - end - end - - # Replace `@user` user references in text with links to the referenced - # user's profile page. - # - # text - String text to replace references in. - # - # Returns a String with `@user` references replaced with links. All links - # have `gfm` and `gfm-project_member` class names attached for styling. - def user_link_filter(text) - self.class.references_in(text) do |match, username| - if username == 'all' - link_to_all - elsif namespace = Namespace.find_by(path: username) - link_to_namespace(namespace) || match - else - match - end - end - end - - private - - def urls - Gitlab::Application.routes.url_helpers - end - - def link_class - reference_class(:project_member) - end - - def link_to_all - project = context[:project] - url = urls.namespace_project_url(project.namespace, project, - only_path: context[:only_path]) - data = data_attribute(project: project.id) - text = User.reference_prefix + 'all' - - link_tag(url, data, text) - end - - def link_to_namespace(namespace) - if namespace.is_a?(Group) - link_to_group(namespace.path, namespace) - else - link_to_user(namespace.path, namespace) - end - end - - def link_to_group(group, namespace) - url = urls.group_url(group, only_path: context[:only_path]) - data = data_attribute(group: namespace.id) - text = Group.reference_prefix + group - - link_tag(url, data, text) - end - - def link_to_user(user, namespace) - url = urls.user_url(user, only_path: context[:only_path]) - data = data_attribute(user: namespace.owner_id) - text = User.reference_prefix + user - - link_tag(url, data, text) - end - - def link_tag(url, data, text) - %(#{text}) - end - end - end -end diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index e5cafebdbc0..e83167fa7d7 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -33,8 +33,7 @@ module Gitlab # # Returns the results Array for the requested filter type def pipeline_result(filter_type) - klass = "#{filter_type.to_s.camelize}ReferenceFilter" - filter = Gitlab::Markdown.const_get(klass) + filter = Gitlab::Markdown::ReferenceFilter[filter_type] context = { pipeline: :reference_extraction, -- cgit v1.2.1 From 888821f9ffb56c6fdf762f28dd42cf3b7226652f Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 19 Nov 2015 19:22:46 +0100 Subject: Add support for batch download operation --- lib/gitlab/lfs/response.rb | 105 +++++++++++++++++++++++++++++++++------------ lib/gitlab/lfs/router.rb | 2 +- 2 files changed, 79 insertions(+), 28 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/lfs/response.rb b/lib/gitlab/lfs/response.rb index 4202c786466..ddadc07ebba 100644 --- a/lib/gitlab/lfs/response.rb +++ b/lib/gitlab/lfs/response.rb @@ -26,7 +26,7 @@ module Gitlab def render_download_object_response(oid) render_response_to_download do - if check_download_sendfile_header? && check_download_accept_header? + if check_download_sendfile_header? render_lfs_sendfile(oid) else render_not_found @@ -34,20 +34,15 @@ module Gitlab end end - def render_lfs_api_auth - render_response_to_push do - request_body = JSON.parse(@request.body.read) - return render_not_found if request_body.empty? || request_body['objects'].empty? - - response = build_response(request_body['objects']) - [ - 200, - { - "Content-Type" => "application/json; charset=utf-8", - "Cache-Control" => "private", - }, - [JSON.dump(response)] - ] + def render_batch_operation_response + request_body = JSON.parse(@request.body.read) + case request_body["operation"] + when "download" + render_batch_download(request_body) + when "upload" + render_batch_upload(request_body) + else + render_forbidden end end @@ -142,6 +137,38 @@ module Gitlab end end + def render_batch_upload(body) + return render_not_found if body.empty? || body['objects'].nil? + + render_response_to_push do + response = build_upload_batch_response(body['objects']) + [ + 200, + { + "Content-Type" => "application/json; charset=utf-8", + "Cache-Control" => "private", + }, + [JSON.dump(response)] + ] + end + end + + def render_batch_download(body) + return render_not_found if body.empty? || body['objects'].nil? + + render_response_to_download do + response = build_download_batch_response(body['objects']) + [ + 200, + { + "Content-Type" => "application/json; charset=utf-8", + "Cache-Control" => "private", + }, + [JSON.dump(response)] + ] + end + end + def render_lfs_download_hypermedia(oid) return render_not_found unless oid.present? @@ -266,10 +293,16 @@ module Gitlab @project.lfs_objects.where(oid: objects_oids).pluck(:oid).to_set end - def build_response(objects) + def build_upload_batch_response(objects) selected_objects = select_existing_objects(objects) - upload_hypermedia(objects, selected_objects) + upload_hypermedia_links(objects, selected_objects) + end + + def build_download_batch_response(objects) + selected_objects = select_existing_objects(objects) + + download_hypermedia_links(objects, selected_objects) end def download_hypermedia(oid) @@ -279,7 +312,6 @@ module Gitlab { 'href' => "#{@origin_project.http_url_to_repo}/gitlab-lfs/objects/#{oid}", 'header' => { - 'Accept' => "application/vnd.git-lfs+json; charset=utf-8", 'Authorization' => @env['HTTP_AUTHORIZATION'] }.compact } @@ -287,21 +319,40 @@ module Gitlab } end - def upload_hypermedia(all_objects, existing_objects) + def download_hypermedia_links(all_objects, existing_objects) all_objects.each do |object| - object['_links'] = hypermedia_links(object) unless existing_objects.include?(object['oid']) + # generate links only for existing objects + next unless existing_objects.include?(object['oid']) + + object['_links'] = { + 'download' => { + 'href' => "#{@origin_project.http_url_to_repo}/gitlab-lfs/objects/#{object['oid']}", + 'header' => { + 'Authorization' => @env['HTTP_AUTHORIZATION'] + }.compact + } + } end { 'objects' => all_objects } end - def hypermedia_links(object) - { - "upload" => { - 'href' => "#{@origin_project.http_url_to_repo}/gitlab-lfs/objects/#{object['oid']}/#{object['size']}", - 'header' => { 'Authorization' => @env['HTTP_AUTHORIZATION'] } - }.compact - } + def upload_hypermedia_links(all_objects, existing_objects) + all_objects.each do |object| + # generate links only for non-existing objects + next if existing_objects.include?(object['oid']) + + object['_links'] = { + 'upload' => { + 'href' => "#{@origin_project.http_url_to_repo}/gitlab-lfs/objects/#{object['oid']}/#{object['size']}", + 'header' => { + 'Authorization' => @env['HTTP_AUTHORIZATION'] + }.compact + } + } + end + + { 'objects' => all_objects } end end end diff --git a/lib/gitlab/lfs/router.rb b/lib/gitlab/lfs/router.rb index 4809e834984..2b3f2e8e958 100644 --- a/lib/gitlab/lfs/router.rb +++ b/lib/gitlab/lfs/router.rb @@ -48,7 +48,7 @@ module Gitlab # Check for Batch API if post_path[0].ends_with?("/info/lfs/objects/batch") - lfs.render_lfs_api_auth + lfs.render_batch_operation_response else nil end -- cgit v1.2.1 From 14d95b0529eacb8f42c5184fb71bff3f326d1670 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 20 Nov 2015 11:59:32 +0100 Subject: Part of tests done [ci skip] --- lib/gitlab/lfs/response.rb | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/lfs/response.rb b/lib/gitlab/lfs/response.rb index ddadc07ebba..0371e1a7107 100644 --- a/lib/gitlab/lfs/response.rb +++ b/lib/gitlab/lfs/response.rb @@ -42,7 +42,7 @@ module Gitlab when "upload" render_batch_upload(request_body) else - render_forbidden + render_not_found end end @@ -322,16 +322,21 @@ module Gitlab def download_hypermedia_links(all_objects, existing_objects) all_objects.each do |object| # generate links only for existing objects - next unless existing_objects.include?(object['oid']) - - object['_links'] = { - 'download' => { - 'href' => "#{@origin_project.http_url_to_repo}/gitlab-lfs/objects/#{object['oid']}", - 'header' => { - 'Authorization' => @env['HTTP_AUTHORIZATION'] - }.compact + if existing_objects.include?(object['oid']) + object['actions'] = { + 'download' => { + 'href' => "#{@origin_project.http_url_to_repo}/gitlab-lfs/objects/#{object['oid']}", + 'header' => { + 'Authorization' => @env['HTTP_AUTHORIZATION'] + }.compact + } } - } + else + object['error'] = { + 'code' => 404, + 'message' => "Object does not exist on the server or you don't have permissions to access it", + } + end end { 'objects' => all_objects } @@ -342,7 +347,7 @@ module Gitlab # generate links only for non-existing objects next if existing_objects.include?(object['oid']) - object['_links'] = { + object['actions'] = { 'upload' => { 'href' => "#{@origin_project.http_url_to_repo}/gitlab-lfs/objects/#{object['oid']}/#{object['size']}", 'header' => { -- cgit v1.2.1 From b8d8292bef996a5d074b21a82d4faec0edb2e2bf Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 20 Nov 2015 12:21:41 +0100 Subject: Fix upload tests, reformat code and make rubocop happy --- lib/gitlab/lfs/response.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/lfs/response.rb b/lib/gitlab/lfs/response.rb index 0371e1a7107..ada518f9e04 100644 --- a/lib/gitlab/lfs/response.rb +++ b/lib/gitlab/lfs/response.rb @@ -321,7 +321,6 @@ module Gitlab def download_hypermedia_links(all_objects, existing_objects) all_objects.each do |object| - # generate links only for existing objects if existing_objects.include?(object['oid']) object['actions'] = { 'download' => { @@ -344,7 +343,7 @@ module Gitlab def upload_hypermedia_links(all_objects, existing_objects) all_objects.each do |object| - # generate links only for non-existing objects + # generate actions only for non-existing objects next if existing_objects.include?(object['oid']) object['actions'] = { -- cgit v1.2.1 From dbc0be1b275e92af5432cf7c5cf44de3dc8c9ca5 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Fri, 20 Nov 2015 12:45:30 +0100 Subject: Error 501 when client is using deprecated API. --- lib/gitlab/lfs/response.rb | 60 ++++++++++------------------------------------ lib/gitlab/lfs/router.rb | 4 +++- 2 files changed, 15 insertions(+), 49 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/lfs/response.rb b/lib/gitlab/lfs/response.rb index ada518f9e04..aceef53ba60 100644 --- a/lib/gitlab/lfs/response.rb +++ b/lib/gitlab/lfs/response.rb @@ -10,20 +10,6 @@ module Gitlab @request = request end - # Return a response for a download request - # Can be a response to: - # Request from a user to get the file - # Request from gitlab-workhorse which file to serve to the user - def render_download_hypermedia_response(oid) - render_response_to_download do - if check_download_accept_header? - render_lfs_download_hypermedia(oid) - else - render_not_found - end - end - end - def render_download_object_response(oid) render_response_to_download do if check_download_sendfile_header? @@ -66,13 +52,24 @@ module Gitlab end end + def render_unsupported_deprecated_api + [ + 501, + { "Content-Type" => "application/json; charset=utf-8" }, + [JSON.dump({ + 'message' => 'Server supports batch API only, please update your Git LFS client to version 0.6.0 and up.', + 'documentation_url' => "#{Gitlab.config.gitlab.url}/help", + })] + ] + end + private def render_not_enabled [ 501, { - "Content-Type" => "application/vnd.git-lfs+json", + "Content-Type" => "application/json; charset=utf-8", }, [JSON.dump({ 'message' => 'Git LFS is not enabled on this GitLab server, contact your admin.', @@ -169,21 +166,6 @@ module Gitlab end end - def render_lfs_download_hypermedia(oid) - return render_not_found unless oid.present? - - lfs_object = object_for_download(oid) - if lfs_object - [ - 200, - { "Content-Type" => "application/vnd.git-lfs+json" }, - [JSON.dump(download_hypermedia(oid))] - ] - else - render_not_found - end - end - def render_lfs_upload_ok(oid, size, tmp_file) if store_file(oid, size, tmp_file) [ @@ -226,10 +208,6 @@ module Gitlab @env['HTTP_X_SENDFILE_TYPE'].to_s == "X-Sendfile" end - def check_download_accept_header? - @env['HTTP_ACCEPT'].to_s == "application/vnd.git-lfs+json; charset=utf-8" - end - def user_can_fetch? # Check user access against the project they used to initiate the pull @user.can?(:download_code, @origin_project) @@ -305,20 +283,6 @@ module Gitlab download_hypermedia_links(objects, selected_objects) end - def download_hypermedia(oid) - { - '_links' => { - 'download' => - { - 'href' => "#{@origin_project.http_url_to_repo}/gitlab-lfs/objects/#{oid}", - 'header' => { - 'Authorization' => @env['HTTP_AUTHORIZATION'] - }.compact - } - } - } - end - def download_hypermedia_links(all_objects, existing_objects) all_objects.each do |object| if existing_objects.include?(object['oid']) diff --git a/lib/gitlab/lfs/router.rb b/lib/gitlab/lfs/router.rb index 2b3f2e8e958..78d02891102 100644 --- a/lib/gitlab/lfs/router.rb +++ b/lib/gitlab/lfs/router.rb @@ -34,7 +34,7 @@ module Gitlab case path_match[1] when "info/lfs" - lfs.render_download_hypermedia_response(oid) + lfs.render_unsupported_deprecated_api when "gitlab-lfs" lfs.render_download_object_response(oid) else @@ -49,6 +49,8 @@ module Gitlab # Check for Batch API if post_path[0].ends_with?("/info/lfs/objects/batch") lfs.render_batch_operation_response + elsif post_path[0].ends_with?("/info/lfs/objects") + lfs.render_unsupported_deprecated_api else nil end -- cgit v1.2.1 From 899807f604f7923cc40a64cdd0f61c4248b8870d Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Fri, 20 Nov 2015 16:10:08 +0100 Subject: Update required version of lfs client and separate the docs for users and admins. --- lib/gitlab/lfs/response.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/lfs/response.rb b/lib/gitlab/lfs/response.rb index aceef53ba60..c18dfbd485d 100644 --- a/lib/gitlab/lfs/response.rb +++ b/lib/gitlab/lfs/response.rb @@ -57,7 +57,7 @@ module Gitlab 501, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump({ - 'message' => 'Server supports batch API only, please update your Git LFS client to version 0.6.0 and up.', + 'message' => 'Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.', 'documentation_url' => "#{Gitlab.config.gitlab.url}/help", })] ] -- cgit v1.2.1 From 2cba93a0d2d12ee36bf98569e5c6c14ac7ea40e0 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Sat, 21 Nov 2015 17:29:26 +0100 Subject: Make tag API consistent for release feature --- lib/api/entities.rb | 3 ++- lib/api/tags.rb | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 3da6bc415d6..5dea74db295 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -322,7 +322,8 @@ module API end class Release < Grape::Entity - expose :tag, :description + expose :tag, as: :tag_name + expose :description end class RepoTag < Grape::Entity diff --git a/lib/api/tags.rb b/lib/api/tags.rb index 673342dd447..2c6c73da08e 100644 --- a/lib/api/tags.rb +++ b/lib/api/tags.rb @@ -44,14 +44,14 @@ module API # # Parameters: # id (required) - The ID of a project - # tag (required) - The name of the tag + # tag_name (required) - The name of the tag # description (required) - Release notes with markdown support # Example Request: - # PUT /projects/:id/repository/tags - put ':id/repository/:tag/release', requirements: { tag: /.*/ } do + # PUT /projects/:id/repository/tags/:tag_name/release + put ':id/repository/tags/:tag_name/release', requirements: { tag_name: /.*/ } do authorize_push_project required_attributes! [:description] - release = user_project.releases.find_or_initialize_by(tag: params[:tag]) + release = user_project.releases.find_or_initialize_by(tag: params[:tag_name]) release.update_attributes(description: params[:description]) present release, with: Entities::Release -- cgit v1.2.1 From faef95af1a07bdcfd02eead36d144f332b428f1f Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Sat, 21 Nov 2015 18:08:45 +0100 Subject: API: Return 404 if the tag for a release does not exist --- lib/api/tags.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/api/tags.rb b/lib/api/tags.rb index 2c6c73da08e..0721b9cc844 100644 --- a/lib/api/tags.rb +++ b/lib/api/tags.rb @@ -51,10 +51,14 @@ module API put ':id/repository/tags/:tag_name/release', requirements: { tag_name: /.*/ } do authorize_push_project required_attributes! [:description] - release = user_project.releases.find_or_initialize_by(tag: params[:tag_name]) - release.update_attributes(description: params[:description]) + result = CreateReleaseService.new(user_project, current_user). + execute(params[:tag_name], params[:description]) - present release, with: Entities::Release + if result[:status] == :success + present result[:release], with: Entities::Release + else + render_api_error!(result[:message], 404) + end end end end -- cgit v1.2.1 From 6f7e90f6dba300591281aba08ffbe30ce3cc5c90 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Sat, 21 Nov 2015 18:51:41 +0100 Subject: Use POST to create a new release instead of PUT --- lib/api/tags.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/tags.rb b/lib/api/tags.rb index 0721b9cc844..48f630d58e5 100644 --- a/lib/api/tags.rb +++ b/lib/api/tags.rb @@ -48,7 +48,7 @@ module API # description (required) - Release notes with markdown support # Example Request: # PUT /projects/:id/repository/tags/:tag_name/release - put ':id/repository/tags/:tag_name/release', requirements: { tag_name: /.*/ } do + post ':id/repository/tags/:tag_name/release', requirements: { tag_name: /.*/ } do authorize_push_project required_attributes! [:description] result = CreateReleaseService.new(user_project, current_user). -- cgit v1.2.1 From 26b12e2c374c8f07abda06a8b19bd116448325f4 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Sat, 21 Nov 2015 21:36:31 +0100 Subject: Add upvote/downvote fields to merge request and note API to preserve compatibility --- lib/api/entities.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 3da6bc415d6..7f9dba4b6a5 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -163,6 +163,8 @@ module API class MergeRequest < ProjectEntity expose :target_branch, :source_branch + # deprecated, always returns 0 + expose :upvotes, :downvotes expose :author, :assignee, using: Entities::UserBasic expose :source_project_id, :target_project_id expose :label_names, as: :labels @@ -192,6 +194,9 @@ module API expose :author, using: Entities::UserBasic expose :created_at expose :system?, as: :system + # upvote? and downvote? are deprecated, always return false + expose :upvote?, as: :upvote + expose :downvote?, as: :downvote end class MRNote < Grape::Entity -- cgit v1.2.1 From 3ea05c5b5b253de33d8bf8d615c66e2935b940ef Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Sat, 21 Nov 2015 22:24:34 +0100 Subject: Only allow to create a release if it does not exist yet --- lib/api/tags.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/api/tags.rb b/lib/api/tags.rb index 48f630d58e5..e46d9bb96f0 100644 --- a/lib/api/tags.rb +++ b/lib/api/tags.rb @@ -47,7 +47,7 @@ module API # tag_name (required) - The name of the tag # description (required) - Release notes with markdown support # Example Request: - # PUT /projects/:id/repository/tags/:tag_name/release + # POST /projects/:id/repository/tags/:tag_name/release post ':id/repository/tags/:tag_name/release', requirements: { tag_name: /.*/ } do authorize_push_project required_attributes! [:description] @@ -57,7 +57,7 @@ module API if result[:status] == :success present result[:release], with: Entities::Release else - render_api_error!(result[:message], 404) + render_api_error!(result[:message], result[:http_status]) end end end -- cgit v1.2.1 From 04a3d27eaba0312d99e8d88a3a9ee4b5c83ecce1 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Sat, 21 Nov 2015 22:34:53 +0100 Subject: Allow editing a release in API via PUT method --- lib/api/tags.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'lib') diff --git a/lib/api/tags.rb b/lib/api/tags.rb index e46d9bb96f0..47621f443e6 100644 --- a/lib/api/tags.rb +++ b/lib/api/tags.rb @@ -60,6 +60,27 @@ module API render_api_error!(result[:message], result[:http_status]) end end + + # Updates a release notes of a tag + # + # Parameters: + # id (required) - The ID of a project + # tag_name (required) - The name of the tag + # description (required) - Release notes with markdown support + # Example Request: + # PUT /projects/:id/repository/tags/:tag_name/release + put ':id/repository/tags/:tag_name/release', requirements: { tag_name: /.*/ } do + authorize_push_project + required_attributes! [:description] + result = UpdateReleaseService.new(user_project, current_user). + execute(params[:tag_name], params[:description]) + + if result[:status] == :success + present result[:release], with: Entities::Release + else + render_api_error!(result[:message], result[:http_status]) + end + end end end end -- cgit v1.2.1 From 8608c6325e19f529f7b43ff881c562d3a0114e1c Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 23 Nov 2015 09:42:20 +0100 Subject: Refactor MergeWhenBuildSucceedsService and incorporate feedback --- lib/api/merge_requests.rb | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index f981432db36..b72f816932b 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -182,39 +182,35 @@ module API # id (required) - The ID of a project # merge_request_id (required) - ID of MR # merge_commit_message (optional) - Custom merge commit message - # merge_when_build_succeeds (optional) - truethy when this MR should be merged when the build is succesfull + # should_remove_source_branch - When true, the source branch will be deleted if possible + # merge_when_build_succeeds (optional) - When true, this MR will be merged when the build succeeds # Example: # PUT /projects/:id/merge_request/:merge_request_id/merge # put ":id/merge_request/:merge_request_id/merge" do merge_request = user_project.merge_requests.find(params[:merge_request_id]) - allowed = ::Gitlab::GitAccess.new(current_user, user_project). - can_push_to_branch?(merge_request.target_branch) - # Merge request can not be merged # because user dont have permissions to push into target branch - unauthorized! unless allowed + unauthorized! unless merge_request.can_be_merged_by?(current_user) - not_allowed! unless merge_request.open? + not_allowed! unless merge_request.open? && !merge_request.work_in_progress? merge_request.check_if_can_be_merged if merge_request.unchecked? + render_api_error!('Branch cannot be merged', 406) if merge_request.can_be_merged? + merge_params = { commit_message: params[:merge_commit_message], should_remove_source_branch: params[:should_remove_source_branch] } - if !merge_request.work_in_progress? - if parse_boolean(params[:merge_when_build_succeeds]) - ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). - execute(merge_request) - else - ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params). - execute(merge_request, merge_params) - end + if parse_boolean(params[:merge_when_build_succeeds]) && merge_request.ci_commit && merge_request.ci_commit.active? + ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). + execute(merge_request) else - render_api_error!('Branch cannot be merged', 405) + ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params). + execute(merge_request) end present merge_request, with: Entities::MergeRequest @@ -233,15 +229,9 @@ module API # Merge request can not be merged # because user dont have permissions to push into target branch - unauthorized! unless allowed + unauthorized! unless merge_request.can_cancel_merge_when_build_succeeds?(current_user) - if merge_request.merged? || !merge_request.open? || !merge_request.merge_when_build_succeeds? - not_allowed! - end - - merge_request.reset_merge_when_build_succeeds - - present merge_request, with: Entities::MergeRequest + ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user).cancel(merge_request) end # Get a merge request's comments -- cgit v1.2.1 From 11728b50f96a296c760d9e69273d304f92e51f8f Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sun, 22 Nov 2015 14:27:30 +0100 Subject: Expose artifacts path --- lib/ci/api/builds.rb | 2 ++ lib/gitlab/current_settings.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb index 0a586672807..15faa6edd84 100644 --- a/lib/ci/api/builds.rb +++ b/lib/ci/api/builds.rb @@ -58,6 +58,7 @@ module Ci # POST /builds/:id/artifacts/authorize post ":id/artifacts/authorize" do require_gitlab_workhorse! + not_allowed! unless Gitlab.config.artifacts.enabled build = Ci::Build.find_by_id(params[:id]) not_found! unless build authenticate_build_token!(build) @@ -91,6 +92,7 @@ module Ci # POST /builds/:id/artifacts post ":id/artifacts" do require_gitlab_workhorse! + not_allowed! unless Gitlab.config.artifacts.enabled build = Ci::Build.find_by_id(params[:id]) not_found! unless build authenticate_build_token!(build) diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 2d3e32d9539..46a4ef0e31f 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -25,7 +25,7 @@ module Gitlab session_expire_delay: Settings.gitlab['session_expire_delay'], import_sources: Settings.gitlab['import_sources'], shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'], - max_artifacts_size: Ci::Settings.gitlab_ci['max_artifacts_size'], + max_artifacts_size: Settings.artifacts['max_size'], ) end -- cgit v1.2.1 From 97f8c6279fc39c4bad87bb880eba04802f6d351d Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 19 Nov 2015 12:33:58 +0100 Subject: Added total query time to Sherlock This makes it easier to see if a problem is caused by slow queries or slow Ruby code (unrelated to any SQL queries that might be used). --- lib/gitlab/sherlock/transaction.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/gitlab/sherlock/transaction.rb b/lib/gitlab/sherlock/transaction.rb index d87a4c9bb4a..3489fb251b6 100644 --- a/lib/gitlab/sherlock/transaction.rb +++ b/lib/gitlab/sherlock/transaction.rb @@ -36,6 +36,11 @@ module Gitlab @duration ||= started_at && finished_at ? finished_at - started_at : 0 end + # Returns the total query duration in seconds. + def query_duration + @query_duration ||= @queries.map { |q| q.duration }.inject(:+) / 1000.0 + end + def to_param @id end -- cgit v1.2.1 From ec002e802677a691d758ebc6f94f23020b2b063a Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 24 Nov 2015 19:20:23 -0500 Subject: Remove usage of Colored --- lib/tasks/gitlab/task_helpers.rake | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake index c95b6540ebc..efb863a8764 100644 --- a/lib/tasks/gitlab/task_helpers.rake +++ b/lib/tasks/gitlab/task_helpers.rake @@ -2,16 +2,6 @@ module Gitlab class TaskAbortedByUserError < StandardError; end end -unless STDOUT.isatty - module Colored - extend self - - def colorize(string, options={}) - string - end - end -end - namespace :gitlab do # Ask if the user wants to continue @@ -103,7 +93,7 @@ namespace :gitlab do gitlab_user = Gitlab.config.gitlab.user current_user = run(%W(whoami)).chomp unless current_user == gitlab_user - puts "#{Colored.color(:black)+Colored.color(:on_yellow)} Warning #{Colored.extra(:clear)}" + puts " Warning ".colorize(:black).on_yellow puts " You are running as user #{current_user.magenta}, we hope you know what you are doing." puts " Things may work\/fail for the wrong reasons." puts " For correct results you should run this as user #{gitlab_user.magenta}." -- cgit v1.2.1 From 7f214cee74796ceaf7b01bd6e133d4d54c5123db Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Thu, 26 Nov 2015 15:48:01 +0200 Subject: Migrate mailers to ActiveJob --- lib/gitlab/markdown/label_reference_filter.rb | 3 +-- lib/gitlab/seeder.rb | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb index 618acb7a578..13581b8fb13 100644 --- a/lib/gitlab/markdown/label_reference_filter.rb +++ b/lib/gitlab/markdown/label_reference_filter.rb @@ -60,8 +60,7 @@ module Gitlab def url_for_label(project, label) h = Gitlab::Application.routes.url_helpers h.namespace_project_issues_path(project.namespace, project, - label_name: label.name, - only_path: context[:only_path]) + label_name: label.name) end def render_colored_label(label) diff --git a/lib/gitlab/seeder.rb b/lib/gitlab/seeder.rb index 31aa3528c4c..2ef0e982256 100644 --- a/lib/gitlab/seeder.rb +++ b/lib/gitlab/seeder.rb @@ -14,7 +14,7 @@ module Gitlab def self.mute_mailer code = <<-eos -def Notify.delay +def Notify.deliver_later self end eos -- cgit v1.2.1 From 295d378e9ab1a8e052e35c6e6fedf8d6890b74d0 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 27 Nov 2015 13:56:26 +0100 Subject: Repeat "client_max_body_size 0" everywhere It turns out that if we do not the declaration from "location /" wins. --- lib/support/nginx/gitlab | 6 ++++++ lib/support/nginx/gitlab-ssl | 6 ++++++ 2 files changed, 12 insertions(+) (limited to 'lib') diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab index 0cf5292b290..1dfcac91cdc 100644 --- a/lib/support/nginx/gitlab +++ b/lib/support/nginx/gitlab @@ -114,24 +114,28 @@ server { } location ~ ^/[\w\.-]+/[\w\.-]+/gitlab-lfs/objects { + client_max_body_size 0; # 'Error' 418 is a hack to re-use the @gitlab-workhorse block error_page 418 = @gitlab-workhorse; return 418; } location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ { + client_max_body_size 0; # 'Error' 418 is a hack to re-use the @gitlab-workhorse block error_page 418 = @gitlab-workhorse; return 418; } location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive { + client_max_body_size 0; # 'Error' 418 is a hack to re-use the @gitlab-workhorse block error_page 418 = @gitlab-workhorse; return 418; } location ~ ^/api/v3/projects/.*/repository/archive { + client_max_body_size 0; # 'Error' 418 is a hack to re-use the @gitlab-workhorse block error_page 418 = @gitlab-workhorse; return 418; @@ -139,6 +143,7 @@ server { # Build artifacts should be submitted to this location location ~ ^/[\w\.-]+/[\w\.-]+/builds/download { + client_max_body_size 0; # 'Error' 418 is a hack to re-use the @gitlab-workhorse block error_page 418 = @gitlab-workhorse; return 418; @@ -146,6 +151,7 @@ server { # Build artifacts should be submitted to this location location ~ /ci/api/v1/builds/[0-9]+/artifacts { + client_max_body_size 0; # 'Error' 418 is a hack to re-use the @gitlab-workhorse block error_page 418 = @gitlab-workhorse; return 418; diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl index 31a651c87fd..7cd32de073b 100644 --- a/lib/support/nginx/gitlab-ssl +++ b/lib/support/nginx/gitlab-ssl @@ -161,24 +161,28 @@ server { } location ~ ^/[\w\.-]+/[\w\.-]+/gitlab-lfs/objects { + client_max_body_size 0; # 'Error' 418 is a hack to re-use the @gitlab-workhorse block error_page 418 = @gitlab-workhorse; return 418; } location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ { + client_max_body_size 0; # 'Error' 418 is a hack to re-use the @gitlab-workhorse block error_page 418 = @gitlab-workhorse; return 418; } location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive { + client_max_body_size 0; # 'Error' 418 is a hack to re-use the @gitlab-workhorse block error_page 418 = @gitlab-workhorse; return 418; } location ~ ^/api/v3/projects/.*/repository/archive { + client_max_body_size 0; # 'Error' 418 is a hack to re-use the @gitlab-workhorse block error_page 418 = @gitlab-workhorse; return 418; @@ -186,6 +190,7 @@ server { # Build artifacts should be submitted to this location location ~ ^/[\w\.-]+/[\w\.-]+/builds/download { + client_max_body_size 0; # 'Error' 418 is a hack to re-use the @gitlab-workhorse block error_page 418 = @gitlab-workhorse; return 418; @@ -193,6 +198,7 @@ server { # Build artifacts should be submitted to this location location ~ /ci/api/v1/builds/[0-9]+/artifacts { + client_max_body_size 0; # 'Error' 418 is a hack to re-use the @gitlab-workhorse block error_page 418 = @gitlab-workhorse; return 418; -- cgit v1.2.1 From 04049b6b17c9354555115b5d2f049daffa311c16 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 27 Nov 2015 13:57:53 +0100 Subject: Fix indentation in NGINX config --- lib/support/nginx/gitlab-ssl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl index 7cd32de073b..016f7a536fb 100644 --- a/lib/support/nginx/gitlab-ssl +++ b/lib/support/nginx/gitlab-ssl @@ -191,17 +191,17 @@ server { # Build artifacts should be submitted to this location location ~ ^/[\w\.-]+/[\w\.-]+/builds/download { client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; + # 'Error' 418 is a hack to re-use the @gitlab-workhorse block + error_page 418 = @gitlab-workhorse; + return 418; } # Build artifacts should be submitted to this location location ~ /ci/api/v1/builds/[0-9]+/artifacts { client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; + # 'Error' 418 is a hack to re-use the @gitlab-workhorse block + error_page 418 = @gitlab-workhorse; + return 418; } location @gitlab-workhorse { -- cgit v1.2.1 From f1710073b46c940245d38b46e5436c0745223aee Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 27 Nov 2015 14:39:55 -0500 Subject: Fix alignment [ci skip] --- lib/support/nginx/gitlab | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab index 1dfcac91cdc..2a79fbdcf93 100644 --- a/lib/support/nginx/gitlab +++ b/lib/support/nginx/gitlab @@ -144,17 +144,17 @@ server { # Build artifacts should be submitted to this location location ~ ^/[\w\.-]+/[\w\.-]+/builds/download { client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; + # 'Error' 418 is a hack to re-use the @gitlab-workhorse block + error_page 418 = @gitlab-workhorse; + return 418; } # Build artifacts should be submitted to this location location ~ /ci/api/v1/builds/[0-9]+/artifacts { client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; + # 'Error' 418 is a hack to re-use the @gitlab-workhorse block + error_page 418 = @gitlab-workhorse; + return 418; } location @gitlab-workhorse { -- cgit v1.2.1 From e92ceb7b57139e985674a44cfe75534c52ed4acd Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Mon, 30 Nov 2015 16:12:31 +0200 Subject: fix specs --- lib/gitlab/github_import/client.rb | 2 +- lib/gitlab/gitlab_import/client.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb index 270cbcd9ccd..74d1529e1ff 100644 --- a/lib/gitlab/github_import/client.rb +++ b/lib/gitlab/github_import/client.rb @@ -46,7 +46,7 @@ module Gitlab end def github_options - OmniAuth::Strategies::GitHub.default_options[:client_options].symbolize_keys + OmniAuth::Strategies::GitHub.default_options[:client_options].to_h.symbolize_keys end end end diff --git a/lib/gitlab/gitlab_import/client.rb b/lib/gitlab/gitlab_import/client.rb index 9c00896c913..86fb6c51765 100644 --- a/lib/gitlab/gitlab_import/client.rb +++ b/lib/gitlab/gitlab_import/client.rb @@ -75,7 +75,7 @@ module Gitlab end def gitlab_options - OmniAuth::Strategies::GitLab.default_options[:client_options].symbolize_keys + OmniAuth::Strategies::GitLab.default_options[:client_options].to_h.symbolize_keys end end end -- cgit v1.2.1 From ae18ba16327abd79cf6207b83209d4ef96d3e158 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Tue, 24 Nov 2015 13:35:07 +0200 Subject: Fire update hook from GitLab --- lib/gitlab/git/hook.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'lib') diff --git a/lib/gitlab/git/hook.rb b/lib/gitlab/git/hook.rb index dd393fe09d2..07b856ca64c 100644 --- a/lib/gitlab/git/hook.rb +++ b/lib/gitlab/git/hook.rb @@ -16,6 +16,17 @@ module Gitlab def trigger(gl_id, oldrev, newrev, ref) return true unless exists? + case name + when "pre-receive", "post-receive" + call_receive_hook(gl_id, oldrev, newrev, ref) + when "update" + call_update_hook(gl_id, oldrev, newrev, ref) + end + end + + private + + def call_receive_hook(gl_id, oldrev, newrev, ref) changes = [oldrev, newrev, ref].join(" ") # function will return true if succesful @@ -54,6 +65,12 @@ module Gitlab exit_status end + + def call_update_hook(gl_id, oldrev, newrev, ref) + Dir.chdir(repo_path) do + system({ 'GL_ID' => gl_id }, path, ref, oldrev, newrev) + end + end end end end -- cgit v1.2.1 From d6a5b45c8ea5ec7a68e213636fde405c52bb90e4 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 30 Nov 2015 21:14:46 +0100 Subject: Recognize issue/MR/snippet/commit links as references. --- lib/gitlab/markdown.rb | 5 +- lib/gitlab/markdown/abstract_reference_filter.rb | 31 +++++++--- .../markdown/commit_range_reference_filter.rb | 70 ++++++---------------- lib/gitlab/markdown/commit_reference_filter.rb | 68 +++++---------------- lib/gitlab/markdown/external_link_filter.rb | 3 + .../markdown/merge_request_reference_filter.rb | 10 ++++ lib/gitlab/markdown/redactor_filter.rb | 5 +- 7 files changed, 77 insertions(+), 115 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index b082bfc434b..ee458eda025 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -181,8 +181,6 @@ module Gitlab Gitlab::Markdown::RelativeLinkFilter, Gitlab::Markdown::EmojiFilter, Gitlab::Markdown::TableOfContentsFilter, - Gitlab::Markdown::AutolinkFilter, - Gitlab::Markdown::ExternalLinkFilter, Gitlab::Markdown::UserReferenceFilter, Gitlab::Markdown::IssueReferenceFilter, @@ -193,6 +191,9 @@ module Gitlab Gitlab::Markdown::CommitReferenceFilter, Gitlab::Markdown::LabelReferenceFilter, + Gitlab::Markdown::AutolinkFilter, + Gitlab::Markdown::ExternalLinkFilter, + Gitlab::Markdown::TaskListFilter ] end diff --git a/lib/gitlab/markdown/abstract_reference_filter.rb b/lib/gitlab/markdown/abstract_reference_filter.rb index fd5b7eb9332..4adc44361b7 100644 --- a/lib/gitlab/markdown/abstract_reference_filter.rb +++ b/lib/gitlab/markdown/abstract_reference_filter.rb @@ -40,7 +40,7 @@ module Gitlab # Returns a String replaced with the return of the block. def self.references_in(text) text.gsub(object_class.reference_pattern) do |match| - yield match, $~[object_sym].to_i, $~[:project] + yield match, $~[object_sym].to_i, $~[:project], $~ end end @@ -74,26 +74,41 @@ module Gitlab # Returns a String with references replaced with links. All links # have `gfm` and `gfm-OBJECT_NAME` class names attached for styling. def object_link_filter(text) - references_in(text) do |match, id, project_ref| + references_in(text) do |match, id, project_ref, matches| project = project_from_ref(project_ref) if project && object = find_object(project, id) - title = escape_once("#{object_title}: #{object.title}") + title = escape_once(object_link_title(object)) klass = reference_class(object_sym) - data = data_attribute(project: project.id, object_sym => object.id) - url = url_for_object(object, project) + data = data_attribute(project: project.id, object_sym => object.id, original: match) + url = matches[:url] || url_for_object(object, project) + + text = object.to_reference(context[:project]) + + extras = object_link_text_extras(object, matches) + text += " (#{extras.join(", ")})" if extras.any? %(#{match}) + class="#{klass}">#{text}) else match end end end - def object_title - object_class.name.titleize + def object_link_text_extras(object, matches) + extras = [] + + if matches[:anchor] && matches[:anchor] =~ /\A\#note_(\d+)\z/ + extras << "comment #{$1}" + end + + extras + end + + def object_link_title(object) + "#{object_class.name.titleize}: #{object.title}" end end end diff --git a/lib/gitlab/markdown/commit_range_reference_filter.rb b/lib/gitlab/markdown/commit_range_reference_filter.rb index e070edae0a4..f24bed76193 100644 --- a/lib/gitlab/markdown/commit_range_reference_filter.rb +++ b/lib/gitlab/markdown/commit_range_reference_filter.rb @@ -5,24 +5,14 @@ module Gitlab # HTML filter that replaces commit range references with links. # # This filter supports cross-project references. - class CommitRangeReferenceFilter < ReferenceFilter - include CrossProjectReference + class CommitRangeReferenceFilter < AbstractReferenceFilter + def self.object_class + CommitRange + end - # Public: Find commit range references in text - # - # CommitRangeReferenceFilter.references_in(text) do |match, commit_range, project_ref| - # "#{commit_range}" - # end - # - # text - String text to search. - # - # Yields the String match, the String commit range, and an optional String - # of the external project reference. - # - # Returns a String replaced with the return of the block. def self.references_in(text) text.gsub(CommitRange.reference_pattern) do |match| - yield match, $~[:commit_range], $~[:project] + yield match, $~[:commit_range], $~[:project], $~ end end @@ -31,9 +21,9 @@ module Gitlab return unless project id = node.attr("data-commit-range") - range = CommitRange.new(id, project) + range = find_object(project, id) - return unless range.valid_commits? + return unless range { commit_range: range } end @@ -44,49 +34,25 @@ module Gitlab @commit_map = {} end - def call - replace_text_nodes_matching(CommitRange.reference_pattern) do |content| - commit_range_link_filter(content) - end - end - - # Replace commit range references in text with links to compare the commit - # ranges. - # - # text - String text to replace references in. - # - # Returns a String with commit range references replaced with links. All - # links have `gfm` and `gfm-commit_range` class names attached for - # styling. - def commit_range_link_filter(text) - self.class.references_in(text) do |match, id, project_ref| - project = self.project_from_ref(project_ref) - - range = CommitRange.new(id, project) - - if range.valid_commits? - url = url_for_commit_range(project, range) - - title = range.reference_title - klass = reference_class(:commit_range) - data = data_attribute(project: project.id, commit_range: id) + def self.find_object(project, id) + range = CommitRange.new(id, project) - project_ref += '@' if project_ref + range.valid_commits? ? range : nil + end - %(#{project_ref}#{range}) - else - match - end - end + def find_object(*args) + self.class.find_object(*args) end - def url_for_commit_range(project, range) + def url_for_object(range, project) h = Gitlab::Application.routes.url_helpers h.namespace_project_compare_url(project.namespace, project, range.to_param.merge(only_path: context[:only_path])) end + + def object_link_title(range) + range.reference_title + end end end end diff --git a/lib/gitlab/markdown/commit_reference_filter.rb b/lib/gitlab/markdown/commit_reference_filter.rb index 8cdbeb1f9cf..cc7abc08c87 100644 --- a/lib/gitlab/markdown/commit_reference_filter.rb +++ b/lib/gitlab/markdown/commit_reference_filter.rb @@ -5,24 +5,14 @@ module Gitlab # HTML filter that replaces commit references with links. # # This filter supports cross-project references. - class CommitReferenceFilter < ReferenceFilter - include CrossProjectReference + class CommitReferenceFilter < AbstractReferenceFilter + def self.object_class + Commit + end - # Public: Find commit references in text - # - # CommitReferenceFilter.references_in(text) do |match, commit, project_ref| - # "#{commit}" - # end - # - # text - String text to search. - # - # Yields the String match, the String commit identifier, and an optional - # String of the external project reference. - # - # Returns a String replaced with the return of the block. def self.references_in(text) text.gsub(Commit.reference_pattern) do |match| - yield match, $~[:commit], $~[:project] + yield match, $~[:commit], $~[:project], $~ end end @@ -31,58 +21,32 @@ module Gitlab return unless project id = node.attr("data-commit") - commit = commit_from_ref(project, id) + commit = find_object(project, id) return unless commit { commit: commit } end - def call - replace_text_nodes_matching(Commit.reference_pattern) do |content| - commit_link_filter(content) - end - end - - # Replace commit references in text with links to the commit specified. - # - # text - String text to replace references in. - # - # Returns a String with commit references replaced with links. All links - # have `gfm` and `gfm-commit` class names attached for styling. - def commit_link_filter(text) - self.class.references_in(text) do |match, id, project_ref| - project = self.project_from_ref(project_ref) - - if commit = self.class.commit_from_ref(project, id) - url = url_for_commit(project, commit) - - title = escape_once(commit.link_title) - klass = reference_class(:commit) - data = data_attribute(project: project.id, commit: id) - - project_ref += '@' if project_ref - - %(#{project_ref}#{commit.short_id}) - else - match - end - end - end - - def self.commit_from_ref(project, id) + def self.find_object(project, id) if project && project.valid_repo? project.commit(id) end end - def url_for_commit(project, commit) + def find_object(*args) + self.class.find_object(*args) + end + + def url_for_object(commit, project) h = Gitlab::Application.routes.url_helpers h.namespace_project_commit_url(project.namespace, project, commit, only_path: context[:only_path]) end + + def object_link_title(commit) + commit.link_title + end end end end diff --git a/lib/gitlab/markdown/external_link_filter.rb b/lib/gitlab/markdown/external_link_filter.rb index 29e51b6ade6..b6792932016 100644 --- a/lib/gitlab/markdown/external_link_filter.rb +++ b/lib/gitlab/markdown/external_link_filter.rb @@ -10,6 +10,9 @@ module Gitlab doc.search('a').each do |node| next unless node.has_attribute?('href') + klass = node.attribute('class') + next if klass && klass.include?('gfm') + link = node.attribute('href').value # Skip non-HTTP(S) links diff --git a/lib/gitlab/markdown/merge_request_reference_filter.rb b/lib/gitlab/markdown/merge_request_reference_filter.rb index 1f47f03c94e..3780a14a130 100644 --- a/lib/gitlab/markdown/merge_request_reference_filter.rb +++ b/lib/gitlab/markdown/merge_request_reference_filter.rb @@ -20,6 +20,16 @@ module Gitlab h.namespace_project_merge_request_url(project.namespace, project, mr, only_path: context[:only_path]) end + + def object_link_text_extras(object, matches) + extras = super + + if matches[:path] && matches[:path] == '/diffs' + extras.unshift "diffs" + end + + extras + end end end end diff --git a/lib/gitlab/markdown/redactor_filter.rb b/lib/gitlab/markdown/redactor_filter.rb index a1f3a8a8ebf..2a58c798f9f 100644 --- a/lib/gitlab/markdown/redactor_filter.rb +++ b/lib/gitlab/markdown/redactor_filter.rb @@ -12,7 +12,10 @@ module Gitlab def call doc.css('a.gfm').each do |node| unless user_can_reference?(node) - node.replace(node.text) + # The reference should be replaced by the original text, + # which is not always the same as the rendered text. + text = node.attribute('data-original') || node.text + node.replace(text) end end -- cgit v1.2.1 From f9017a2b0384eef3f99ec2f3f1f2ef156afff2b8 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 30 Nov 2015 21:15:19 +0100 Subject: Have ClosingIssueExtractor recognize all referenced issues --- lib/gitlab/closing_issue_extractor.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/closing_issue_extractor.rb b/lib/gitlab/closing_issue_extractor.rb index aeec595782c..70b9943d7eb 100644 --- a/lib/gitlab/closing_issue_extractor.rb +++ b/lib/gitlab/closing_issue_extractor.rb @@ -1,6 +1,10 @@ module Gitlab class ClosingIssueExtractor - ISSUE_CLOSING_REGEX = Regexp.new(Gitlab.config.gitlab.issue_closing_pattern) + ISSUE_CLOSING_REGEX = begin + pattern = Gitlab.config.gitlab.issue_closing_pattern + pattern = pattern.sub('%{issue_ref}', "(?:#{Issue.reference_pattern})") + Regexp.new(pattern).freeze + end def initialize(project, current_user = nil) @extractor = Gitlab::ReferenceExtractor.new(project, current_user) @@ -9,10 +13,12 @@ module Gitlab def closed_by_message(message) return [] if message.nil? - closing_statements = message.scan(ISSUE_CLOSING_REGEX). - map { |ref| ref[0] }.join(" ") + closing_statements = [] + message.scan(ISSUE_CLOSING_REGEX) do + closing_statements << Regexp.last_match[0] + end - @extractor.analyze(closing_statements) + @extractor.analyze(closing_statements.join(" ")) @extractor.issues end -- cgit v1.2.1 From bd4ab21c07061e06166b08d86157e4004665ccbc Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 1 Dec 2015 12:49:22 +0100 Subject: Fix code docs --- lib/gitlab/markdown/abstract_reference_filter.rb | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/abstract_reference_filter.rb b/lib/gitlab/markdown/abstract_reference_filter.rb index 4adc44361b7..02a9e05a699 100644 --- a/lib/gitlab/markdown/abstract_reference_filter.rb +++ b/lib/gitlab/markdown/abstract_reference_filter.rb @@ -2,8 +2,8 @@ require 'gitlab/markdown' module Gitlab module Markdown - # Issues, Snippets and Merge Requests shares similar functionality in refernce filtering. - # All this functionality moved to this class + # Issues, Snippets, Merge Requests, Commits and Commit Ranges share + # similar functionality in refernce filtering. class AbstractReferenceFilter < ReferenceFilter include CrossProjectReference @@ -26,16 +26,15 @@ module Gitlab # Public: Find references in text (like `!123` for merge requests) # - # AnyReferenceFilter.references_in(text) do |match, object| - # "PREFIX#{object}" + # AnyReferenceFilter.references_in(text) do |match, id, project_ref, matches| + # object = find_object(project_ref, id) + # "#{object.to_reference}" # end # - # PREFIX - symbol that detects reference (like ! for merge requests) - # object - reference object (snippet, merget request etc) # text - String text to search. # - # Yields the String match, the Integer referenced object ID, and an optional String - # of the external project reference. + # Yields the String match, the Integer referenced object ID, an optional String + # of the external project reference, and all of the matchdata. # # Returns a String replaced with the return of the block. def self.references_in(text) -- cgit v1.2.1 From 62c14ba2edf9ac4b4bb1e8c46c0c60f1b6574909 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 1 Dec 2015 12:58:45 +0100 Subject: Render commit reference using short sha, but include full sha in comment. --- lib/gitlab/markdown/abstract_reference_filter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/abstract_reference_filter.rb b/lib/gitlab/markdown/abstract_reference_filter.rb index 02a9e05a699..f6df9518fc6 100644 --- a/lib/gitlab/markdown/abstract_reference_filter.rb +++ b/lib/gitlab/markdown/abstract_reference_filter.rb @@ -82,7 +82,7 @@ module Gitlab data = data_attribute(project: project.id, object_sym => object.id, original: match) url = matches[:url] || url_for_object(object, project) - text = object.to_reference(context[:project]) + text = object.reference_link_text(context[:project]) extras = object_link_text_extras(object, matches) text += " (#{extras.join(", ")})" if extras.any? -- cgit v1.2.1 From f3ea06eb7f8bef748be0882cb0b4fb58deed8eef Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 1 Dec 2015 15:51:27 +0100 Subject: Autolink first so we don't pick up numeric anchors as issue references. --- lib/gitlab/closing_issue_extractor.rb | 2 +- lib/gitlab/markdown.rb | 5 ++--- lib/gitlab/markdown/abstract_reference_filter.rb | 20 ++++++++++++------- .../markdown/commit_range_reference_filter.rb | 4 ++-- lib/gitlab/markdown/commit_reference_filter.rb | 4 ++-- lib/gitlab/markdown/external_link_filter.rb | 7 ++----- .../markdown/merge_request_reference_filter.rb | 2 +- lib/gitlab/markdown/redactor_filter.rb | 2 +- lib/gitlab/markdown/reference_filter.rb | 23 ++++++++++++++++++++++ lib/gitlab/reference_extractor.rb | 14 ++++++++++--- 10 files changed, 58 insertions(+), 25 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/closing_issue_extractor.rb b/lib/gitlab/closing_issue_extractor.rb index 70b9943d7eb..0cf4c918736 100644 --- a/lib/gitlab/closing_issue_extractor.rb +++ b/lib/gitlab/closing_issue_extractor.rb @@ -2,7 +2,7 @@ module Gitlab class ClosingIssueExtractor ISSUE_CLOSING_REGEX = begin pattern = Gitlab.config.gitlab.issue_closing_pattern - pattern = pattern.sub('%{issue_ref}', "(?:#{Issue.reference_pattern})") + pattern = pattern.sub('%{issue_ref}', "(?:(?:#{Issue.link_reference_pattern})|(?:#{Issue.reference_pattern}))") Regexp.new(pattern).freeze end diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index ee458eda025..b082bfc434b 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -181,6 +181,8 @@ module Gitlab Gitlab::Markdown::RelativeLinkFilter, Gitlab::Markdown::EmojiFilter, Gitlab::Markdown::TableOfContentsFilter, + Gitlab::Markdown::AutolinkFilter, + Gitlab::Markdown::ExternalLinkFilter, Gitlab::Markdown::UserReferenceFilter, Gitlab::Markdown::IssueReferenceFilter, @@ -191,9 +193,6 @@ module Gitlab Gitlab::Markdown::CommitReferenceFilter, Gitlab::Markdown::LabelReferenceFilter, - Gitlab::Markdown::AutolinkFilter, - Gitlab::Markdown::ExternalLinkFilter, - Gitlab::Markdown::TaskListFilter ] end diff --git a/lib/gitlab/markdown/abstract_reference_filter.rb b/lib/gitlab/markdown/abstract_reference_filter.rb index f6df9518fc6..37ed423eeda 100644 --- a/lib/gitlab/markdown/abstract_reference_filter.rb +++ b/lib/gitlab/markdown/abstract_reference_filter.rb @@ -37,8 +37,8 @@ module Gitlab # of the external project reference, and all of the matchdata. # # Returns a String replaced with the return of the block. - def self.references_in(text) - text.gsub(object_class.reference_pattern) do |match| + def self.references_in(text, pattern = object_class.reference_pattern) + text.gsub(pattern) do |match| yield match, $~[object_sym].to_i, $~[:project], $~ end end @@ -61,7 +61,11 @@ module Gitlab def call replace_text_nodes_matching(object_class.reference_pattern) do |content| - object_link_filter(content) + object_link_filter(content, object_class.reference_pattern) + end + + replace_link_nodes_matching(object_class.link_reference_pattern) do |content| + object_link_filter(content, object_class.link_reference_pattern) end end @@ -72,15 +76,17 @@ module Gitlab # # Returns a String with references replaced with links. All links # have `gfm` and `gfm-OBJECT_NAME` class names attached for styling. - def object_link_filter(text) - references_in(text) do |match, id, project_ref, matches| + def object_link_filter(text, pattern) + references_in(text, pattern) do |match, id, project_ref, matches| project = project_from_ref(project_ref) if project && object = find_object(project, id) title = escape_once(object_link_title(object)) klass = reference_class(object_sym) data = data_attribute(project: project.id, object_sym => object.id, original: match) - url = matches[:url] || url_for_object(object, project) + + url = matches[:url] if matches.names.include?("url") + url ||= url_for_object(object, project) text = object.reference_link_text(context[:project]) @@ -99,7 +105,7 @@ module Gitlab def object_link_text_extras(object, matches) extras = [] - if matches[:anchor] && matches[:anchor] =~ /\A\#note_(\d+)\z/ + if matches.names.include?("anchor") && matches[:anchor] && matches[:anchor] =~ /\A\#note_(\d+)\z/ extras << "comment #{$1}" end diff --git a/lib/gitlab/markdown/commit_range_reference_filter.rb b/lib/gitlab/markdown/commit_range_reference_filter.rb index f24bed76193..36b3258ef76 100644 --- a/lib/gitlab/markdown/commit_range_reference_filter.rb +++ b/lib/gitlab/markdown/commit_range_reference_filter.rb @@ -10,8 +10,8 @@ module Gitlab CommitRange end - def self.references_in(text) - text.gsub(CommitRange.reference_pattern) do |match| + def self.references_in(text, pattern = CommitRange.reference_pattern) + text.gsub(pattern) do |match| yield match, $~[:commit_range], $~[:project], $~ end end diff --git a/lib/gitlab/markdown/commit_reference_filter.rb b/lib/gitlab/markdown/commit_reference_filter.rb index cc7abc08c87..b4036578e60 100644 --- a/lib/gitlab/markdown/commit_reference_filter.rb +++ b/lib/gitlab/markdown/commit_reference_filter.rb @@ -10,8 +10,8 @@ module Gitlab Commit end - def self.references_in(text) - text.gsub(Commit.reference_pattern) do |match| + def self.references_in(text, pattern = Commit.reference_pattern) + text.gsub(pattern) do |match| yield match, $~[:commit], $~[:project], $~ end end diff --git a/lib/gitlab/markdown/external_link_filter.rb b/lib/gitlab/markdown/external_link_filter.rb index b6792932016..e09dfcb83c8 100644 --- a/lib/gitlab/markdown/external_link_filter.rb +++ b/lib/gitlab/markdown/external_link_filter.rb @@ -8,12 +8,9 @@ module Gitlab class ExternalLinkFilter < HTML::Pipeline::Filter def call doc.search('a').each do |node| - next unless node.has_attribute?('href') + link = node.attr('href') - klass = node.attribute('class') - next if klass && klass.include?('gfm') - - link = node.attribute('href').value + next unless link # Skip non-HTTP(S) links next unless link.start_with?('http') diff --git a/lib/gitlab/markdown/merge_request_reference_filter.rb b/lib/gitlab/markdown/merge_request_reference_filter.rb index 3780a14a130..de71fc76a9b 100644 --- a/lib/gitlab/markdown/merge_request_reference_filter.rb +++ b/lib/gitlab/markdown/merge_request_reference_filter.rb @@ -24,7 +24,7 @@ module Gitlab def object_link_text_extras(object, matches) extras = super - if matches[:path] && matches[:path] == '/diffs' + if matches.names.include?("path") && matches[:path] && matches[:path] == '/diffs' extras.unshift "diffs" end diff --git a/lib/gitlab/markdown/redactor_filter.rb b/lib/gitlab/markdown/redactor_filter.rb index 2a58c798f9f..bea714a01e7 100644 --- a/lib/gitlab/markdown/redactor_filter.rb +++ b/lib/gitlab/markdown/redactor_filter.rb @@ -14,7 +14,7 @@ module Gitlab unless user_can_reference?(node) # The reference should be replaced by the original text, # which is not always the same as the rendered text. - text = node.attribute('data-original') || node.text + text = node.attr('data-original') || node.text node.replace(text) end end diff --git a/lib/gitlab/markdown/reference_filter.rb b/lib/gitlab/markdown/reference_filter.rb index a4c560f578c..e52633ee74c 100644 --- a/lib/gitlab/markdown/reference_filter.rb +++ b/lib/gitlab/markdown/reference_filter.rb @@ -122,6 +122,29 @@ module Gitlab doc end + def replace_link_nodes_matching(pattern) + return doc if project.nil? + + doc.search('a').each do |node| + klass = node.attr('class') + next if klass && klass.include?('gfm') + + link = node.attr('href') + text = node.text + + # Ignore ending punctionation like periods or commas + next unless link == text && text =~ /\A#{pattern}/ + + html = yield text + + next if html == text + + node.replace(html) + end + + doc + end + # Ensure that a :project key exists in context # # Note that while the key might exist, its value could be nil! diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index da8df8a3025..3c3478a1271 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -41,14 +41,14 @@ module Gitlab # Returns the results Array for the requested filter type def pipeline_result(filter_type) return [] if @text.blank? - + klass = "#{filter_type.to_s.camelize}ReferenceFilter" filter = Gitlab::Markdown.const_get(klass) context = { project: project, current_user: current_user, - + # We don't actually care about the links generated only_path: true, ignore_blockquotes: true, @@ -58,7 +58,15 @@ module Gitlab reference_filter: filter } - pipeline = HTML::Pipeline.new([filter, Gitlab::Markdown::ReferenceGathererFilter], context) + # We need to autolink first to finds links to referables, and to prevent + # numeric anchors to be parsed as issue references. + filters = [ + Gitlab::Markdown::AutolinkFilter, + filter, + Gitlab::Markdown::ReferenceGathererFilter + ] + + pipeline = HTML::Pipeline.new(filters, context) result = pipeline.call(@text) values = result[:references][filter_type].uniq -- cgit v1.2.1 From 1d6d757dbd563500671f57f45faa808510a612d1 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 1 Dec 2015 16:25:56 +0100 Subject: Allow reference format as link href --- lib/gitlab/markdown.rb | 3 ++- lib/gitlab/markdown/abstract_reference_filter.rb | 22 ++++++++++------ .../markdown/external_issue_reference_filter.rb | 10 ++++++-- lib/gitlab/markdown/label_reference_filter.rb | 10 ++++++-- lib/gitlab/markdown/reference_filter.rb | 29 +++++++++++++++++++++- lib/gitlab/markdown/relative_link_filter.rb | 3 +++ lib/gitlab/markdown/user_reference_filter.rb | 28 ++++++++++++--------- 7 files changed, 80 insertions(+), 25 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index b082bfc434b..886a09f52af 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -178,7 +178,6 @@ module Gitlab Gitlab::Markdown::SanitizationFilter, Gitlab::Markdown::UploadLinkFilter, - Gitlab::Markdown::RelativeLinkFilter, Gitlab::Markdown::EmojiFilter, Gitlab::Markdown::TableOfContentsFilter, Gitlab::Markdown::AutolinkFilter, @@ -193,6 +192,8 @@ module Gitlab Gitlab::Markdown::CommitReferenceFilter, Gitlab::Markdown::LabelReferenceFilter, + Gitlab::Markdown::RelativeLinkFilter, + Gitlab::Markdown::TaskListFilter ] end diff --git a/lib/gitlab/markdown/abstract_reference_filter.rb b/lib/gitlab/markdown/abstract_reference_filter.rb index 37ed423eeda..b044a73ed17 100644 --- a/lib/gitlab/markdown/abstract_reference_filter.rb +++ b/lib/gitlab/markdown/abstract_reference_filter.rb @@ -2,7 +2,7 @@ require 'gitlab/markdown' module Gitlab module Markdown - # Issues, Snippets, Merge Requests, Commits and Commit Ranges share + # Issues, Merge Requests, Snippets, Commits and Commit Ranges share # similar functionality in refernce filtering. class AbstractReferenceFilter < ReferenceFilter include CrossProjectReference @@ -64,8 +64,13 @@ module Gitlab object_link_filter(content, object_class.reference_pattern) end - replace_link_nodes_matching(object_class.link_reference_pattern) do |content| - object_link_filter(content, object_class.link_reference_pattern) + replace_link_nodes_with_href(object_class.reference_pattern) do |link, text| + object_link_filter(link, object_class.reference_pattern, link_text: text) + end + + replace_link_nodes_with_text(object_class.link_reference_pattern) do |text| + object_link_filter(text, object_class.link_reference_pattern) + end end end @@ -76,7 +81,7 @@ module Gitlab # # Returns a String with references replaced with links. All links # have `gfm` and `gfm-OBJECT_NAME` class names attached for styling. - def object_link_filter(text, pattern) + def object_link_filter(text, pattern, link_text: nil) references_in(text, pattern) do |match, id, project_ref, matches| project = project_from_ref(project_ref) @@ -88,10 +93,13 @@ module Gitlab url = matches[:url] if matches.names.include?("url") url ||= url_for_object(object, project) - text = object.reference_link_text(context[:project]) + text = link_text + unless text + text = object.reference_link_text(context[:project]) - extras = object_link_text_extras(object, matches) - text += " (#{extras.join(", ")})" if extras.any? + extras = object_link_text_extras(object, matches) + text += " (#{extras.join(", ")})" if extras.any? + end %(#{match}) + class="#{klass}">#{text}) end end diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb index 618acb7a578..4d0507b607d 100644 --- a/lib/gitlab/markdown/label_reference_filter.rb +++ b/lib/gitlab/markdown/label_reference_filter.rb @@ -30,6 +30,10 @@ module Gitlab replace_text_nodes_matching(Label.reference_pattern) do |content| label_link_filter(content) end + + replace_link_nodes_with_href(Label.reference_pattern) do |link, text| + label_link_filter(link, link_text: text) + end end # Replace label references in text with links to the label specified. @@ -38,7 +42,7 @@ module Gitlab # # Returns a String with label references replaced with links. All links # have `gfm` and `gfm-label` class names attached for styling. - def label_link_filter(text) + def label_link_filter(text, link_text: nil) project = context[:project] self.class.references_in(text) do |match, id, name| @@ -49,8 +53,10 @@ module Gitlab klass = reference_class(:label) data = data_attribute(project: project.id, label: label.id) + text = link_text || render_colored_label(label) + %(#{render_colored_label(label)}) + class="#{klass}">#{text}) else match end diff --git a/lib/gitlab/markdown/reference_filter.rb b/lib/gitlab/markdown/reference_filter.rb index e52633ee74c..2597784c7ae 100644 --- a/lib/gitlab/markdown/reference_filter.rb +++ b/lib/gitlab/markdown/reference_filter.rb @@ -122,7 +122,7 @@ module Gitlab doc end - def replace_link_nodes_matching(pattern) + def replace_link_nodes_with_text(pattern) return doc if project.nil? doc.search('a').each do |node| @@ -132,6 +132,9 @@ module Gitlab link = node.attr('href') text = node.text + next unless link && text + + link = URI.decode(link) # Ignore ending punctionation like periods or commas next unless link == text && text =~ /\A#{pattern}/ @@ -145,6 +148,30 @@ module Gitlab doc end + def replace_link_nodes_with_href(pattern) + return doc if project.nil? + + doc.search('a').each do |node| + klass = node.attr('class') + next if klass && klass.include?('gfm') + + link = node.attr('href') + text = node.text + + next unless link && text + link = URI.decode(link) + next unless link && link =~ /\A#{pattern}\z/ + + html = yield link, text + + next if html == link + + node.replace(html) + end + + doc + end + # Ensure that a :project key exists in context # # Note that while the key might exist, its value could be nil! diff --git a/lib/gitlab/markdown/relative_link_filter.rb b/lib/gitlab/markdown/relative_link_filter.rb index 632be4d7542..692c51fd324 100644 --- a/lib/gitlab/markdown/relative_link_filter.rb +++ b/lib/gitlab/markdown/relative_link_filter.rb @@ -17,6 +17,9 @@ module Gitlab return doc unless linkable_files? doc.search('a').each do |el| + klass = el.attr('class') + next if klass && klass.include?('gfm') + process_link_attr el.attribute('href') end diff --git a/lib/gitlab/markdown/user_reference_filter.rb b/lib/gitlab/markdown/user_reference_filter.rb index ab5e1f6fe9e..0a20d9c0347 100644 --- a/lib/gitlab/markdown/user_reference_filter.rb +++ b/lib/gitlab/markdown/user_reference_filter.rb @@ -52,6 +52,10 @@ module Gitlab replace_text_nodes_matching(User.reference_pattern) do |content| user_link_filter(content) end + + replace_link_nodes_with_href(User.reference_pattern) do |link, text| + user_link_filter(link, link_text: text) + end end # Replace `@user` user references in text with links to the referenced @@ -61,12 +65,12 @@ module Gitlab # # Returns a String with `@user` references replaced with links. All links # have `gfm` and `gfm-project_member` class names attached for styling. - def user_link_filter(text) + def user_link_filter(text, link_text: nil) self.class.references_in(text) do |match, username| if username == 'all' - link_to_all + link_to_all(link_text: link_text) elsif namespace = Namespace.find_by(path: username) - link_to_namespace(namespace) || match + link_to_namespace(namespace, link_text: link_text) || match else match end @@ -83,36 +87,36 @@ module Gitlab reference_class(:project_member) end - def link_to_all + def link_to_all(link_text: nil) project = context[:project] url = urls.namespace_project_url(project.namespace, project, only_path: context[:only_path]) data = data_attribute(project: project.id) - text = User.reference_prefix + 'all' + text = link_text || User.reference_prefix + 'all' link_tag(url, data, text) end - def link_to_namespace(namespace) + def link_to_namespace(namespace, link_text: nil) if namespace.is_a?(Group) - link_to_group(namespace.path, namespace) + link_to_group(namespace.path, namespace, link_text: link_text) else - link_to_user(namespace.path, namespace) + link_to_user(namespace.path, namespace, link_text: link_text) end end - def link_to_group(group, namespace) + def link_to_group(group, namespace, link_text: nil) url = urls.group_url(group, only_path: context[:only_path]) data = data_attribute(group: namespace.id) - text = Group.reference_prefix + group + text = link_text || Group.reference_prefix + group link_tag(url, data, text) end - def link_to_user(user, namespace) + def link_to_user(user, namespace, link_text: nil) url = urls.user_url(user, only_path: context[:only_path]) data = data_attribute(user: namespace.owner_id) - text = User.reference_prefix + user + text = link_text || User.reference_prefix + user link_tag(url, data, text) end -- cgit v1.2.1 From d4030a845eebcb913a7aac1e8fd502706669d0cc Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 1 Dec 2015 16:26:05 +0100 Subject: Pick up direct links to issues/MRs as references. --- lib/gitlab/markdown/abstract_reference_filter.rb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/abstract_reference_filter.rb b/lib/gitlab/markdown/abstract_reference_filter.rb index b044a73ed17..0ec55c0207e 100644 --- a/lib/gitlab/markdown/abstract_reference_filter.rb +++ b/lib/gitlab/markdown/abstract_reference_filter.rb @@ -60,17 +60,27 @@ module Gitlab end def call + # `#123` replace_text_nodes_matching(object_class.reference_pattern) do |content| object_link_filter(content, object_class.reference_pattern) end + # `[Issue](#123)`, which is turned into + # `Issue` replace_link_nodes_with_href(object_class.reference_pattern) do |link, text| object_link_filter(link, object_class.reference_pattern, link_text: text) end + # `http://gitlab.example.com/namespace/project/issues/123`, which is turned into + # `http://gitlab.example.com/namespace/project/issues/123` replace_link_nodes_with_text(object_class.link_reference_pattern) do |text| object_link_filter(text, object_class.link_reference_pattern) end + + # `[Issue](http://gitlab.example.com/namespace/project/issues/123)`, which is turned into + # `Issue` + replace_link_nodes_with_href(object_class.link_reference_pattern) do |link, text| + object_link_filter(link, object_class.link_reference_pattern, link_text: text) end end @@ -88,7 +98,12 @@ module Gitlab if project && object = find_object(project, id) title = escape_once(object_link_title(object)) klass = reference_class(object_sym) - data = data_attribute(project: project.id, object_sym => object.id, original: match) + + data = data_attribute( + original: link_text || match, + project: project.id, + object_sym => object.id + ) url = matches[:url] if matches.names.include?("url") url ||= url_for_object(object, project) -- cgit v1.2.1 From 2f5074dc395c784f91abb3bacd23e75ce080a547 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 1 Dec 2015 17:13:47 +0100 Subject: Expand inline docs. --- lib/gitlab/markdown/abstract_reference_filter.rb | 6 ++++-- lib/gitlab/markdown/reference_filter.rb | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/abstract_reference_filter.rb b/lib/gitlab/markdown/abstract_reference_filter.rb index 0ec55c0207e..9488e980c08 100644 --- a/lib/gitlab/markdown/abstract_reference_filter.rb +++ b/lib/gitlab/markdown/abstract_reference_filter.rb @@ -3,7 +3,7 @@ require 'gitlab/markdown' module Gitlab module Markdown # Issues, Merge Requests, Snippets, Commits and Commit Ranges share - # similar functionality in refernce filtering. + # similar functionality in reference filtering. class AbstractReferenceFilter < ReferenceFilter include CrossProjectReference @@ -88,6 +88,8 @@ module Gitlab # to the referenced object's details page. # # text - String text to replace references in. + # pattern - Reference pattern to match against. + # link_text - Original content of the link being replaced. # # Returns a String with references replaced with links. All links # have `gfm` and `gfm-OBJECT_NAME` class names attached for styling. @@ -98,7 +100,7 @@ module Gitlab if project && object = find_object(project, id) title = escape_once(object_link_title(object)) klass = reference_class(object_sym) - + data = data_attribute( original: link_text || match, project: project.id, diff --git a/lib/gitlab/markdown/reference_filter.rb b/lib/gitlab/markdown/reference_filter.rb index 2597784c7ae..b6d93e05ec7 100644 --- a/lib/gitlab/markdown/reference_filter.rb +++ b/lib/gitlab/markdown/reference_filter.rb @@ -122,6 +122,18 @@ module Gitlab doc end + # Iterate through the document's link nodes, yielding the current node's + # content if: + # + # * The `project` context value is present AND + # * The node's content matches `pattern` + # + # pattern - Regex pattern against which to match the node's content + # + # Yields the current node's String contents. The result of the block will + # replace the node and update the current document. + # + # Returns the updated Nokogiri::HTML::DocumentFragment object. def replace_link_nodes_with_text(pattern) return doc if project.nil? @@ -148,6 +160,18 @@ module Gitlab doc end + # Iterate through the document's link nodes, yielding the current node's + # content if: + # + # * The `project` context value is present AND + # * The node's HREF matches `pattern` + # + # pattern - Regex pattern against which to match the node's HREF + # + # Yields the current node's String HREF and String content. + # The result of the block will replace the node and update the current document. + # + # Returns the updated Nokogiri::HTML::DocumentFragment object. def replace_link_nodes_with_href(pattern) return doc if project.nil? -- cgit v1.2.1 From a7682f8775a4609ac8c70151ffe8f3ccf3b767b6 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Tue, 24 Nov 2015 14:59:02 +0100 Subject: Specs for 'Merge When Build Succeeds' --- lib/api/entities.rb | 1 + lib/api/merge_requests.rb | 22 ++++++++-------------- 2 files changed, 9 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index d6aec03d7f5..6f9f71b0945 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -169,6 +169,7 @@ module API expose :description expose :work_in_progress?, as: :work_in_progress expose :milestone, using: Entities::Milestone + expose :merge_when_build_succeeds end class MergeRequestChanges < MergeRequest diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index b72f816932b..32cb1137ef7 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -179,11 +179,11 @@ module API # Merge MR # # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - ID of MR - # merge_commit_message (optional) - Custom merge commit message - # should_remove_source_branch - When true, the source branch will be deleted if possible - # merge_when_build_succeeds (optional) - When true, this MR will be merged when the build succeeds + # id (required) - The ID of a project + # merge_request_id (required) - ID of MR + # merge_commit_message (optional) - Custom merge commit message + # should_remove_source_branch (optional) - When true, the source branch will be deleted if possible + # merge_when_build_succeeds (optional) - When true, this MR will be merged when the build succeeds # Example: # PUT /projects/:id/merge_request/:merge_request_id/merge # @@ -193,12 +193,11 @@ module API # Merge request can not be merged # because user dont have permissions to push into target branch unauthorized! unless merge_request.can_be_merged_by?(current_user) - - not_allowed! unless merge_request.open? && !merge_request.work_in_progress? + not_allowed! if !merge_request.open? || merge_request.work_in_progress? merge_request.check_if_can_be_merged if merge_request.unchecked? - render_api_error!('Branch cannot be merged', 406) if merge_request.can_be_merged? + render_api_error!('Branch cannot be merged', 406) unless merge_request.can_be_merged? merge_params = { commit_message: params[:merge_commit_message], @@ -206,7 +205,7 @@ module API } if parse_boolean(params[:merge_when_build_succeeds]) && merge_request.ci_commit && merge_request.ci_commit.active? - ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). + ::MergeRequests::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). execute(merge_request) else ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params). @@ -224,11 +223,6 @@ module API post ":id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds" do merge_request = user_project.merge_requests.find(params[:merge_request_id]) - allowed = ::Gitlab::GitAccess.new(current_user, user_project). - can_push_to_branch?(merge_request.target_branch) - - # Merge request can not be merged - # because user dont have permissions to push into target branch unauthorized! unless merge_request.can_cancel_merge_when_build_succeeds?(current_user) ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user).cancel(merge_request) -- cgit v1.2.1 From 044e0e33dce9371430a3c91e63f9f687b536d35b Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 2 Dec 2015 18:48:39 +0100 Subject: Allow invalid URLs in closing pattern --- lib/gitlab/closing_issue_extractor.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/closing_issue_extractor.rb b/lib/gitlab/closing_issue_extractor.rb index 0cf4c918736..9bef9037ad6 100644 --- a/lib/gitlab/closing_issue_extractor.rb +++ b/lib/gitlab/closing_issue_extractor.rb @@ -1,8 +1,10 @@ module Gitlab class ClosingIssueExtractor ISSUE_CLOSING_REGEX = begin + link_pattern = URI.regexp(%w(http https)) + pattern = Gitlab.config.gitlab.issue_closing_pattern - pattern = pattern.sub('%{issue_ref}', "(?:(?:#{Issue.link_reference_pattern})|(?:#{Issue.reference_pattern}))") + pattern = pattern.sub('%{issue_ref}', "(?:(?:#{link_pattern})|(?:#{Issue.reference_pattern}))") Regexp.new(pattern).freeze end -- cgit v1.2.1 From 162cd0099c6c1f4ee0051e35562636468e88ee0c Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Thu, 3 Dec 2015 10:33:38 +0200 Subject: fix deprecation messages in tests --- lib/gitlab/lfs/response.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/lfs/response.rb b/lib/gitlab/lfs/response.rb index c18dfbd485d..9be9a65671b 100644 --- a/lib/gitlab/lfs/response.rb +++ b/lib/gitlab/lfs/response.rb @@ -260,7 +260,7 @@ module Gitlab end def link_to_project(object) - if object && !object.projects.exists?(@project) + if object && !object.projects.exists?(@project.id) object.projects << @project object.save end -- cgit v1.2.1 From f905fd239c79f391ce5a7cc2c5c6648b3d6380e4 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 3 Dec 2015 14:00:00 +0100 Subject: Use URL helpers in specs --- lib/gitlab/markdown/label_reference_filter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb index a23aa0adeec..ec2b179b7de 100644 --- a/lib/gitlab/markdown/label_reference_filter.rb +++ b/lib/gitlab/markdown/label_reference_filter.rb @@ -65,8 +65,8 @@ module Gitlab def url_for_label(project, label) h = Gitlab::Application.routes.url_helpers - h.namespace_project_issues_path(project.namespace, project, - label_name: label.name) + h.namespace_project_issues_url( project.namespace, project, label_name: label.name, + only_path: context[:only_path]) end def render_colored_label(label) -- cgit v1.2.1 From 0de8e260662a62603dbee5efb133cd4f1e0f0ed7 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 3 Dec 2015 14:00:41 +0100 Subject: Pass original text along with label reference filter. --- lib/gitlab/markdown/label_reference_filter.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb index ec2b179b7de..36cf7a8f4ce 100644 --- a/lib/gitlab/markdown/label_reference_filter.rb +++ b/lib/gitlab/markdown/label_reference_filter.rb @@ -51,7 +51,11 @@ module Gitlab if label = project.labels.find_by(params) url = url_for_label(project, label) klass = reference_class(:label) - data = data_attribute(project: project.id, label: label.id) + data = data_attribute( + original: link_text || match, + project: project.id, + label: label.id + ) text = link_text || render_colored_label(label) -- cgit v1.2.1 From f9d954fae71d40a314a5812c1a7eec5a601d1575 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 3 Dec 2015 19:02:56 +0100 Subject: Satisfy rubocop --- lib/gitlab/markdown/label_reference_filter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb index 36cf7a8f4ce..a2026eecaeb 100644 --- a/lib/gitlab/markdown/label_reference_filter.rb +++ b/lib/gitlab/markdown/label_reference_filter.rb @@ -70,7 +70,7 @@ module Gitlab def url_for_label(project, label) h = Gitlab::Application.routes.url_helpers h.namespace_project_issues_url( project.namespace, project, label_name: label.name, - only_path: context[:only_path]) + only_path: context[:only_path]) end def render_colored_label(label) -- cgit v1.2.1 From 0b68a0e79e1cbe12c44beb6c23e79d48b71f219e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 4 Dec 2015 11:08:10 +0100 Subject: Add API endpoint to fetch merge request commits list Signed-off-by: Dmitriy Zaporozhets --- lib/api/merge_requests.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'lib') diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 6eb84baf9cb..e7c5f808aea 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -76,6 +76,22 @@ module API present merge_request, with: Entities::MergeRequest end + # Show MR commits + # + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - The ID of MR + # + # Example: + # GET /projects/:id/merge_request/:merge_request_id/commits + # + get ':id/merge_request/:merge_request_id/commits' do + merge_request = user_project.merge_requests. + find(params[:merge_request_id]) + authorize! :read_merge_request, merge_request + present merge_request.commits, with: Entities::RepoCommit + end + # Show MR changes # # Parameters: -- cgit v1.2.1 From 3227a5ead22c90873794b0c0e4c788436283fb3e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 4 Dec 2015 12:21:06 +0100 Subject: Extent Event and Note API * add note to Events API * add author section to Events API * add noteable_id and noteable_type to Notes API Signed-off-by: Dmitriy Zaporozhets --- lib/api/entities.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 9f337bc3cc6..96b73df6af9 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -194,6 +194,7 @@ module API expose :author, using: Entities::UserBasic expose :created_at expose :system?, as: :system + expose :noteable_id, :noteable_type # upvote? and downvote? are deprecated, always return false expose :upvote?, as: :upvote expose :downvote?, as: :downvote @@ -224,6 +225,8 @@ module API expose :target_id, :target_type, :author_id expose :data, :target_title expose :created_at + expose :note, using: Entities::Note, if: ->(event, options) { event.note? } + expose :author, using: Entities::UserBasic, if: ->(event, options) { event.author } expose :author_username do |event, options| if event.author -- cgit v1.2.1 From b2c4675cb0e681027334e5bd046451d3116924c8 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Fri, 4 Dec 2015 12:32:13 +0100 Subject: Recursivity needed if a fork is a fork of a fork. --- lib/gitlab/lfs/response.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/lfs/response.rb b/lib/gitlab/lfs/response.rb index 9be9a65671b..9d9617761b3 100644 --- a/lib/gitlab/lfs/response.rb +++ b/lib/gitlab/lfs/response.rb @@ -220,7 +220,7 @@ module Gitlab def storage_project(project) if project.forked? - project.forked_from_project + storage_project(project.forked_from_project) else project end -- cgit v1.2.1 From 5c1b49f494f07bf37ba3c60f3b9f70d1842d8b60 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Fri, 4 Dec 2015 16:23:21 +0200 Subject: Add added, modified and removed properties to commit object in webhook --- lib/gitlab/push_data_builder.rb | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb index fa068d50763..cdcdb02a052 100644 --- a/lib/gitlab/push_data_builder.rb +++ b/lib/gitlab/push_data_builder.rb @@ -18,10 +18,7 @@ module Gitlab # homepage: String, # }, # commits: Array, - # total_commits_count: Fixnum, - # added: ["CHANGELOG"], - # modified: [], - # removed: ["tmp/file.txt"] + # total_commits_count: Fixnum # } # def build(project, user, oldrev, newrev, ref, commits = [], message = nil) @@ -37,7 +34,6 @@ module Gitlab type = Gitlab::Git.tag_ref?(ref) ? "tag_push" : "push" - repo_changes = repo_changes(project, newrev, oldrev) # Hash to be passed as post_receive_data data = { object_kind: type, @@ -60,10 +56,7 @@ module Gitlab visibility_level: project.visibility_level }, commits: commit_attrs, - total_commits_count: commits_count, - added: repo_changes[:added], - modified: repo_changes[:modified], - removed: repo_changes[:removed] + total_commits_count: commits_count } data @@ -94,27 +87,6 @@ module Gitlab newrev end end - - def repo_changes(project, newrev, oldrev) - changes = { added: [], modified: [], removed: [] } - compare_result = CompareService.new. - execute(project, newrev, project, oldrev) - - if compare_result - compare_result.diffs.each do |diff| - case true - when diff.deleted_file - changes[:removed] << diff.old_path - when diff.renamed_file, diff.new_file - changes[:added] << diff.new_path - else - changes[:modified] << diff.new_path - end - end - end - - changes - end end end end -- cgit v1.2.1 From f1fd4880d9bbb7c34e910b357bc52874d2e6188e Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 2 Dec 2015 20:11:58 +0000 Subject: Check GitLab Workhorse status in init.d script when reporting all components are up and running Closes https://github.com/gitlabhq/gitlabhq/issues/9869 --- lib/support/init.d/gitlab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab index f0a6c2b30e9..43fda6fa92e 100755 --- a/lib/support/init.d/gitlab +++ b/lib/support/init.d/gitlab @@ -327,7 +327,7 @@ print_status() { printf "The GitLab MailRoom email processor is \033[31mnot running\033[0m.\n" fi fi - if [ "$web_status" = "0" ] && [ "$sidekiq_status" = "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" = "0" ]; }; then + if [ "$web_status" = "0" ] && [ "$sidekiq_status" = "0" ] && [ "$gitlab_workhorse_status" = "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" = "0" ]; }; then printf "GitLab and all its components are \033[32mup and running\033[0m.\n" fi } -- cgit v1.2.1 From 1c4213acd5dde6ce44a70b79dd766e9e7f8b59b4 Mon Sep 17 00:00:00 2001 From: Vyacheslav Stetskevych Date: Sun, 6 Dec 2015 03:10:29 +0200 Subject: Fix gitlab-ssl nginx config to work when multiple server_names are served over https --- lib/support/nginx/gitlab-ssl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl index 016f7a536fb..79fe1474821 100644 --- a/lib/support/nginx/gitlab-ssl +++ b/lib/support/nginx/gitlab-ssl @@ -56,7 +56,7 @@ server { listen [::]:80 ipv6only=on default_server; server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com server_tokens off; ## Don't show the nginx version number, a security best practice - return 301 https://$server_name$request_uri; + return 301 https://$http_host$request_uri; access_log /var/log/nginx/gitlab_access.log; error_log /var/log/nginx/gitlab_error.log; } -- cgit v1.2.1 From 631a30276e30354cfde6b759527abbb26ff6cf96 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sat, 5 Dec 2015 17:36:19 -0800 Subject: Fix API setting of 'public' attribute to false will make a project private Closes #3864 --- lib/api/projects.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 2b4ada6e2eb..6928fe0eb9d 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -7,8 +7,12 @@ module API helpers do def map_public_to_visibility_level(attrs) publik = attrs.delete(:public) - publik = parse_boolean(publik) - attrs[:visibility_level] = Gitlab::VisibilityLevel::PUBLIC if !attrs[:visibility_level].present? && publik == true + if publik.present? && !attrs[:visibility_level].present? + publik = parse_boolean(publik) + # Since setting the public attribute to private could mean either + # private or internal, use the more conservative option, private. + attrs[:visibility_level] = (publik == true) ? Gitlab::VisibilityLevel::PUBLIC : Gitlab::VisibilityLevel::PRIVATE + end attrs end end -- cgit v1.2.1 From 5df2c4419c5019b5003ddfa6adb59c84c3d9910c Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Mon, 7 Dec 2015 14:11:15 +0200 Subject: fox specs --- lib/gitlab/push_data_builder.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb index cdcdb02a052..5842b740e8e 100644 --- a/lib/gitlab/push_data_builder.rb +++ b/lib/gitlab/push_data_builder.rb @@ -30,7 +30,9 @@ module Gitlab # For performance purposes maximum 20 latest commits # will be passed as post receive hook data. - commit_attrs = commits_limited.map(&:hook_attrs) + commit_attrs = commits_limited.map do |commit| + commit.hook_attrs(true) + end type = Gitlab::Git.tag_ref?(ref) ? "tag_push" : "push" -- cgit v1.2.1 From 3c97cbc74cf87856ed7b1af197358d4e3adb1240 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Mon, 7 Dec 2015 15:13:06 +0200 Subject: fixes after review --- lib/gitlab/push_data_builder.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb index 5842b740e8e..4f9cdef3869 100644 --- a/lib/gitlab/push_data_builder.rb +++ b/lib/gitlab/push_data_builder.rb @@ -31,7 +31,7 @@ module Gitlab # For performance purposes maximum 20 latest commits # will be passed as post receive hook data. commit_attrs = commits_limited.map do |commit| - commit.hook_attrs(true) + commit.hook_attrs(with_changed_files: true) end type = Gitlab::Git.tag_ref?(ref) ? "tag_push" : "push" -- cgit v1.2.1 From 8f817c7b08bcad23e1b047f84cc60d1748104e2a Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 7 Dec 2015 17:10:40 +0100 Subject: Add API group projects endpoint. --- lib/api/groups.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'lib') diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 024aeec2e14..1a14d870a4a 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -65,6 +65,18 @@ module API DestroyGroupService.new(group, current_user).execute end + # Get a list of projects in this group + # + # Example Request: + # GET /groups/:id/projects + get ":id/projects" do + group = find_group(params[:id]) + projects = group.projects + projects = filter_projects(projects) + projects = paginate projects + present projects, with: Entities::Project + end + # Transfer a project to the Group namespace # # Parameters: -- cgit v1.2.1 From b3200c8c44f2351d88d5d78d7ded3ac06001bd7c Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 1 Dec 2015 18:46:00 -0500 Subject: Move EmailValidator to app/validators --- lib/email_validator.rb | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 lib/email_validator.rb (limited to 'lib') diff --git a/lib/email_validator.rb b/lib/email_validator.rb deleted file mode 100644 index f509f0a5843..00000000000 --- a/lib/email_validator.rb +++ /dev/null @@ -1,21 +0,0 @@ -# Based on https://github.com/balexand/email_validator -# -# Extended to use only strict mode with following allowed characters: -# ' - apostrophe -# -# See http://www.remote.org/jochen/mail/info/chars.html -# -class EmailValidator < ActiveModel::EachValidator - @@default_options = {} - - def self.default_options - @@default_options - end - - def validate_each(record, attribute, value) - options = @@default_options.merge(self.options) - unless value =~ /\A\s*([-a-z0-9+._']{1,64})@((?:[-a-z0-9]+\.)+[a-z]{2,})\s*\z/i - record.errors.add(attribute, options[:message] || :invalid) - end - end -end -- cgit v1.2.1 From 2379c8beeac600c3352e33fda0c2b4f4f39c8b84 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 7 Dec 2015 16:29:39 -0500 Subject: Inline Gitlab::Blacklist in NamespaceValidator --- lib/gitlab/blacklist.rb | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 lib/gitlab/blacklist.rb (limited to 'lib') diff --git a/lib/gitlab/blacklist.rb b/lib/gitlab/blacklist.rb deleted file mode 100644 index 43145e0ee1b..00000000000 --- a/lib/gitlab/blacklist.rb +++ /dev/null @@ -1,34 +0,0 @@ -module Gitlab - module Blacklist - extend self - - def path - %w( - admin - dashboard - files - groups - help - profile - projects - search - public - assets - u - s - teams - merge_requests - issues - users - snippets - services - repository - hooks - notes - unsubscribes - all - ci - ) - end - end -end -- cgit v1.2.1 From 611912fe6870cac43fef9eea389f1229945f186a Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 7 Dec 2015 19:40:46 -0500 Subject: Store the demodulized reference filter name in data attribute --- lib/gitlab/markdown/filter/reference_gatherer_filter.rb | 2 +- lib/gitlab/markdown/reference_filter.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/filter/reference_gatherer_filter.rb b/lib/gitlab/markdown/filter/reference_gatherer_filter.rb index 00f983675e6..62f241b4967 100644 --- a/lib/gitlab/markdown/filter/reference_gatherer_filter.rb +++ b/lib/gitlab/markdown/filter/reference_gatherer_filter.rb @@ -31,7 +31,7 @@ module Gitlab return unless node.has_attribute?('data-reference-filter') reference_type = node.attr('data-reference-filter') - reference_filter = reference_type.constantize + reference_filter = Gitlab::Markdown.const_get(reference_type) return if context[:reference_filter] && reference_filter != context[:reference_filter] diff --git a/lib/gitlab/markdown/reference_filter.rb b/lib/gitlab/markdown/reference_filter.rb index 1b741d647d1..3b83b8bd8f8 100644 --- a/lib/gitlab/markdown/reference_filter.rb +++ b/lib/gitlab/markdown/reference_filter.rb @@ -57,14 +57,14 @@ module Gitlab # Examples: # # data_attribute(project: 1, issue: 2) - # # => "data-reference-filter=\"Gitlab::Markdown::SomeReferenceFilter\" data-project=\"1\" data-issue=\"2\"" + # # => "data-reference-filter=\"SomeReferenceFilter\" data-project=\"1\" data-issue=\"2\"" # # data_attribute(project: 3, merge_request: 4) - # # => "data-reference-filter=\"Gitlab::Markdown::SomeReferenceFilter\" data-project=\"3\" data-merge-request=\"4\"" + # # => "data-reference-filter=\"SomeReferenceFilter\" data-project=\"3\" data-merge-request=\"4\"" # # Returns a String def data_attribute(attributes = {}) - attributes[:reference_filter] = self.class.name + attributes[:reference_filter] = self.class.name.demodulize attributes.map { |key, value| %Q(data-#{key.to_s.dasherize}="#{value}") }.join(" ") end -- cgit v1.2.1 From 8c6db54e1283348f64b46733875db7ffe08993a6 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 17 Nov 2015 13:08:42 +0100 Subject: Extract repository_push_email to separate class --- lib/gitlab/email/repository_push.rb | 116 ++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 lib/gitlab/email/repository_push.rb (limited to 'lib') diff --git a/lib/gitlab/email/repository_push.rb b/lib/gitlab/email/repository_push.rb new file mode 100644 index 00000000000..f484f3cb76d --- /dev/null +++ b/lib/gitlab/email/repository_push.rb @@ -0,0 +1,116 @@ +module Gitlab + module Email + class RepositoryPush + attr_reader :compare, :reverse_compare, :send_from_cmmitter_email, :disable_diffs, + :action, :ref, :author_id + + def initialize(project_id, recipient, opts = {}) + raise ArgumentError, 'Missing arguments: author_id, ref, action' unless + opts[:author_id] && opts[:ref] && opts[:action] + + @project_id = project_id + @recipient = recipient + + @author_id = opts[:author_id] + @ref = opts[:ref] + @action = opts[:action] + + @compare = opts[:compare] || nil + @reverse_compare = opts[:reverse_compare] || false + @send_from_committer_email = opts[:send_from_committer_email] || false + @disable_diffs = opts[:disable_diffs] || false + + @author = author + @project = project + @commits = commits + @diffs = diffs + @ref_name = ref_name + @ref_type = ref_type + @action_name = action_name + end + + def project + Project.find(@project_id) + end + + def author + User.find(@author_id) + end + + def commits + Commit.decorate(@compare.commits, @project) if @compare + end + + def diffs + @compare.diffs if @compare + end + + def action_name + case @action + when :create + 'pushed new' + when :delete + 'deleted' + else + 'pushed to' + end + end + + def subject + subject_text = '[Git]' + subject_text << "[#{@project.path_with_namespace}]" + subject_text << "[#{@ref_name}]" if @action == :push + subject_text << ' ' + + if @action == :push + if @commits.length > 1 + subject_text << "Deleted " if @reverse_compare + subject_text << "#{@commits.length} commits: #{@commits.first.title}" + else + subject_text << "Deleted 1 commit: " if @reverse_compare + subject_text << @commits.first.title + end + end + + subject_action = @action_name.dup + subject_action[0] = subject_action[0].capitalize + subject_text << "#{subject_action} #{@ref_type} #{@ref_name}" + end + + def ref_name + Gitlab::Git.ref_name(@ref) + end + + def ref_type + Gitlab::Git.tag_ref?(@ref) ? 'tag' : 'branch' + end + + def target_url + if action == :push + if @commits.length > 1 + namespace_project_compare_url(@project.namespace, + @project, + from: Commit.new(@compare.base, @project), + to: Commit.new(@compare.head, @project)) + else + namespace_project_commit_url(@project.namespace, + @project, @commits.first) + end + end + + if action != :delete && action != :push + namespace_project_tree_url(@project.namespace, + @project, @ref_name) + end + end + + def reply_to + if @send_from_committer_email && can_send_from_user_email?(@author) + @author.email + else + Gitlab.config.gitlab.email_reply_to + end + end + end + end +end -- cgit v1.2.1 From e2f937ce22e6b0eb458bbdb3fa93b06d80ecfd21 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 18 Nov 2015 10:13:34 +0100 Subject: Refactor RepositoryPush, move to Message namespace --- lib/gitlab/email/message/repository_push.rb | 120 ++++++++++++++++++++++++++++ lib/gitlab/email/repository_push.rb | 116 --------------------------- 2 files changed, 120 insertions(+), 116 deletions(-) create mode 100644 lib/gitlab/email/message/repository_push.rb delete mode 100644 lib/gitlab/email/repository_push.rb (limited to 'lib') diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb new file mode 100644 index 00000000000..bb92df9e1bb --- /dev/null +++ b/lib/gitlab/email/message/repository_push.rb @@ -0,0 +1,120 @@ +module Gitlab + module Email + module Message + class RepositoryPush + attr_reader :compare, :reverse_compare, :send_from_committer_email, + :disable_diffs, :action, :ref, :author_id + attr_accessor :recipient + + def initialize(notify, project_id, recipient, opts = {}) + raise ArgumentError, 'Missing arguments: author_id, ref, action' unless + opts[:author_id] && opts[:ref] && opts[:action] + + @notify = notify + @project_id = project_id + @recipient = recipient + + @author_id = opts[:author_id] + @ref = opts[:ref] + @action = opts[:action] + + @compare = opts[:compare] || nil + @reverse_compare = opts[:reverse_compare] || false + @send_from_committer_email = opts[:send_from_committer_email] || false + @disable_diffs = opts[:disable_diffs] || false + + @author = author + @project = project + @commits = commits + @diffs = diffs + @ref_name = ref_name + @ref_type = ref_type + @action_name = action_name + end + + def project + Project.find(@project_id) + end + + def author + User.find(@author_id) + end + + def commits + Commit.decorate(@compare.commits, @project) if @compare + end + + def diffs + @compare.diffs if @compare + end + + def action_name + case @action + when :create + 'pushed new' + when :delete + 'deleted' + else + 'pushed to' + end + end + + def subject + subject_text = '[Git]' + subject_text << "[#{@project.path_with_namespace}]" + subject_text << "[#{@ref_name}]" if @action == :push + subject_text << ' ' + + if @action == :push + if @commits.length > 1 + subject_text << "Deleted " if @reverse_compare + subject_text << "#{@commits.length} commits: #{@commits.first.title}" + else + subject_text << "Deleted 1 commit: " if @reverse_compare + subject_text << @commits.first.title + end + else + subject_action = @action_name.dup + subject_action[0] = subject_action[0].capitalize + subject_text << "#{subject_action} #{@ref_type} #{@ref_name}" + end + end + + def ref_name + Gitlab::Git.ref_name(@ref) + end + + def ref_type + Gitlab::Git.tag_ref?(@ref) ? 'tag' : 'branch' + end + + def target_url + if @action == :push + if @commits.length > 1 + @notify.namespace_project_compare_url(@project.namespace, + @project, + from: Commit.new(@compare.base, @project), + to: Commit.new(@compare.head, @project)) + else + @notify.namespace_project_commit_url(@project.namespace, + @project, @commits.first) + end + else + unless @action == :delete + @notify.namespace_project_tree_url(@project.namespace, + @project, @ref_name) + end + end + end + + def reply_to + if @send_from_committer_email && @notify.can_send_from_user_email?(@author) + @author.email + else + Gitlab.config.gitlab.email_reply_to + end + end + end + end + end +end diff --git a/lib/gitlab/email/repository_push.rb b/lib/gitlab/email/repository_push.rb deleted file mode 100644 index f484f3cb76d..00000000000 --- a/lib/gitlab/email/repository_push.rb +++ /dev/null @@ -1,116 +0,0 @@ -module Gitlab - module Email - class RepositoryPush - attr_reader :compare, :reverse_compare, :send_from_cmmitter_email, :disable_diffs, - :action, :ref, :author_id - - def initialize(project_id, recipient, opts = {}) - raise ArgumentError, 'Missing arguments: author_id, ref, action' unless - opts[:author_id] && opts[:ref] && opts[:action] - - @project_id = project_id - @recipient = recipient - - @author_id = opts[:author_id] - @ref = opts[:ref] - @action = opts[:action] - - @compare = opts[:compare] || nil - @reverse_compare = opts[:reverse_compare] || false - @send_from_committer_email = opts[:send_from_committer_email] || false - @disable_diffs = opts[:disable_diffs] || false - - @author = author - @project = project - @commits = commits - @diffs = diffs - @ref_name = ref_name - @ref_type = ref_type - @action_name = action_name - end - - def project - Project.find(@project_id) - end - - def author - User.find(@author_id) - end - - def commits - Commit.decorate(@compare.commits, @project) if @compare - end - - def diffs - @compare.diffs if @compare - end - - def action_name - case @action - when :create - 'pushed new' - when :delete - 'deleted' - else - 'pushed to' - end - end - - def subject - subject_text = '[Git]' - subject_text << "[#{@project.path_with_namespace}]" - subject_text << "[#{@ref_name}]" if @action == :push - subject_text << ' ' - - if @action == :push - if @commits.length > 1 - subject_text << "Deleted " if @reverse_compare - subject_text << "#{@commits.length} commits: #{@commits.first.title}" - else - subject_text << "Deleted 1 commit: " if @reverse_compare - subject_text << @commits.first.title - end - end - - subject_action = @action_name.dup - subject_action[0] = subject_action[0].capitalize - subject_text << "#{subject_action} #{@ref_type} #{@ref_name}" - end - - def ref_name - Gitlab::Git.ref_name(@ref) - end - - def ref_type - Gitlab::Git.tag_ref?(@ref) ? 'tag' : 'branch' - end - - def target_url - if action == :push - if @commits.length > 1 - namespace_project_compare_url(@project.namespace, - @project, - from: Commit.new(@compare.base, @project), - to: Commit.new(@compare.head, @project)) - else - namespace_project_commit_url(@project.namespace, - @project, @commits.first) - end - end - - if action != :delete && action != :push - namespace_project_tree_url(@project.namespace, - @project, @ref_name) - end - end - - def reply_to - if @send_from_committer_email && can_send_from_user_email?(@author) - @author.email - else - Gitlab.config.gitlab.email_reply_to - end - end - end - end -end -- cgit v1.2.1 From 4beba7494b096f2540b19017bb7c1c8e91679135 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 20 Nov 2015 15:29:47 +0100 Subject: Improve Messagee::RepositoryPush --- lib/gitlab/email/message/repository_push.rb | 126 ++++++++++++++-------------- 1 file changed, 65 insertions(+), 61 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb index bb92df9e1bb..61962abf822 100644 --- a/lib/gitlab/email/message/repository_push.rb +++ b/lib/gitlab/email/message/repository_push.rb @@ -2,118 +2,122 @@ module Gitlab module Email module Message class RepositoryPush - attr_reader :compare, :reverse_compare, :send_from_committer_email, - :disable_diffs, :action, :ref, :author_id attr_accessor :recipient + attr_reader :author_id, :ref, :action def initialize(notify, project_id, recipient, opts = {}) - raise ArgumentError, 'Missing arguments: author_id, ref, action' unless + raise ArgumentError, 'Missing options: author_id, ref, action' unless opts[:author_id] && opts[:ref] && opts[:action] @notify = notify @project_id = project_id @recipient = recipient + @opts = opts - @author_id = opts[:author_id] - @ref = opts[:ref] - @action = opts[:action] - - @compare = opts[:compare] || nil - @reverse_compare = opts[:reverse_compare] || false - @send_from_committer_email = opts[:send_from_committer_email] || false - @disable_diffs = opts[:disable_diffs] || false - - @author = author - @project = project - @commits = commits - @diffs = diffs - @ref_name = ref_name - @ref_type = ref_type - @action_name = action_name + @author_id = opts.delete(:author_id) + @ref = opts.delete(:ref) + @action = opts.delete(:action) end def project - Project.find(@project_id) + @project ||= Project.find(@project_id) end def author - User.find(@author_id) + @author ||= User.find(@author_id) end def commits - Commit.decorate(@compare.commits, @project) if @compare + @commits ||= (Commit.decorate(compare.commits, project) if compare) end def diffs - @compare.diffs if @compare + @diffs ||= (compare.diffs if compare) end - def action_name - case @action - when :create - 'pushed new' - when :delete - 'deleted' - else - 'pushed to' - end + def compare + @opts[:compare] end - def subject - subject_text = '[Git]' - subject_text << "[#{@project.path_with_namespace}]" - subject_text << "[#{@ref_name}]" if @action == :push - subject_text << ' ' + def reverse_compare? + @opts[:reverse_compare] || false + end - if @action == :push - if @commits.length > 1 - subject_text << "Deleted " if @reverse_compare - subject_text << "#{@commits.length} commits: #{@commits.first.title}" + def disable_diffs? + @opts[:disable_diffs] || false + end + + def send_from_committer_email? + @opts[:send_from_committer_email] || false + end + + def action_name + @action_name ||= + case @action + when :create + 'pushed new' + when :delete + 'deleted' else - subject_text << "Deleted 1 commit: " if @reverse_compare - subject_text << @commits.first.title + 'pushed to' end - else - subject_action = @action_name.dup - subject_action[0] = subject_action[0].capitalize - subject_text << "#{subject_action} #{@ref_type} #{@ref_name}" - end end def ref_name - Gitlab::Git.ref_name(@ref) + @ref_name ||= Gitlab::Git.ref_name(@ref) end def ref_type - Gitlab::Git.tag_ref?(@ref) ? 'tag' : 'branch' + @ref_type ||= Gitlab::Git.tag_ref?(@ref) ? 'tag' : 'branch' end def target_url if @action == :push - if @commits.length > 1 - @notify.namespace_project_compare_url(@project.namespace, - @project, - from: Commit.new(@compare.base, @project), - to: Commit.new(@compare.head, @project)) + if commits.length > 1 && compare + @notify.namespace_project_compare_url(project.namespace, + project, + from: Commit.new(compare.base, project), + to: Commit.new(compare.head, project)) else - @notify.namespace_project_commit_url(@project.namespace, - @project, @commits.first) + @notify.namespace_project_commit_url(project.namespace, + project, commits.first) end else unless @action == :delete - @notify.namespace_project_tree_url(@project.namespace, - @project, @ref_name) + @notify.namespace_project_tree_url(project.namespace, + project, ref_name) end end end def reply_to - if @send_from_committer_email && @notify.can_send_from_user_email?(@author) - @author.email + if send_from_committer_email? && @notify.can_send_from_user_email?(author) + author.email else Gitlab.config.gitlab.email_reply_to end end + + def subject + subject_text = '[Git]' + subject_text << "[#{project.path_with_namespace}]" + subject_text << "[#{ref_name}]" if @action == :push + subject_text << ' ' + + if @action == :push + if commits.length > 1 + subject_text << "Deleted " if reverse_compare? + subject_text << "#{commits.length} commits: #{commits.first.title}" + else + subject_text << "Deleted 1 commit: " if reverse_compare? + subject_text << commits.first.title + end + else + subject_action = action_name.dup + subject_action[0] = subject_action[0].capitalize + subject_text << "#{subject_action} #{ref_type} #{ref_name}" + end + end end end end -- cgit v1.2.1 From 9f2752e5dcc31dc4e9d91ee18caf1d36f1b7684e Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Sat, 21 Nov 2015 20:54:19 +0100 Subject: Remove obsolete variables in `repository_push_email` --- lib/gitlab/email/message/repository_push.rb | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb index 61962abf822..b0af3feee9e 100644 --- a/lib/gitlab/email/message/repository_push.rb +++ b/lib/gitlab/email/message/repository_push.rb @@ -5,6 +5,9 @@ module Gitlab attr_accessor :recipient attr_reader :author_id, :ref, :action + delegate :namespace, :name_with_namespace, to: :project, prefix: :project + delegate :name, to: :author, prefix: :author + def initialize(notify, project_id, recipient, opts = {}) raise ArgumentError, 'Missing options: author_id, ref, action' unless opts[:author_id] && opts[:ref] && opts[:action] @@ -35,10 +38,18 @@ module Gitlab @diffs ||= (compare.diffs if compare) end + def diffs_count + diffs.count if diffs + end + def compare @opts[:compare] end + def compare_timeout + compare.timeout if compare + end + def reverse_compare? @opts[:reverse_compare] || false end @@ -74,17 +85,17 @@ module Gitlab def target_url if @action == :push if commits.length > 1 && compare - @notify.namespace_project_compare_url(project.namespace, + @notify.namespace_project_compare_url(project_namespace, project, from: Commit.new(compare.base, project), to: Commit.new(compare.head, project)) else - @notify.namespace_project_commit_url(project.namespace, + @notify.namespace_project_commit_url(project_namespace, project, commits.first) end else unless @action == :delete - @notify.namespace_project_tree_url(project.namespace, + @notify.namespace_project_tree_url(project_namespace, project, ref_name) end end -- cgit v1.2.1 From d835fbc79f6cd6f17fc7472af48074805622a573 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Sun, 22 Nov 2015 20:59:31 +0100 Subject: Fix url helpers in RepositoryPush --- lib/gitlab/email/message/repository_push.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb index b0af3feee9e..bc8aece733f 100644 --- a/lib/gitlab/email/message/repository_push.rb +++ b/lib/gitlab/email/message/repository_push.rb @@ -16,6 +16,7 @@ module Gitlab @project_id = project_id @recipient = recipient @opts = opts + @urls = Gitlab::Application.routes.url_helpers @author_id = opts.delete(:author_id) @ref = opts.delete(:ref) @@ -85,17 +86,17 @@ module Gitlab def target_url if @action == :push if commits.length > 1 && compare - @notify.namespace_project_compare_url(project_namespace, + @urls.namespace_project_compare_url(project_namespace, project, from: Commit.new(compare.base, project), to: Commit.new(compare.head, project)) else - @notify.namespace_project_commit_url(project_namespace, + @urls.namespace_project_commit_url(project_namespace, project, commits.first) end else unless @action == :delete - @notify.namespace_project_tree_url(project_namespace, + @urls.namespace_project_tree_url(project_namespace, project, ref_name) end end -- cgit v1.2.1 From 75c6b29f6b15e164717c27e6c3d7eecb84c923f8 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 3 Dec 2015 14:16:16 +0100 Subject: Add `RepositoryPush` specs --- lib/gitlab/email/message/repository_push.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb index bc8aece733f..3526eb2cad9 100644 --- a/lib/gitlab/email/message/repository_push.rb +++ b/lib/gitlab/email/message/repository_push.rb @@ -87,17 +87,17 @@ module Gitlab if @action == :push if commits.length > 1 && compare @urls.namespace_project_compare_url(project_namespace, - project, - from: Commit.new(compare.base, project), - to: Commit.new(compare.head, project)) + project, + from: Commit.new(compare.base, project), + to: Commit.new(compare.head, project)) else @urls.namespace_project_commit_url(project_namespace, - project, commits.first) + project, commits.first) end else unless @action == :delete @urls.namespace_project_tree_url(project_namespace, - project, ref_name) + project, ref_name) end end end -- cgit v1.2.1 From 591035968dc96acd27155ced4c0ae04649fcd113 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 4 Dec 2015 12:55:19 +0000 Subject: Duplicate options in `RepositoryPush` --- lib/gitlab/email/message/repository_push.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb index 3526eb2cad9..ca89b67e580 100644 --- a/lib/gitlab/email/message/repository_push.rb +++ b/lib/gitlab/email/message/repository_push.rb @@ -15,12 +15,12 @@ module Gitlab @notify = notify @project_id = project_id @recipient = recipient - @opts = opts + @opts = opts.dup @urls = Gitlab::Application.routes.url_helpers - @author_id = opts.delete(:author_id) - @ref = opts.delete(:ref) - @action = opts.delete(:action) + @author_id = @opts.delete(:author_id) + @ref = @opts.delete(:ref) + @action = @opts.delete(:action) end def project -- cgit v1.2.1 From 66f658a9b543b1493f625b2f44f3f845d64b749d Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 4 Dec 2015 14:11:17 +0100 Subject: Check if commits are available in `RepositoryPush` --- lib/gitlab/email/message/repository_push.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb index ca89b67e580..c53148d2ed8 100644 --- a/lib/gitlab/email/message/repository_push.rb +++ b/lib/gitlab/email/message/repository_push.rb @@ -84,8 +84,8 @@ module Gitlab end def target_url - if @action == :push - if commits.length > 1 && compare + if @action == :push && commits + if commits.length > 1 @urls.namespace_project_compare_url(project_namespace, project, from: Commit.new(compare.base, project), @@ -116,7 +116,7 @@ module Gitlab subject_text << "[#{ref_name}]" if @action == :push subject_text << ' ' - if @action == :push + if @action == :push && commits if commits.length > 1 subject_text << "Deleted " if reverse_compare? subject_text << "#{commits.length} commits: #{commits.first.title}" -- cgit v1.2.1 From 652de0b820587983e0af76186db4570b536d7ce3 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 7 Dec 2015 10:43:07 +0100 Subject: Refactor CI YAML processor's validators --- lib/ci/gitlab_ci_yaml_processor.rb | 66 +++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 26 deletions(-) (limited to 'lib') diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 3beafcad117..9c11fc3c81d 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -132,26 +132,36 @@ module Ci end def validate_job!(name, job) + validate_job_name!(name) + validate_job_keys!(name, job) + validate_job_types!(name, job) + + validate_job_stage!(name, job) if job[:stage] + validate_job_cache!(name, job) if job[:cache] + validate_job_artifacts!(name, job) if job[:artifacts] + end + + private + + def validate_job_name!(name) if name.blank? || !validate_string(name) raise ValidationError, "job name should be non-empty string" end + end + def validate_job_keys!(name, job) job.keys.each do |key| unless ALLOWED_JOB_KEYS.include? key raise ValidationError, "#{name} job: unknown parameter #{key}" end end + end + def validate_job_types!(name, job) if !validate_string(job[:script]) && !validate_array_of_strings(job[:script]) raise ValidationError, "#{name} job: script should be a string or an array of a strings" end - if job[:stage] - unless job[:stage].is_a?(String) && job[:stage].in?(stages) - raise ValidationError, "#{name} job: stage parameter should be #{stages.join(", ")}" - end - end - if job[:image] && !validate_string(job[:image]) raise ValidationError, "#{name} job: image should be a string" end @@ -172,36 +182,40 @@ module Ci raise ValidationError, "#{name} job: except parameter should be an array of strings" end - if job[:cache] - if job[:cache][:untracked] && !validate_boolean(job[:cache][:untracked]) - raise ValidationError, "#{name} job: cache:untracked parameter should be an boolean" - end - - if job[:cache][:paths] && !validate_array_of_strings(job[:cache][:paths]) - raise ValidationError, "#{name} job: cache:paths parameter should be an array of strings" - end + if job[:allow_failure] && !validate_boolean(job[:allow_failure]) + raise ValidationError, "#{name} job: allow_failure parameter should be an boolean" end - if job[:artifacts] - if job[:artifacts][:untracked] && !validate_boolean(job[:artifacts][:untracked]) - raise ValidationError, "#{name} job: artifacts:untracked parameter should be an boolean" - end + if job[:when] && !job[:when].in?(%w(on_success on_failure always)) + raise ValidationError, "#{name} job: when parameter should be on_success, on_failure or always" + end + end - if job[:artifacts][:paths] && !validate_array_of_strings(job[:artifacts][:paths]) - raise ValidationError, "#{name} job: artifacts:paths parameter should be an array of strings" - end + def validate_job_stage!(name, job) + unless job[:stage].is_a?(String) && job[:stage].in?(stages) + raise ValidationError, "#{name} job: stage parameter should be #{stages.join(", ")}" end + end - if job[:allow_failure] && !validate_boolean(job[:allow_failure]) - raise ValidationError, "#{name} job: allow_failure parameter should be an boolean" + def validate_job_cache!(name, job) + if job[:cache][:untracked] && !validate_boolean(job[:cache][:untracked]) + raise ValidationError, "#{name} job: cache:untracked parameter should be an boolean" end - if job[:when] && !job[:when].in?(%w(on_success on_failure always)) - raise ValidationError, "#{name} job: when parameter should be on_success, on_failure or always" + if job[:cache][:paths] && !validate_array_of_strings(job[:cache][:paths]) + raise ValidationError, "#{name} job: cache:paths parameter should be an array of strings" end end - private + def validate_job_artifacts!(name, job) + if job[:artifacts][:untracked] && !validate_boolean(job[:artifacts][:untracked]) + raise ValidationError, "#{name} job: artifacts:untracked parameter should be an boolean" + end + + if job[:artifacts][:paths] && !validate_array_of_strings(job[:artifacts][:paths]) + raise ValidationError, "#{name} job: artifacts:paths parameter should be an array of strings" + end + end def validate_array_of_strings(values) values.is_a?(Array) && values.all? { |value| validate_string(value) } -- cgit v1.2.1 From 13f44822d97e643b55047cf619f7bb1f354f165b Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 8 Dec 2015 12:29:48 +0100 Subject: Move CombinedPipeline methods around --- lib/gitlab/markdown/combined_pipeline.rb | 12 +++++++----- lib/gitlab/markdown/pipeline/full_pipeline.rb | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/combined_pipeline.rb b/lib/gitlab/markdown/combined_pipeline.rb index a3d717550f5..6b08a5e9f72 100644 --- a/lib/gitlab/markdown/combined_pipeline.rb +++ b/lib/gitlab/markdown/combined_pipeline.rb @@ -7,16 +7,18 @@ module Gitlab Class.new(Pipeline) do const_set :PIPELINES, pipelines + def self.pipelines + self::PIPELINES + end + def self.filters pipelines.flat_map(&:filters) end def self.transform_context(context) - pipelines.reduce(context) { |context, pipeline| pipeline.transform_context(context) } - end - - def self.pipelines - self::PIPELINES + pipelines.reduce(context) do |context, pipeline| + pipeline.transform_context(context) + end end end end diff --git a/lib/gitlab/markdown/pipeline/full_pipeline.rb b/lib/gitlab/markdown/pipeline/full_pipeline.rb index 553e9367c1c..b3b7a3c27c0 100644 --- a/lib/gitlab/markdown/pipeline/full_pipeline.rb +++ b/lib/gitlab/markdown/pipeline/full_pipeline.rb @@ -3,7 +3,7 @@ require 'gitlab/markdown' module Gitlab module Markdown class FullPipeline < CombinedPipeline.new(PlainMarkdownPipeline, GfmPipeline) - + end end end -- cgit v1.2.1 From af6b5437421106caf34719e37d359808b88eb45c Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 8 Dec 2015 13:04:59 +0100 Subject: Make commit and MR ref filters aware of /builds path --- lib/gitlab/markdown/commit_reference_filter.rb | 11 +++++++++++ lib/gitlab/markdown/merge_request_reference_filter.rb | 8 +++++++- 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/commit_reference_filter.rb b/lib/gitlab/markdown/commit_reference_filter.rb index b4036578e60..e3066a89b04 100644 --- a/lib/gitlab/markdown/commit_reference_filter.rb +++ b/lib/gitlab/markdown/commit_reference_filter.rb @@ -47,6 +47,17 @@ module Gitlab def object_link_title(commit) commit.link_title end + + def object_link_text_extras(object, matches) + extras = super + + path = matches[:path] if matches.names.include?("path") + if path == '/builds' + extras.unshift "builds" + end + + extras + end end end end diff --git a/lib/gitlab/markdown/merge_request_reference_filter.rb b/lib/gitlab/markdown/merge_request_reference_filter.rb index de71fc76a9b..79d67870b14 100644 --- a/lib/gitlab/markdown/merge_request_reference_filter.rb +++ b/lib/gitlab/markdown/merge_request_reference_filter.rb @@ -24,8 +24,14 @@ module Gitlab def object_link_text_extras(object, matches) extras = super - if matches.names.include?("path") && matches[:path] && matches[:path] == '/diffs' + path = matches[:path] if matches.names.include?("path") + case path + when '/diffs' extras.unshift "diffs" + when '/builds' + extras.unshift "builds" + when '/commits' + extras.unshift "commits" end extras -- cgit v1.2.1 From 1a10945066d0da1801bb4cf89ce5f54996f1756f Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 8 Dec 2015 13:40:23 +0100 Subject: Fix RedactorFilter --- lib/gitlab/markdown/filter/redactor_filter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/filter/redactor_filter.rb b/lib/gitlab/markdown/filter/redactor_filter.rb index bea714a01e7..33ef7ce18b5 100644 --- a/lib/gitlab/markdown/filter/redactor_filter.rb +++ b/lib/gitlab/markdown/filter/redactor_filter.rb @@ -27,7 +27,7 @@ module Gitlab def user_can_reference?(node) if node.has_attribute?('data-reference-filter') reference_type = node.attr('data-reference-filter') - reference_filter = reference_type.constantize + reference_filter = Gitlab::Markdown.const_get(reference_type) reference_filter.user_can_reference?(current_user, node, context) else -- cgit v1.2.1 From 41a4785b855a082197b3c22004cb8af96e5453ee Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 8 Dec 2015 14:41:19 +0100 Subject: Fix signin with OmniAuth providers --- lib/omni_auth/request_forgery_protection.rb | 63 +++++------------------------ 1 file changed, 9 insertions(+), 54 deletions(-) (limited to 'lib') diff --git a/lib/omni_auth/request_forgery_protection.rb b/lib/omni_auth/request_forgery_protection.rb index 3557522d3c9..69155131d8d 100644 --- a/lib/omni_auth/request_forgery_protection.rb +++ b/lib/omni_auth/request_forgery_protection.rb @@ -1,66 +1,21 @@ # Protects OmniAuth request phase against CSRF. module OmniAuth - # Based on ActionController::RequestForgeryProtection. - class RequestForgeryProtection - def initialize(env) - @env = env - end - - def request - @request ||= ActionDispatch::Request.new(@env) - end - - def session - request.session - end - - def reset_session - request.reset_session - end - - def params - request.params - end - - def call - verify_authenticity_token - end + module RequestForgeryProtection + class Controller < ActionController::Base + protect_from_forgery with: :exception - def verify_authenticity_token - if !verified_request? - Rails.logger.warn "Can't verify CSRF token authenticity" if Rails.logger - handle_unverified_request + def index + head :ok end end - private - - def protect_against_forgery? - ApplicationController.allow_forgery_protection - end - - def request_forgery_protection_token - ApplicationController.request_forgery_protection_token - end - - def forgery_protection_strategy - ApplicationController.forgery_protection_strategy - end - - def verified_request? - !protect_against_forgery? || request.get? || request.head? || - form_authenticity_token == params[request_forgery_protection_token] || - form_authenticity_token == request.headers['X-CSRF-Token'] - end - - def handle_unverified_request - forgery_protection_strategy.new(self).handle_unverified_request + def self.app + @app ||= Controller.action(:index) end - # Sets the token value for the current session. - def form_authenticity_token - session[:_csrf_token] ||= SecureRandom.base64(32) + def self.call(env) + app.call(env) end end end -- cgit v1.2.1 From 23f383ef69889c9829ad36afa53b5abfbf4b5511 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 8 Dec 2015 16:06:06 +0100 Subject: Detect project and namespace changes in list:repos --- lib/tasks/gitlab/list_repos.rake | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/tasks/gitlab/list_repos.rake b/lib/tasks/gitlab/list_repos.rake index 1377e1ea910..c7596e7abcb 100644 --- a/lib/tasks/gitlab/list_repos.rake +++ b/lib/tasks/gitlab/list_repos.rake @@ -3,9 +3,10 @@ namespace :gitlab do scope = Project if ENV['SINCE'] date = Time.parse(ENV['SINCE']) - warn "Listing repositories with activity since #{date}" - project_ids = Project.where(['last_activity_at > ?', date]).pluck(:id) - scope = scope.where(id: project_ids) + warn "Listing repositories with activity or changes since #{date}" + project_ids = Project.where('last_activity_at > ? OR updated_at > ?', date, date).pluck(:id).sort + namespace_ids = Namespace.where(['updated_at > ?', date]).pluck(:id).sort + scope = scope.where('id IN (?) OR namespace_id in (?)', project_ids, namespace_ids) end scope.find_each do |project| base = File.join(Gitlab.config.gitlab_shell.repos_path, project.path_with_namespace) -- cgit v1.2.1 From 1d410ac96a96462d9f48ec4e43a4e819bbffdeee Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 7 Dec 2015 23:01:53 -0800 Subject: Update project repository size and commit count during import:repos task Closes #3848 --- lib/tasks/gitlab/import.rake | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake index c1ee271ae2b..1c04f47f08f 100644 --- a/lib/tasks/gitlab/import.rake +++ b/lib/tasks/gitlab/import.rake @@ -64,6 +64,8 @@ namespace :gitlab do if project.persisted? puts " * Created #{project.name} (#{repo_path})".green + project.update_repository_size + project.update_commit_count else puts " * Failed trying to create #{project.name} (#{repo_path})".red puts " Errors: #{project.errors.messages}".red -- cgit v1.2.1 From bf5683f8892c4aefc4c996812ece6291b701dada Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Tue, 8 Dec 2015 09:47:42 -0600 Subject: Block LDAP user when they are no longer found in the LDAP server --- lib/gitlab/ldap/access.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/ldap/access.rb b/lib/gitlab/ldap/access.rb index 16ff03c38d4..c438a3d167b 100644 --- a/lib/gitlab/ldap/access.rb +++ b/lib/gitlab/ldap/access.rb @@ -37,13 +37,15 @@ module Gitlab # Block user in GitLab if he/she was blocked in AD if Gitlab::LDAP::Person.disabled_via_active_directory?(user.ldap_identity.extern_uid, adapter) - user.block unless user.blocked? + user.block false else user.activate if user.blocked? && !ldap_config.block_auto_created_users true end else + # Block the user if they no longer exist in LDAP/AD + user.block false end rescue -- cgit v1.2.1 From 23b6a98de00b966728f6b5ed3747b0d2e078165f Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 8 Dec 2015 22:28:28 +0100 Subject: Move Builds tab to the end --- lib/gitlab/markdown/merge_request_reference_filter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/markdown/merge_request_reference_filter.rb b/lib/gitlab/markdown/merge_request_reference_filter.rb index 79d67870b14..2eb77c46da7 100644 --- a/lib/gitlab/markdown/merge_request_reference_filter.rb +++ b/lib/gitlab/markdown/merge_request_reference_filter.rb @@ -28,10 +28,10 @@ module Gitlab case path when '/diffs' extras.unshift "diffs" - when '/builds' - extras.unshift "builds" when '/commits' extras.unshift "commits" + when '/builds' + extras.unshift "builds" end extras -- cgit v1.2.1 From 9ebdee09673d79b57c07c7332ee87791229b6f72 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 9 Dec 2015 10:50:38 +0100 Subject: Split up feature specs more --- lib/tasks/spinach.rake | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/tasks/spinach.rake b/lib/tasks/spinach.rake index d5a96fd38f4..3acfc6e2075 100644 --- a/lib/tasks/spinach.rake +++ b/lib/tasks/spinach.rake @@ -1,11 +1,31 @@ Rake::Task["spinach"].clear if Rake::Task.task_defined?('spinach') namespace :spinach do + namespace :project do + desc "GitLab | Spinach | Run project commits, issues and merge requests spinach features" + task :half do + cmds = [ + %W(rake gitlab:setup), + %W(spinach --tags @project_commits,@project_issues,@project_merge_requests), + ] + run_commands(cmds) + end + + desc "GitLab | Spinach | Run remaining project spinach features" + task :rest do + cmds = [ + %W(rake gitlab:setup), + %W(spinach --tags ~@admin,~@dashboard,~@profile,~@public,~@snippets,~@project_commits,~@project_issues,~@project_merge_requests), + ] + run_commands(cmds) + end + end + desc "GitLab | Spinach | Run project spinach features" task :project do cmds = [ %W(rake gitlab:setup), - %W(spinach --tags ~@admin,~@dashboard,~@profile,~@public,~@snippets,~@commits), + %W(spinach --tags ~@admin,~@dashboard,~@profile,~@public,~@snippets), ] run_commands(cmds) end @@ -14,7 +34,7 @@ namespace :spinach do task :other do cmds = [ %W(rake gitlab:setup), - %W(spinach --tags @admin,@dashboard,@profile,@public,@snippets,@commits), + %W(spinach --tags @admin,@dashboard,@profile,@public,@snippets), ] run_commands(cmds) end @@ -33,4 +53,4 @@ def run_commands(cmds) cmds.each do |cmd| system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd) or raise("#{cmd} failed!") end -end \ No newline at end of file +end -- cgit v1.2.1 From ae0b9017315b38dd42b4a1c9b6fb1daa78fee28a Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 9 Dec 2015 10:51:01 +0100 Subject: Split up specs more --- lib/tasks/spec.rake | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/tasks/spec.rake b/lib/tasks/spec.rake index 365ff2defd4..049e17e6c11 100644 --- a/lib/tasks/spec.rake +++ b/lib/tasks/spec.rake @@ -19,6 +19,15 @@ namespace :spec do run_commands(cmds) end + desc 'GitLab | Rspec | Run model specs' + task :models do + cmds = [ + %W(rake gitlab:setup), + %W(rspec spec --tag @models) + ] + run_commands(cmds) + end + desc 'GitLab | Rspec | Run benchmark specs' task :benchmark do cmds = [ @@ -32,7 +41,7 @@ namespace :spec do task :other do cmds = [ %W(rake gitlab:setup), - %W(rspec spec --tag ~@api --tag ~@feature --tag ~@benchmark) + %W(rspec spec --tag ~@api,~@feature,~@models,~@benchmark) ] run_commands(cmds) end -- cgit v1.2.1 From 7a5e77c0a0591ff5d121f93deced27b798ddbee3 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 9 Dec 2015 11:09:25 +0100 Subject: Fix rspec tag syntax --- lib/tasks/spec.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/tasks/spec.rake b/lib/tasks/spec.rake index 049e17e6c11..343e4b63524 100644 --- a/lib/tasks/spec.rake +++ b/lib/tasks/spec.rake @@ -41,7 +41,7 @@ namespace :spec do task :other do cmds = [ %W(rake gitlab:setup), - %W(rspec spec --tag ~@api,~@feature,~@models,~@benchmark) + %W(rspec spec --tag ~@api --tag ~@feature --tag ~@models --tag ~@benchmark) ] run_commands(cmds) end -- cgit v1.2.1 From 6c6fb1d8bb2c6aa44553ebf35496d64ff6b202d2 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 9 Dec 2015 11:56:23 +0100 Subject: Split up spec:other even more --- lib/tasks/spec.rake | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/tasks/spec.rake b/lib/tasks/spec.rake index 343e4b63524..0985ef3a669 100644 --- a/lib/tasks/spec.rake +++ b/lib/tasks/spec.rake @@ -28,6 +28,24 @@ namespace :spec do run_commands(cmds) end + desc 'GitLab | Rspec | Run service specs' + task :services do + cmds = [ + %W(rake gitlab:setup), + %W(rspec spec --tag @services) + ] + run_commands(cmds) + end + + desc 'GitLab | Rspec | Run lib specs' + task :lib do + cmds = [ + %W(rake gitlab:setup), + %W(rspec spec --tag @lib) + ] + run_commands(cmds) + end + desc 'GitLab | Rspec | Run benchmark specs' task :benchmark do cmds = [ @@ -41,7 +59,7 @@ namespace :spec do task :other do cmds = [ %W(rake gitlab:setup), - %W(rspec spec --tag ~@api --tag ~@feature --tag ~@models --tag ~@benchmark) + %W(rspec spec --tag ~@api --tag ~@feature --tag ~@models --tag ~@lib --tag ~@services --tag ~@benchmark) ] run_commands(cmds) end -- cgit v1.2.1 From c5dacce4d7e47a0504975fbb3bfaf478b95f1065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Wed, 9 Dec 2015 19:50:00 +0000 Subject: Use YAML.safe_load --- lib/ci/gitlab_ci_yaml_processor.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 3beafcad117..7f54f5f0722 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -10,7 +10,7 @@ module Ci attr_reader :before_script, :image, :services, :variables, :path, :cache def initialize(config, path = nil) - @config = YAML.load(config) + @config = YAML.safe_load(config) @path = path unless @config.is_a? Hash @@ -250,4 +250,4 @@ module Ci end end end -end +end \ No newline at end of file -- cgit v1.2.1 From b4b9df277bb1490ba04a976fb2a59f2a0f603173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Wed, 9 Dec 2015 20:58:53 +0000 Subject: Allow [Symbol] when loading YAML --- lib/ci/gitlab_ci_yaml_processor.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 7f54f5f0722..e7fb1b79b7c 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -10,7 +10,7 @@ module Ci attr_reader :before_script, :image, :services, :variables, :path, :cache def initialize(config, path = nil) - @config = YAML.safe_load(config) + @config = YAML.safe_load(config, [Symbol]) @path = path unless @config.is_a? Hash @@ -250,4 +250,4 @@ module Ci end end end -end \ No newline at end of file +end -- cgit v1.2.1 From 2988e1fbf50b3c9e803a9358933e3e969e64dcc3 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 7 Dec 2015 13:23:23 +0100 Subject: Migrate CI::Services and CI::WebHooks to Services and WebHooks --- lib/api/entities.rb | 5 ++-- lib/api/project_hooks.rb | 2 ++ lib/ci/api/projects.rb | 38 ------------------------ lib/gitlab/build_data_builder.rb | 64 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 40 deletions(-) create mode 100644 lib/gitlab/build_data_builder.rb (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 81bf7a8222b..03e3056a87e 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -45,7 +45,8 @@ module API class ProjectHook < Hook expose :project_id, :push_events - expose :issues_events, :merge_requests_events, :tag_push_events, :note_events, :enable_ssl_verification + expose :issues_events, :merge_requests_events, :tag_push_events, :note_events, :build_events + expose :enable_ssl_verification end class ForkedFromProject < Grape::Entity @@ -252,7 +253,7 @@ module API class ProjectService < Grape::Entity expose :id, :title, :created_at, :updated_at, :active - expose :push_events, :issues_events, :merge_requests_events, :tag_push_events, :note_events + expose :push_events, :issues_events, :merge_requests_events, :tag_push_events, :note_events, :build_events # Expose serialized properties expose :properties do |service, options| field_names = service.fields. diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb index 882d1a083ad..cf9938d25a7 100644 --- a/lib/api/project_hooks.rb +++ b/lib/api/project_hooks.rb @@ -45,6 +45,7 @@ module API :merge_requests_events, :tag_push_events, :note_events, + :build_events, :enable_ssl_verification ] @hook = user_project.hooks.new(attrs) @@ -77,6 +78,7 @@ module API :merge_requests_events, :tag_push_events, :note_events, + :build_events, :enable_ssl_verification ] diff --git a/lib/ci/api/projects.rb b/lib/ci/api/projects.rb index d719ad9e8d5..23c79f3879d 100644 --- a/lib/ci/api/projects.rb +++ b/lib/ci/api/projects.rb @@ -5,30 +5,6 @@ module Ci before { authenticate! } resource :projects do - # Register new webhook for project - # - # Parameters - # project_id (required) - The ID of a project - # web_hook (required) - WebHook URL - # Example Request - # POST /projects/:project_id/webhooks - post ":project_id/webhooks" do - required_attributes! [:web_hook] - - project = Ci::Project.find(params[:project_id]) - - unauthorized! unless can?(current_user, :admin_project, project.gl_project) - - web_hook = project.web_hooks.new({ url: params[:web_hook] }) - - if web_hook.save - present web_hook, with: Entities::WebHook - else - errors = web_hook.errors.full_messages.join(", ") - render_api_error!(errors, 400) - end - end - # Retrieve all Gitlab CI projects that the user has access to # # Example Request: @@ -121,20 +97,6 @@ module Ci end end - # Remove a Gitlab CI project - # - # Parameters: - # id (required) - The ID of a project - # Example Request: - # DELETE /projects/:id - delete ":id" do - project = Ci::Project.find(params[:id]) - - unauthorized! unless can?(current_user, :admin_project, project.gl_project) - - project.destroy - end - # Link a Gitlab CI project to a runner # # Parameters: diff --git a/lib/gitlab/build_data_builder.rb b/lib/gitlab/build_data_builder.rb new file mode 100644 index 00000000000..fa2cd551cee --- /dev/null +++ b/lib/gitlab/build_data_builder.rb @@ -0,0 +1,64 @@ +module Gitlab + class BuildDataBuilder + class << self + def build(build) + project = build.gl_project + commit = build.commit + user = build.user + + data = { + object_kind: 'build', + + ref: build.ref, + tag: build.tag, + before_sha: build.before_sha, + sha: build.sha, + + # TODO: should this be not prefixed with build_? + # Leaving this way to have backward compatibility + build_id: build.id, + build_name: build.name, + build_stage: build.stage, + build_status: build.status, + build_started_at: build.started_at, + build_finished_at: build.finished_at, + build_duration: build.duration, + + # TODO: do we still need it? + project_id: project.id, + project_name: project.name_with_namespace, + + user: { + id: user.try(:id), + name: user.try(:name), + email: user.try(:email), + }, + + commit: { + id: commit.id, + sha: commit.sha, + message: commit.git_commit_message, + author_name: commit.git_author_name, + author_email: commit.git_author_email, + status: commit.status, + duration: commit.duration, + started_at: commit.started_at, + finished_at: commit.finished_at, + }, + + repository: { + name: project.name, + url: project.url_to_repo, + description: project.description, + homepage: project.web_url, + git_http_url: project.http_url_to_repo, + git_ssh_url: project.ssh_url_to_repo, + visibility_level: project.visibility_level + }, + } + + data + end + end + end +end -- cgit v1.2.1 From d5c91bb9a601a1a344d94763654f0b0996857497 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 9 Dec 2015 16:31:42 +0100 Subject: Migrate CI WebHooks and Emails to new tables --- lib/gitlab/database.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'lib') diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb index 71f37f1fef8..de77a6fbff1 100644 --- a/lib/gitlab/database.rb +++ b/lib/gitlab/database.rb @@ -7,5 +7,23 @@ module Gitlab def self.postgresql? ActiveRecord::Base.connection.adapter_name.downcase == 'postgresql' end + + def true_value + case ActiveRecord::Base.connection.adapter_name.downcase + when 'postgresql' + "'t'" + else + 1 + end + end + + def false_value + case ActiveRecord::Base.connection.adapter_name.downcase + when 'postgresql' + "'f'" + else + 0 + end + end end end -- cgit v1.2.1 From d8b3c3274c63d5fa62c441bac6e78a16e94422c3 Mon Sep 17 00:00:00 2001 From: Corey Hinshaw Date: Thu, 14 May 2015 11:46:48 -0400 Subject: AuthHash should not parameterize email user --- lib/gitlab/o_auth/auth_hash.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/o_auth/auth_hash.rb b/lib/gitlab/o_auth/auth_hash.rb index d94b104bbf8..ba31599432b 100644 --- a/lib/gitlab/o_auth/auth_hash.rb +++ b/lib/gitlab/o_auth/auth_hash.rb @@ -62,7 +62,7 @@ module Gitlab # Get the first part of the email address (before @) # In addtion in removes illegal characters def generate_username(email) - email.match(/^[^@]*/)[0].parameterize + email.match(/^[^@]*/)[0].mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/,'').to_s end def generate_temporarily_email(username) -- cgit v1.2.1 From e2e43a114b5af63aad6d9badcb727c8829abb167 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 10 Dec 2015 13:50:00 +0100 Subject: Use new runners registration token to register CI runners --- lib/ci/api/helpers.rb | 6 +++++- lib/ci/api/runners.rb | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb index 02502333756..12d7396189d 100644 --- a/lib/ci/api/helpers.rb +++ b/lib/ci/api/helpers.rb @@ -6,7 +6,7 @@ module Ci UPDATE_RUNNER_EVERY = 60 def authenticate_runners! - forbidden! unless params[:token] == GitlabCi::REGISTRATION_TOKEN + forbidden! unless runner_registration_token_valid? end def authenticate_runner! @@ -22,6 +22,10 @@ module Ci forbidden! unless token && build.valid_token?(token) end + def runner_registration_token_valid? + params[:token] == current_application_settings.runners_registration_token + end + def update_runner_last_contact # Use a random threshold to prevent beating DB updates contacted_at_max_age = UPDATE_RUNNER_EVERY + Random.rand(UPDATE_RUNNER_EVERY) diff --git a/lib/ci/api/runners.rb b/lib/ci/api/runners.rb index 1466fe4356e..3edf067f46d 100644 --- a/lib/ci/api/runners.rb +++ b/lib/ci/api/runners.rb @@ -40,7 +40,7 @@ module Ci required_attributes! [:token] runner = - if params[:token] == GitlabCi::REGISTRATION_TOKEN + if runner_registration_token_valid? # Create shared runner. Requires admin access Ci::Runner.create( description: params[:description], -- cgit v1.2.1 From 72b7d1f59d4fb26fb9119c5a059528f0fc951904 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Fri, 11 Dec 2015 13:10:00 +0200 Subject: emoji aliases problem --- lib/award_emoji.rb | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'lib') diff --git a/lib/award_emoji.rb b/lib/award_emoji.rb index d58a196c4ef..4d99164bc33 100644 --- a/lib/award_emoji.rb +++ b/lib/award_emoji.rb @@ -6,7 +6,42 @@ class AwardEmoji "ambulance", "anguished", "two_hearts", "wink" ] + ALIASES = { + pout: "rage", + satisfied: "laughing", + hankey: "shit", + poop: "shit", + collision: "boom", + thumbsup: "+1", + thumbsdown: "-1", + punch: "facepunch", + raised_hand: "hand", + running: "runner", + ng_woman: "no_good", + shoe: "mans_shoe", + tshirt: "shirt", + honeybee: "bee", + flipper: "dolphin", + paw_prints: "feet", + waxing_gibbous_moon: "moon", + telephone: "phone", + knife: "hocho", + envelope: "email", + pencil: "memo", + open_book: "book", + sailboat: "boat", + red_car: "car", + lantern: "izakaya_lantern", + uk: "gb", + heavy_exclamation_mark: "exclamation", + squirrel: "shipit" + }.with_indifferent_access + def self.path_to_emoji_image(name) "emoji/#{Emoji.emoji_filename(name)}.png" end + + def self.normilize_emoji_name(name) + ALIASES[name] || name + end end -- cgit v1.2.1 From cbeb06eb420f294b3a406f869f11de554048e93d Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 11 Dec 2015 13:00:24 +0000 Subject: Mix url helpers in into `RepositoryPush` --- lib/gitlab/email/message/repository_push.rb | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb index c53148d2ed8..a2eb7a70bd2 100644 --- a/lib/gitlab/email/message/repository_push.rb +++ b/lib/gitlab/email/message/repository_push.rb @@ -5,6 +5,8 @@ module Gitlab attr_accessor :recipient attr_reader :author_id, :ref, :action + include Gitlab::Application.routes.url_helpers + delegate :namespace, :name_with_namespace, to: :project, prefix: :project delegate :name, to: :author, prefix: :author @@ -16,7 +18,6 @@ module Gitlab @project_id = project_id @recipient = recipient @opts = opts.dup - @urls = Gitlab::Application.routes.url_helpers @author_id = @opts.delete(:author_id) @ref = @opts.delete(:ref) @@ -86,18 +87,18 @@ module Gitlab def target_url if @action == :push && commits if commits.length > 1 - @urls.namespace_project_compare_url(project_namespace, - project, - from: Commit.new(compare.base, project), - to: Commit.new(compare.head, project)) + namespace_project_compare_url(project_namespace, + project, + from: Commit.new(compare.base, project), + to: Commit.new(compare.head, project)) else - @urls.namespace_project_commit_url(project_namespace, - project, commits.first) + namespace_project_commit_url(project_namespace, + project, commits.first) end else unless @action == :delete - @urls.namespace_project_tree_url(project_namespace, - project, ref_name) + namespace_project_tree_url(project_namespace, + project, ref_name) end end end -- cgit v1.2.1 From 6b0c0d5bcc7940c7d84b8af965b2c4f9ceeb4175 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 11 Dec 2015 14:43:44 +0100 Subject: Ensure that runners registration token is present --- lib/ci/api/helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb index 12d7396189d..abd1869efc0 100644 --- a/lib/ci/api/helpers.rb +++ b/lib/ci/api/helpers.rb @@ -23,7 +23,7 @@ module Ci end def runner_registration_token_valid? - params[:token] == current_application_settings.runners_registration_token + params[:token] == current_application_settings.ensure_runners_registration_token end def update_runner_last_contact -- cgit v1.2.1 From d597a0a21ab7a589eb8c959e3062632f472ee099 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 11 Dec 2015 16:42:40 +0100 Subject: Pass all requests from NGINX to gitlab-workhorse --- lib/support/nginx/gitlab | 146 +----------------------------------------- lib/support/nginx/gitlab-ssl | 147 +------------------------------------------ 2 files changed, 3 insertions(+), 290 deletions(-) (limited to 'lib') diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab index 2a79fbdcf93..fc5475c4eef 100644 --- a/lib/support/nginx/gitlab +++ b/lib/support/nginx/gitlab @@ -10,34 +10,12 @@ ## If you change this file in a Merge Request, please also create ## a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests ## -################################## -## CHUNKED TRANSFER ## -################################## -## -## It is a known issue that Git-over-HTTP requires chunked transfer encoding [0] -## which is not supported by Nginx < 1.3.9 [1]. As a result, pushing a large object -## with Git (i.e. a single large file) can lead to a 411 error. In theory you can get -## around this by tweaking this configuration file and either: -## - installing an old version of Nginx with the chunkin module [2] compiled in, or -## - using a newer version of Nginx. -## -## At the time of writing we do not know if either of these theoretical solutions works. -## As a workaround users can use Git over SSH to push large files. -## -## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99 -## [1] https://github.com/agentzh/chunkin-nginx-module#status -## [2] https://github.com/agentzh/chunkin-nginx-module -## ################################### ## configuration ## ################################### ## ## See installation.md#using-https for additional HTTPS configuration details. -upstream gitlab { - server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0; -} - upstream gitlab-workhorse { server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0; } @@ -54,10 +32,6 @@ server { server_tokens off; ## Don't show the nginx version number, a security best practice root /home/git/gitlab/public; - ## Increase this if you want to upload large attachments - ## Or if you want to accept large git objects over http - client_max_body_size 20m; - ## See app/controllers/application_controller.rb for headers set ## Individual nginx logs for this GitLab vhost @@ -65,103 +39,8 @@ server { error_log /var/log/nginx/gitlab_error.log; location / { - ## Serve static files from defined root folder. - ## @gitlab is a named location for the upstream fallback, see below. - try_files $uri /index.html $uri.html @gitlab; - } - - ## We route uploads through GitLab to prevent XSS and enforce access control. - location /uploads/ { - ## If you use HTTPS make sure you disable gzip compression - ## to be safe against BREACH attack. - # gzip off; - - ## https://github.com/gitlabhq/gitlabhq/issues/694 - ## Some requests take more than 30 seconds. - proxy_read_timeout 300; - proxy_connect_timeout 300; - proxy_redirect off; - - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Frame-Options SAMEORIGIN; - - proxy_pass http://gitlab; - } - - ## If a file, which is not found in the root folder is requested, - ## then the proxy passes the request to the upsteam (gitlab unicorn). - location @gitlab { - ## If you use HTTPS make sure you disable gzip compression - ## to be safe against BREACH attack. - # gzip off; - - ## https://github.com/gitlabhq/gitlabhq/issues/694 - ## Some requests take more than 30 seconds. - proxy_read_timeout 300; - proxy_connect_timeout 300; - proxy_redirect off; - - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Frame-Options SAMEORIGIN; - - proxy_pass http://gitlab; - } - - location ~ ^/[\w\.-]+/[\w\.-]+/gitlab-lfs/objects { - client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; - } - - location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ { - client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; - } - - location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive { - client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; - } - - location ~ ^/api/v3/projects/.*/repository/archive { - client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; - } - - # Build artifacts should be submitted to this location - location ~ ^/[\w\.-]+/[\w\.-]+/builds/download { client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; - } - - # Build artifacts should be submitted to this location - location ~ /ci/api/v1/builds/[0-9]+/artifacts { - client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; - } - - location @gitlab-workhorse { - client_max_body_size 0; - ## If you use HTTPS make sure you disable gzip compression - ## to be safe against BREACH attack. - # gzip off; + gzip off; ## https://github.com/gitlabhq/gitlabhq/issues/694 ## Some requests take more than 30 seconds. @@ -169,14 +48,7 @@ server { proxy_connect_timeout 300; proxy_redirect off; - # Do not buffer Git HTTP responses - proxy_buffering off; - - # The following settings only work with NGINX 1.7.11 or newer - # - # # Pass chunked request bodies to gitlab-workhorse as-is - # proxy_request_buffering off; - # proxy_http_version 1.1; + proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; @@ -185,18 +57,4 @@ server { proxy_pass http://gitlab-workhorse; } - - ## Enable gzip compression as per rails guide: - ## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression - ## WARNING: If you are using relative urls remove the block below - ## See config/application.rb under "Relative url support" for the list of - ## other files that need to be changed for relative url support - location ~ ^/(assets)/ { - root /home/git/gitlab/public; - gzip_static on; # to serve pre-gzipped version - expires max; - add_header Cache-Control public; - } - - error_page 502 /502.html; } diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl index 79fe1474821..1e5f85413ec 100644 --- a/lib/support/nginx/gitlab-ssl +++ b/lib/support/nginx/gitlab-ssl @@ -14,34 +14,12 @@ ## If you change this file in a Merge Request, please also create ## a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests ## -################################## -## CHUNKED TRANSFER ## -################################## -## -## It is a known issue that Git-over-HTTP requires chunked transfer encoding [0] -## which is not supported by Nginx < 1.3.9 [1]. As a result, pushing a large object -## with Git (i.e. a single large file) can lead to a 411 error. In theory you can get -## around this by tweaking this configuration file and either: -## - installing an old version of Nginx with the chunkin module [2] compiled in, or -## - using a newer version of Nginx. -## -## At the time of writing we do not know if either of these theoretical solutions works. -## As a workaround users can use Git over SSH to push large files. -## -## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99 -## [1] https://github.com/agentzh/chunkin-nginx-module#status -## [2] https://github.com/agentzh/chunkin-nginx-module -## ################################### ## configuration ## ################################### ## ## See installation.md#using-https for additional HTTPS configuration details. -upstream gitlab { - server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0; -} - upstream gitlab-workhorse { server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0; } @@ -61,7 +39,6 @@ server { error_log /var/log/nginx/gitlab_error.log; } - ## HTTPS host server { listen 0.0.0.0:443 ssl; @@ -70,10 +47,6 @@ server { server_tokens off; ## Don't show the nginx version number, a security best practice root /home/git/gitlab/public; - ## Increase this if you want to upload large attachments - ## Or if you want to accept large git objects over http - client_max_body_size 20m; - ## Strong SSL Security ## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/ ssl on; @@ -110,104 +83,7 @@ server { error_log /var/log/nginx/gitlab_error.log; location / { - ## Serve static files from defined root folder. - ## @gitlab is a named location for the upstream fallback, see below. - try_files $uri /index.html $uri.html @gitlab; - } - - ## We route uploads through GitLab to prevent XSS and enforce access control. - location /uploads/ { - ## If you use HTTPS make sure you disable gzip compression - ## to be safe against BREACH attack. - gzip off; - - ## https://github.com/gitlabhq/gitlabhq/issues/694 - ## Some requests take more than 30 seconds. - proxy_read_timeout 300; - proxy_connect_timeout 300; - proxy_redirect off; - - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Ssl on; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Frame-Options SAMEORIGIN; - - proxy_pass http://gitlab; - } - - ## If a file, which is not found in the root folder is requested, - ## then the proxy passes the request to the upsteam (gitlab unicorn). - location @gitlab { - ## If you use HTTPS make sure you disable gzip compression - ## to be safe against BREACH attack. - gzip off; - - ## https://github.com/gitlabhq/gitlabhq/issues/694 - ## Some requests take more than 30 seconds. - proxy_read_timeout 300; - proxy_connect_timeout 300; - proxy_redirect off; - - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Ssl on; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Frame-Options SAMEORIGIN; - - proxy_pass http://gitlab; - } - - location ~ ^/[\w\.-]+/[\w\.-]+/gitlab-lfs/objects { - client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; - } - - location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ { - client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; - } - - location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive { client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; - } - - location ~ ^/api/v3/projects/.*/repository/archive { - client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; - } - - # Build artifacts should be submitted to this location - location ~ ^/[\w\.-]+/[\w\.-]+/builds/download { - client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; - } - - # Build artifacts should be submitted to this location - location ~ /ci/api/v1/builds/[0-9]+/artifacts { - client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-workhorse block - error_page 418 = @gitlab-workhorse; - return 418; - } - - location @gitlab-workhorse { - client_max_body_size 0; - ## If you use HTTPS make sure you disable gzip compression - ## to be safe against BREACH attack. gzip off; ## https://github.com/gitlabhq/gitlabhq/issues/694 @@ -216,14 +92,7 @@ server { proxy_connect_timeout 300; proxy_redirect off; - # Do not buffer Git HTTP responses - proxy_buffering off; - - # The following settings only work with NGINX 1.7.11 or newer - # - # # Pass chunked request bodies to gitlab-workhorse as-is - # proxy_request_buffering off; - # proxy_http_version 1.1; + proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; @@ -232,18 +101,4 @@ server { proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://gitlab-workhorse; } - - ## Enable gzip compression as per rails guide: - ## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression - ## WARNING: If you are using relative urls remove the block below - ## See config/application.rb under "Relative url support" for the list of - ## other files that need to be changed for relative url support - location ~ ^/(assets)/ { - root /home/git/gitlab/public; - gzip_static on; # to serve pre-gzipped version - expires max; - add_header Cache-Control public; - } - - error_page 502 /502.html; } -- cgit v1.2.1 From e80e3f5372d6bcad1fbe04a85b3086bb66794828 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 4 Dec 2015 12:55:23 +0100 Subject: Migrate CI::Project to Project --- lib/api/commit_statuses.rb | 2 +- lib/api/entities.rb | 1 + lib/api/helpers.rb | 7 +- lib/api/projects.rb | 6 ++ lib/ci/api/api.rb | 2 - lib/ci/api/commits.rb | 66 ---------------- lib/ci/api/projects.rb | 157 -------------------------------------- lib/ci/api/runners.rb | 15 +--- lib/ci/api/triggers.rb | 2 +- lib/ci/charts.rb | 6 +- lib/ci/current_settings.rb | 22 ------ lib/ci/scheduler.rb | 16 ---- lib/gitlab/backend/grack_auth.rb | 4 +- lib/gitlab/build_data_builder.rb | 2 +- lib/tasks/ci/schedule_builds.rake | 6 -- 15 files changed, 19 insertions(+), 295 deletions(-) delete mode 100644 lib/ci/api/commits.rb delete mode 100644 lib/ci/api/projects.rb delete mode 100644 lib/ci/current_settings.rb delete mode 100644 lib/ci/scheduler.rb delete mode 100644 lib/tasks/ci/schedule_builds.rake (limited to 'lib') diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb index 2c0596c9dfb..1162271f5fc 100644 --- a/lib/api/commit_statuses.rb +++ b/lib/api/commit_statuses.rb @@ -53,7 +53,7 @@ module API name = params[:name] || params[:context] status = GenericCommitStatus.running_or_pending.find_by(commit: ci_commit, name: name, ref: params[:ref]) - status ||= GenericCommitStatus.new(commit: ci_commit, user: current_user) + status ||= GenericCommitStatus.new(project: @project, commit: ci_commit, user: current_user) status.update(attrs) case params[:state].to_s diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 03e3056a87e..381babe291b 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -64,6 +64,7 @@ module API expose :name, :name_with_namespace expose :path, :path_with_namespace expose :issues_enabled, :merge_requests_enabled, :wiki_enabled, :builds_enabled, :snippets_enabled, :created_at, :last_activity_at + expose :shared_runners_enabled expose :creator_id expose :namespace expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ | project, options | project.forked? } diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 92540ccf2b1..a4df810e755 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -266,12 +266,7 @@ module API projects = projects.search(params[:search]) end - if params[:ci_enabled_first].present? - projects.includes(:gitlab_ci_service). - reorder("services.active DESC, projects.#{project_order_by} #{project_sort}") - else - projects.reorder(project_order_by => project_sort) - end + projects.reorder(project_order_by => project_sort) end def project_order_by diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 6928fe0eb9d..bdf4b77596e 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -82,6 +82,7 @@ module API # builds_enabled (optional) # wiki_enabled (optional) # snippets_enabled (optional) + # shared_runners_enabled (optional) # namespace_id (optional) - defaults to user namespace # public (optional) - if true same as setting visibility_level = 20 # visibility_level (optional) - 0 by default @@ -98,6 +99,7 @@ module API :builds_enabled, :wiki_enabled, :snippets_enabled, + :shared_runners_enabled, :namespace_id, :public, :visibility_level, @@ -126,6 +128,7 @@ module API # builds_enabled (optional) # wiki_enabled (optional) # snippets_enabled (optional) + # shared_runners_enabled (optional) # public (optional) - if true same as setting visibility_level = 20 # visibility_level (optional) # import_url (optional) @@ -142,6 +145,7 @@ module API :builds_enabled, :wiki_enabled, :snippets_enabled, + :shared_runners_enabled, :public, :visibility_level, :import_url] @@ -183,6 +187,7 @@ module API # builds_enabled (optional) # wiki_enabled (optional) # snippets_enabled (optional) + # shared_runners_enabled (optional) # public (optional) - if true same as setting visibility_level = 20 # visibility_level (optional) - visibility level of a project # Example Request @@ -197,6 +202,7 @@ module API :builds_enabled, :wiki_enabled, :snippets_enabled, + :shared_runners_enabled, :public, :visibility_level] attrs = map_public_to_visibility_level(attrs) diff --git a/lib/ci/api/api.rb b/lib/ci/api/api.rb index 07e68216d7f..5c347e432b4 100644 --- a/lib/ci/api/api.rb +++ b/lib/ci/api/api.rb @@ -30,9 +30,7 @@ module Ci helpers Gitlab::CurrentSettings mount Builds - mount Commits mount Runners - mount Projects mount Triggers end end diff --git a/lib/ci/api/commits.rb b/lib/ci/api/commits.rb deleted file mode 100644 index a60769d8305..00000000000 --- a/lib/ci/api/commits.rb +++ /dev/null @@ -1,66 +0,0 @@ -module Ci - module API - class Commits < Grape::API - resource :commits do - # Get list of commits per project - # - # Parameters: - # project_id (required) - The ID of a project - # project_token (requires) - Project token - # page (optional) - # per_page (optional) - items per request (default is 20) - # - get do - required_attributes! [:project_id, :project_token] - project = Ci::Project.find(params[:project_id]) - authenticate_project_token!(project) - - commits = project.commits.page(params[:page]).per(params[:per_page] || 20) - present commits, with: Entities::CommitWithBuilds - end - - # Create a commit - # - # Parameters: - # project_id (required) - The ID of a project - # project_token (requires) - Project token - # data (required) - GitLab push data - # - # Sample GitLab push data: - # { - # "before": "95790bf891e76fee5e1747ab589903a6a1f80f22", - # "after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", - # "ref": "refs/heads/master", - # "commits": [ - # { - # "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", - # "message": "Update Catalan translation to e38cb41.", - # "timestamp": "2011-12-12T14:27:31+02:00", - # "url": "http://localhost/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", - # "author": { - # "name": "Jordi Mallach", - # "email": "jordi@softcatala.org", - # } - # }, .... more commits - # ] - # } - # - # Example Request: - # POST /commits - post do - required_attributes! [:project_id, :data, :project_token] - project = Ci::Project.find(params[:project_id]) - authenticate_project_token!(project) - commit = Ci::CreateCommitService.new.execute(project, current_user, params[:data]) - - if commit.persisted? - present commit, with: Entities::CommitWithBuilds - else - errors = commit.errors.full_messages.join(", ") - render_api_error!(errors, 400) - end - end - end - end - end -end diff --git a/lib/ci/api/projects.rb b/lib/ci/api/projects.rb deleted file mode 100644 index 23c79f3879d..00000000000 --- a/lib/ci/api/projects.rb +++ /dev/null @@ -1,157 +0,0 @@ -module Ci - module API - # Projects API - class Projects < Grape::API - before { authenticate! } - - resource :projects do - # Retrieve all Gitlab CI projects that the user has access to - # - # Example Request: - # GET /projects - get do - gitlab_projects = current_user.authorized_projects - gitlab_projects = filter_projects(gitlab_projects) - gitlab_projects = paginate gitlab_projects - - ids = gitlab_projects.map { |project| project.id } - - projects = Ci::Project.where("gitlab_id IN (?)", ids).load - present projects, with: Entities::Project - end - - # Retrieve all Gitlab CI projects that the user owns - # - # Example Request: - # GET /projects/owned - get "owned" do - gitlab_projects = current_user.owned_projects - gitlab_projects = filter_projects(gitlab_projects) - gitlab_projects = paginate gitlab_projects - - ids = gitlab_projects.map { |project| project.id } - - projects = Ci::Project.where("gitlab_id IN (?)", ids).load - present projects, with: Entities::Project - end - - # Retrieve info for a Gitlab CI project - # - # Parameters: - # id (required) - The ID of a project - # Example Request: - # GET /projects/:id - get ":id" do - project = Ci::Project.find(params[:id]) - unauthorized! unless can?(current_user, :read_project, project.gl_project) - - present project, with: Entities::Project - end - - # Create Gitlab CI project using Gitlab project info - # - # Parameters: - # gitlab_id (required) - The gitlab id of the project - # default_ref - The branch to run against (defaults to `master`) - # Example Request: - # POST /projects - post do - required_attributes! [:gitlab_id] - - filtered_params = { - gitlab_id: params[:gitlab_id], - # we accept gitlab_url for backward compatibility for a while (added to 7.11) - default_ref: params[:default_ref] || 'master' - } - - project = Ci::Project.new(filtered_params) - project.build_missing_services - - if project.save - present project, with: Entities::Project - else - errors = project.errors.full_messages.join(", ") - render_api_error!(errors, 400) - end - end - - # Update a Gitlab CI project - # - # Parameters: - # id (required) - The ID of a project - # default_ref - The branch to run against (defaults to `master`) - # Example Request: - # PUT /projects/:id - put ":id" do - project = Ci::Project.find(params[:id]) - - unauthorized! unless can?(current_user, :admin_project, project.gl_project) - - attrs = attributes_for_keys [:default_ref] - - if project.update_attributes(attrs) - present project, with: Entities::Project - else - errors = project.errors.full_messages.join(", ") - render_api_error!(errors, 400) - end - end - - # Link a Gitlab CI project to a runner - # - # Parameters: - # id (required) - The ID of a CI project - # runner_id (required) - The ID of a runner - # Example Request: - # POST /projects/:id/runners/:runner_id - post ":id/runners/:runner_id" do - project = Ci::Project.find(params[:id]) - runner = Ci::Runner.find(params[:runner_id]) - - unauthorized! unless can?(current_user, :admin_project, project.gl_project) - - options = { - project_id: project.id, - runner_id: runner.id - } - - runner_project = Ci::RunnerProject.new(options) - - if runner_project.save - present runner_project, with: Entities::RunnerProject - else - errors = project.errors.full_messages.join(", ") - render_api_error!(errors, 400) - end - end - - # Remove a Gitlab CI project from a runner - # - # Parameters: - # id (required) - The ID of a CI project - # runner_id (required) - The ID of a runner - # Example Request: - # DELETE /projects/:id/runners/:runner_id - delete ":id/runners/:runner_id" do - project = Ci::Project.find(params[:id]) - runner = Ci::Runner.find(params[:runner_id]) - - unauthorized! unless can?(current_user, :admin_project, project.gl_project) - - options = { - project_id: project.id, - runner_id: runner.id - } - - runner_project = Ci::RunnerProject.find_by(options) - - if runner_project.present? - runner_project.destroy - else - not_found! - end - end - end - end - end -end diff --git a/lib/ci/api/runners.rb b/lib/ci/api/runners.rb index 1466fe4356e..dd77bd65863 100644 --- a/lib/ci/api/runners.rb +++ b/lib/ci/api/runners.rb @@ -3,17 +3,6 @@ module Ci # Runners API class Runners < Grape::API resource :runners do - # Get list of all available runners - # - # Example Request: - # GET /runners - get do - authenticate! - runners = Ci::Runner.all - - present runners, with: Entities::Runner - end - # Delete runner # Parameters: # token (required) - The unique token of runner @@ -47,9 +36,9 @@ module Ci tag_list: params[:tag_list], is_shared: true ) - elsif project = Ci::Project.find_by(token: params[:token]) + elsif project = Project.find_by(token: params[:token]) # Create a specific runner for project. - project.runners.create( + project.ci_runners.create( description: params[:description], tag_list: params[:tag_list] ) diff --git a/lib/ci/api/triggers.rb b/lib/ci/api/triggers.rb index 40907d6db54..6d2cdd8c682 100644 --- a/lib/ci/api/triggers.rb +++ b/lib/ci/api/triggers.rb @@ -14,7 +14,7 @@ module Ci post ":id/refs/:ref/trigger" do required_attributes! [:token] - project = Ci::Project.find(params[:id]) + project = Project.find_by_ci_id(params[:id]) trigger = Ci::Trigger.find_by_token(params[:token].to_s) not_found! unless project && trigger unauthorized! unless trigger.project == project diff --git a/lib/ci/charts.rb b/lib/ci/charts.rb index 5ff7407c6fe..912ccff5f98 100644 --- a/lib/ci/charts.rb +++ b/lib/ci/charts.rb @@ -16,10 +16,10 @@ module Ci def push(from, to, format) @labels << from.strftime(format) - @total << project.builds. + @total << project.ci_builds. where("? > #{Ci::Build.table_name}.created_at AND #{Ci::Build.table_name}.created_at > ?", to, from). count(:all) - @success << project.builds. + @success << project.ci_builds. where("? > #{Ci::Build.table_name}.created_at AND #{Ci::Build.table_name}.created_at > ?", to, from). success.count(:all) end @@ -60,7 +60,7 @@ module Ci class BuildTime < Chart def collect - commits = project.commits.last(30) + commits = project.ci_commits.last(30) commits.each do |commit| @labels << commit.short_sha diff --git a/lib/ci/current_settings.rb b/lib/ci/current_settings.rb deleted file mode 100644 index fd78b024970..00000000000 --- a/lib/ci/current_settings.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Ci - module CurrentSettings - def current_application_settings - key = :ci_current_application_settings - - RequestStore.store[key] ||= begin - if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('ci_application_settings') - Ci::ApplicationSetting.current || Ci::ApplicationSetting.create_from_defaults - else - fake_application_settings - end - end - end - - def fake_application_settings - OpenStruct.new( - all_broken_builds: Ci::Settings.gitlab_ci['all_broken_builds'], - add_pusher: Ci::Settings.gitlab_ci['add_pusher'], - ) - end - end -end diff --git a/lib/ci/scheduler.rb b/lib/ci/scheduler.rb deleted file mode 100644 index ee0958f4be1..00000000000 --- a/lib/ci/scheduler.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Ci - class Scheduler - def perform - projects = Ci::Project.where(always_build: true).all - projects.each do |project| - last_commit = project.commits.last - next unless last_commit && last_commit.last_build - - interval = project.polling_interval - if (last_commit.last_build.created_at + interval.hours) < Time.now - last_commit.retry - end - end - end - end -end diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index 0d156047ff0..5a032b572ae 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -77,7 +77,9 @@ module Grack if project && matched_login.present? && git_cmd == 'git-upload-pack' underscored_service = matched_login['s'].underscore - if Service.available_services_names.include?(underscored_service) + if underscored_service == 'gitlab_ci' + return project && project.builds_enabled? && project.valid_token?(password) + elsif Service.available_services_names.include?(underscored_service) service_method = "#{underscored_service}_service" service = project.send(service_method) diff --git a/lib/gitlab/build_data_builder.rb b/lib/gitlab/build_data_builder.rb index fa2cd551cee..86bfa0a4378 100644 --- a/lib/gitlab/build_data_builder.rb +++ b/lib/gitlab/build_data_builder.rb @@ -2,7 +2,7 @@ module Gitlab class BuildDataBuilder class << self def build(build) - project = build.gl_project + project = build.project commit = build.commit user = build.user diff --git a/lib/tasks/ci/schedule_builds.rake b/lib/tasks/ci/schedule_builds.rake deleted file mode 100644 index 49435504c67..00000000000 --- a/lib/tasks/ci/schedule_builds.rake +++ /dev/null @@ -1,6 +0,0 @@ -namespace :ci do - desc "GitLab CI | Clean running builds" - task schedule_builds: :environment do - Ci::Scheduler.new.perform - end -end -- cgit v1.2.1 From 8cdd54cc0696b76daa2baf463d02d944b50bac6a Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 10 Dec 2015 17:29:44 +0100 Subject: Add runners token --- lib/ci/api/helpers.rb | 4 ---- lib/ci/api/runners.rb | 2 +- lib/ci/api/triggers.rb | 2 +- lib/gitlab/backend/grack_auth.rb | 2 +- 4 files changed, 3 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb index 02502333756..9891b5e38ea 100644 --- a/lib/ci/api/helpers.rb +++ b/lib/ci/api/helpers.rb @@ -13,10 +13,6 @@ module Ci forbidden! unless current_runner end - def authenticate_project_token!(project) - forbidden! unless project.valid_token?(params[:project_token]) - end - def authenticate_build_token!(build) token = (params[BUILD_TOKEN_PARAM] || env[BUILD_TOKEN_HEADER]).to_s forbidden! unless token && build.valid_token?(token) diff --git a/lib/ci/api/runners.rb b/lib/ci/api/runners.rb index dd77bd65863..1e738a73157 100644 --- a/lib/ci/api/runners.rb +++ b/lib/ci/api/runners.rb @@ -36,7 +36,7 @@ module Ci tag_list: params[:tag_list], is_shared: true ) - elsif project = Project.find_by(token: params[:token]) + elsif project = Project.find_by(runners_token: params[:token]) # Create a specific runner for project. project.ci_runners.create( description: params[:description], diff --git a/lib/ci/api/triggers.rb b/lib/ci/api/triggers.rb index 6d2cdd8c682..63b42113513 100644 --- a/lib/ci/api/triggers.rb +++ b/lib/ci/api/triggers.rb @@ -14,7 +14,7 @@ module Ci post ":id/refs/:ref/trigger" do required_attributes! [:token] - project = Project.find_by_ci_id(params[:id]) + project = Project.find_by(ci_id: params[:id].to_i) trigger = Ci::Trigger.find_by_token(params[:token].to_s) not_found! unless project && trigger unauthorized! unless trigger.project == project diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index 5a032b572ae..d854c1c8683 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -78,7 +78,7 @@ module Grack underscored_service = matched_login['s'].underscore if underscored_service == 'gitlab_ci' - return project && project.builds_enabled? && project.valid_token?(password) + return project && project.builds_enabled? && project.valid_build_token?(password) elsif Service.available_services_names.include?(underscored_service) service_method = "#{underscored_service}_service" service = project.send(service_method) -- cgit v1.2.1 From 64bfd9d71a4017e0b5336a2c1565926f4b8beedd Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 10 Dec 2015 17:44:06 +0100 Subject: Remove ci_ prefix from all ci related things --- lib/ci/api/runners.rb | 2 +- lib/ci/charts.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/ci/api/runners.rb b/lib/ci/api/runners.rb index 1e738a73157..8704917b9e4 100644 --- a/lib/ci/api/runners.rb +++ b/lib/ci/api/runners.rb @@ -38,7 +38,7 @@ module Ci ) elsif project = Project.find_by(runners_token: params[:token]) # Create a specific runner for project. - project.ci_runners.create( + project.runners.create( description: params[:description], tag_list: params[:tag_list] ) diff --git a/lib/ci/charts.rb b/lib/ci/charts.rb index 912ccff5f98..d53bdcbd0f2 100644 --- a/lib/ci/charts.rb +++ b/lib/ci/charts.rb @@ -16,10 +16,10 @@ module Ci def push(from, to, format) @labels << from.strftime(format) - @total << project.ci_builds. + @total << project.builds. where("? > #{Ci::Build.table_name}.created_at AND #{Ci::Build.table_name}.created_at > ?", to, from). count(:all) - @success << project.ci_builds. + @success << project.builds. where("? > #{Ci::Build.table_name}.created_at AND #{Ci::Build.table_name}.created_at > ?", to, from). success.count(:all) end -- cgit v1.2.1 From 3d9ce37a48615032c786913acdde1eedba351361 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 10 Dec 2015 18:04:40 +0100 Subject: Reimplement Trigger API --- lib/api/api.rb | 1 + lib/api/entities.rb | 4 ++++ lib/api/triggers.rb | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 lib/api/triggers.rb (limited to 'lib') diff --git a/lib/api/api.rb b/lib/api/api.rb index fe1bf8a4816..7834262d612 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -53,5 +53,6 @@ module API mount Settings mount Keys mount Tags + mount Triggers end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 381babe291b..b1cd80bdf65 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -361,5 +361,9 @@ module API end end end + + class TriggerRequest < Grape::Entity + expose :id, :variables + end end end diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb new file mode 100644 index 00000000000..b713c00e82a --- /dev/null +++ b/lib/api/triggers.rb @@ -0,0 +1,48 @@ +module API + # Triggers API + class Triggers < Grape::API + resource :projects do + # Trigger a GitLab project build + # + # Parameters: + # id (required) - The ID of a CI project + # ref (required) - The name of project's branch or tag + # token (required) - The uniq token of trigger + # variables (optional) - The list of variables to be injected into build + # Example Request: + # POST /projects/:id/trigger/builds + post ":id/trigger/builds" do + required_attributes! [:ref, :token] + + project = Project.find_with_namespace(id) || Project.find_by(id: params[:id]) + trigger = Ci::Trigger.find_by_token(params[:token].to_s) + not_found! unless project && trigger + unauthorized! unless trigger.project == project + + # validate variables + variables = params[:variables] + if variables + unless variables.is_a?(Hash) + render_api_error!('variables needs to be a hash', 400) + end + + unless variables.all? { |key, value| key.is_a?(String) && value.is_a?(String) } + render_api_error!('variables needs to be a map of key-valued strings', 400) + end + + # convert variables from Mash to Hash + variables = variables.to_h + end + + # create request and trigger builds + trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref].to_s, variables) + if trigger_request + present trigger_request, with: Entities::TriggerRequest + else + errors = 'No builds created' + render_api_error!(errors, 400) + end + end + end + end +end -- cgit v1.2.1 From 3578153d3e838da92587fed88a608d9a5458c37c Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 10 Dec 2015 18:12:19 +0100 Subject: Fix triggers tests --- lib/api/triggers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb index b713c00e82a..2781f1cf191 100644 --- a/lib/api/triggers.rb +++ b/lib/api/triggers.rb @@ -14,7 +14,7 @@ module API post ":id/trigger/builds" do required_attributes! [:ref, :token] - project = Project.find_with_namespace(id) || Project.find_by(id: params[:id]) + project = Project.find_with_namespace(params[:id]) || Project.find_by(id: params[:id]) trigger = Ci::Trigger.find_by_token(params[:token].to_s) not_found! unless project && trigger unauthorized! unless trigger.project == project -- cgit v1.2.1 From 513d551c8f7078e263d31ef2c30a1f72cbab3fae Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 11 Dec 2015 13:39:43 +0100 Subject: Fix after column rename --- lib/ci/api/entities.rb | 9 --------- 1 file changed, 9 deletions(-) (limited to 'lib') diff --git a/lib/ci/api/entities.rb b/lib/ci/api/entities.rb index 750f421872d..e4ac0545ea2 100644 --- a/lib/ci/api/entities.rb +++ b/lib/ci/api/entities.rb @@ -37,15 +37,6 @@ module Ci expose :id, :token end - class Project < Grape::Entity - expose :id, :name, :token, :default_ref, :gitlab_url, :path, - :always_build, :polling_interval, :public, :ssh_url_to_repo, :gitlab_id - - expose :timeout do |model| - model.timeout - end - end - class RunnerProject < Grape::Entity expose :id, :project_id, :runner_id end -- cgit v1.2.1 From dd8102f2d1acd803793777b26c84d7c6e977b8e2 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 11 Dec 2015 14:37:16 +0100 Subject: Fix specs --- lib/gitlab/backend/grack_auth.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index d854c1c8683..cdcaae8094c 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -78,7 +78,7 @@ module Grack underscored_service = matched_login['s'].underscore if underscored_service == 'gitlab_ci' - return project && project.builds_enabled? && project.valid_build_token?(password) + return project && project.valid_build_token?(password) elsif Service.available_services_names.include?(underscored_service) service_method = "#{underscored_service}_service" service = project.send(service_method) -- cgit v1.2.1 From c9ac38a074423b30b5627553bfdbf0ba15737d8e Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 11 Dec 2015 17:57:04 +0100 Subject: Use Gitlab::Git instead of Ci::Git --- lib/ci/git.rb | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 lib/ci/git.rb (limited to 'lib') diff --git a/lib/ci/git.rb b/lib/ci/git.rb deleted file mode 100644 index 7acc3f38edb..00000000000 --- a/lib/ci/git.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Ci - module Git - BLANK_SHA = '0' * 40 - end -end -- cgit v1.2.1 From 3efae53bd79db118463bfaeceb209bc91f63bd0b Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 11 Dec 2015 23:17:36 -0800 Subject: Add open_issues_count to project API This is needed to support Huboard and a generally useful value. --- lib/api/entities.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 81bf7a8222b..014116ef130 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -68,6 +68,7 @@ module API expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ | project, options | project.forked? } expose :avatar_url expose :star_count, :forks_count + expose :open_issues_count, if: lambda { | project, options | project.issues_enabled? && project.default_issues_tracker? } end class ProjectMember < UserBasic -- cgit v1.2.1 From 9c5d8079a367ac24d04466f03f6b9abf5c333f59 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 24 Nov 2015 08:28:18 -0800 Subject: Bump Redis requirement to 2.8 for Sidekiq 4 requirements Closes #3649 [ci skip] --- lib/tasks/gitlab/check.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index a25fac62cfc..b5af3d88b4c 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -331,7 +331,7 @@ namespace :gitlab do end def check_redis_version - min_redis_version = "2.4.0" + min_redis_version = "2.8.0" print "Redis version >= #{min_redis_version}? ... " redis_version = run(%W(redis-cli --version)) -- cgit v1.2.1 From f8bf6c4b2c5fb41ae92df09b9f968d5d5d61bb2b Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Fri, 11 Dec 2015 17:27:20 -0600 Subject: [ci skip] Add user repository integrity check rake task --- lib/tasks/gitlab/check.rake | 56 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index a25fac62cfc..167b0112666 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -822,10 +822,27 @@ namespace :gitlab do namespace_dirs.each do |namespace_dir| repo_dirs = Dir.glob(File.join(namespace_dir, '*')) - repo_dirs.each do |dir| - puts "\nChecking repo at #{dir}" - system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: dir) - end + repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) } + end + end + end + + namespace :user do + desc "GitLab | Check the integrity of a specific user's repositories" + task :check_repos, [:username] => :environment do |t, args| + username = args[:username] || prompt("Check repository integrity for which username? ".blue) + user = User.find_by(username: username) + if user + repo_dirs = user.authorized_projects.map do |p| + File.join( + Gitlab.config.gitlab_shell.repos_path, + "#{p.path_with_namespace}.git" + ) + end + + repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) } + else + puts "\nUser '#{username}' not found".red end end end @@ -952,4 +969,35 @@ namespace :gitlab do false end end + + def check_repo_integrity(repo_dir) + puts "\nChecking repo at #{repo_dir.yellow}" + + git_fsck(repo_dir) + check_config_lock(repo_dir) + check_ref_locks(repo_dir) + end + + def git_fsck(repo_dir) + puts "Running `git fsck`".yellow + system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: repo_dir) + end + + def check_config_lock(repo_dir) + config_exists = File.exist?(File.join(repo_dir,'config.lock')) + config_output = config_exists ? 'yes'.red : 'no'.green + puts "'config.lock' file exists?".yellow + " ... #{config_output}" + end + + def check_ref_locks(repo_dir) + lock_files = Dir.glob(File.join(repo_dir,'refs/heads/*.lock')) + if lock_files.present? + puts "Ref lock files exist:".red + lock_files.each do |lock_file| + puts " #{lock_file}" + end + else + puts "No ref lock files exist".green + end + end end -- cgit v1.2.1 From b5291f95996743067bbec5a32f9c6cf0d34b36c7 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Tue, 15 Dec 2015 00:53:52 -0200 Subject: Fixed Rubocop offenses --- lib/api/entities.rb | 2 +- lib/gitlab/backend/shell.rb | 2 +- lib/gitlab/bitbucket_import/project_creator.rb | 3 ++- lib/gitlab/diff/file.rb | 4 ++-- lib/gitlab/fogbugz_import/importer.rb | 2 +- lib/gitlab/fogbugz_import/project_creator.rb | 3 ++- lib/gitlab/gitlab_import/project_creator.rb | 3 ++- lib/gitlab/gitorious_import/project_creator.rb | 3 ++- lib/gitlab/google_code_import/importer.rb | 6 +++--- lib/gitlab/google_code_import/project_creator.rb | 3 ++- lib/gitlab/markdown/filter/markdown_filter.rb | 2 +- lib/gitlab/markdown/filter/table_of_contents_filter.rb | 2 +- lib/rouge/formatters/html_gitlab.rb | 2 +- 13 files changed, 21 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index b1cd80bdf65..a5daa45faf0 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -67,7 +67,7 @@ module API expose :shared_runners_enabled expose :creator_id expose :namespace - expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ | project, options | project.forked? } + expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ |project, options| project.forked? } expose :avatar_url expose :star_count, :forks_count end diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index 87ac30b5ffe..459e3d6bcdb 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -2,7 +2,7 @@ module Gitlab class Shell class Error < StandardError; end - class KeyAdder < Struct.new(:io) + KeyAdder = Struct.new(:io) do def add_key(id, key) key.gsub!(/[[:space:]]+/, ' ').strip! io.puts("#{id}\t#{key}") diff --git a/lib/gitlab/bitbucket_import/project_creator.rb b/lib/gitlab/bitbucket_import/project_creator.rb index 35e34d033e0..03aac1a025a 100644 --- a/lib/gitlab/bitbucket_import/project_creator.rb +++ b/lib/gitlab/bitbucket_import/project_creator.rb @@ -11,7 +11,8 @@ module Gitlab end def execute - project = ::Projects::CreateService.new(current_user, + project = ::Projects::CreateService.new( + current_user, name: repo["name"], path: repo["slug"], description: repo["description"], diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index 142058aa69d..79061cd0141 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -46,11 +46,11 @@ module Gitlab end def added_lines - diff_lines.select(&:added?).size + diff_lines.count(&:added?) end def removed_lines - diff_lines.select(&:removed?).size + diff_lines.count(&:removed?) end end end diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb index 496256700b8..403ebeec474 100644 --- a/lib/gitlab/fogbugz_import/importer.rb +++ b/lib/gitlab/fogbugz_import/importer.rb @@ -199,7 +199,7 @@ module Gitlab s = s.gsub(/^#/, "\\#") s = s.gsub(/^-/, "\\-") s = s.gsub("`", "\\~") - s = s.gsub("\r", "") + s = s.delete("\r") s = s.gsub("\n", " \n") s end diff --git a/lib/gitlab/fogbugz_import/project_creator.rb b/lib/gitlab/fogbugz_import/project_creator.rb index 8b1b6f48ed5..e0163499e30 100644 --- a/lib/gitlab/fogbugz_import/project_creator.rb +++ b/lib/gitlab/fogbugz_import/project_creator.rb @@ -12,7 +12,8 @@ module Gitlab end def execute - project = ::Projects::CreateService.new(current_user, + project = ::Projects::CreateService.new( + current_user, name: repo.safe_name, path: repo.path, namespace: namespace, diff --git a/lib/gitlab/gitlab_import/project_creator.rb b/lib/gitlab/gitlab_import/project_creator.rb index d9452de6a50..7baaadb813c 100644 --- a/lib/gitlab/gitlab_import/project_creator.rb +++ b/lib/gitlab/gitlab_import/project_creator.rb @@ -11,7 +11,8 @@ module Gitlab end def execute - project = ::Projects::CreateService.new(current_user, + project = ::Projects::CreateService.new( + current_user, name: repo["name"], path: repo["path"], description: repo["description"], diff --git a/lib/gitlab/gitorious_import/project_creator.rb b/lib/gitlab/gitorious_import/project_creator.rb index cc9a91c91f4..8e22aa9286d 100644 --- a/lib/gitlab/gitorious_import/project_creator.rb +++ b/lib/gitlab/gitorious_import/project_creator.rb @@ -10,7 +10,8 @@ module Gitlab end def execute - ::Projects::CreateService.new(current_user, + ::Projects::CreateService.new( + current_user, name: repo.name, path: repo.path, description: repo.description, diff --git a/lib/gitlab/google_code_import/importer.rb b/lib/gitlab/google_code_import/importer.rb index 87fee28dc01..62da327931f 100644 --- a/lib/gitlab/google_code_import/importer.rb +++ b/lib/gitlab/google_code_import/importer.rb @@ -171,8 +171,6 @@ module Gitlab when /\AMilestone:/ "#fee3ff" - when *@closed_statuses.map { |s| nice_status_name(s) } - "#cfcfcf" when "Status: New" "#428bca" when "Status: Accepted" @@ -199,6 +197,8 @@ module Gitlab "#8e44ad" when "Type: Other" "#7f8c8d" + when *@closed_statuses.map { |s| nice_status_name(s) } + "#cfcfcf" else "#e2e2e2" end @@ -227,7 +227,7 @@ module Gitlab s = s.gsub("`", "\\`") # Carriage returns make me sad - s = s.gsub("\r", "") + s = s.delete("\r") # Markdown ignores single newlines, but we need them as
    . s = s.gsub("\n", " \n") diff --git a/lib/gitlab/google_code_import/project_creator.rb b/lib/gitlab/google_code_import/project_creator.rb index 1cb7d16aeb3..87821c23460 100644 --- a/lib/gitlab/google_code_import/project_creator.rb +++ b/lib/gitlab/google_code_import/project_creator.rb @@ -11,7 +11,8 @@ module Gitlab end def execute - project = ::Projects::CreateService.new(current_user, + project = ::Projects::CreateService.new( + current_user, name: repo.name, path: repo.name, description: repo.summary, diff --git a/lib/gitlab/markdown/filter/markdown_filter.rb b/lib/gitlab/markdown/filter/markdown_filter.rb index 921e2a0794e..b1b974fcc70 100644 --- a/lib/gitlab/markdown/filter/markdown_filter.rb +++ b/lib/gitlab/markdown/filter/markdown_filter.rb @@ -3,7 +3,7 @@ module Gitlab class MarkdownFilter < HTML::Pipeline::TextFilter def initialize(text, context = nil, result = nil) super text, context, result - @text = @text.gsub "\r", '' + @text = @text.delete "\r" end def call diff --git a/lib/gitlab/markdown/filter/table_of_contents_filter.rb b/lib/gitlab/markdown/filter/table_of_contents_filter.rb index bbb3bf7fc8b..6be644b0f67 100644 --- a/lib/gitlab/markdown/filter/table_of_contents_filter.rb +++ b/lib/gitlab/markdown/filter/table_of_contents_filter.rb @@ -31,7 +31,7 @@ module Gitlab id = text.downcase id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation - id.gsub!(' ', '-') # replace spaces with dash + id.tr!(' ', '-') # replace spaces with dash id.squeeze!('-') # replace multiple dashes with one uniq = (headers[id] > 0) ? "-#{headers[id]}" : '' diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb index 6762ca47c32..8c309efc7b8 100644 --- a/lib/rouge/formatters/html_gitlab.rb +++ b/lib/rouge/formatters/html_gitlab.rb @@ -39,7 +39,7 @@ module Rouge lineanchorsid: 'L', anchorlinenos: false, inline_theme: nil - ) + ) @nowrap = nowrap @cssclass = cssclass @linenos = linenos -- cgit v1.2.1 From 7781bda9bd82997f4a03de4cf911b1156ceb2cde Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 15 Dec 2015 15:51:16 +0100 Subject: Move Markdown/reference logic from Gitlab::Markdown to Banzai --- lib/banzai.rb | 13 ++ lib/banzai/cross_project_reference.rb | 22 +++ lib/banzai/filter.rb | 10 + lib/banzai/filter/abstract_reference_filter.rb | 145 ++++++++++++++ lib/banzai/filter/autolink_filter.rb | 107 +++++++++++ lib/banzai/filter/commit_range_reference_filter.rb | 58 ++++++ lib/banzai/filter/commit_reference_filter.rb | 63 ++++++ lib/banzai/filter/emoji_filter.rb | 80 ++++++++ .../filter/external_issue_reference_filter.rb | 69 +++++++ lib/banzai/filter/external_link_filter.rb | 34 ++++ lib/banzai/filter/issue_reference_filter.rb | 23 +++ lib/banzai/filter/label_reference_filter.rb | 96 ++++++++++ lib/banzai/filter/markdown_filter.rb | 42 ++++ .../filter/merge_request_reference_filter.rb | 41 ++++ lib/banzai/filter/redactor_filter.rb | 43 +++++ lib/banzai/filter/reference_filter.rb | 190 +++++++++++++++++++ lib/banzai/filter/reference_gatherer_filter.rb | 62 ++++++ lib/banzai/filter/relative_link_filter.rb | 157 +++++++++++++++ lib/banzai/filter/sanitization_filter.rb | 99 ++++++++++ lib/banzai/filter/snippet_reference_filter.rb | 25 +++ lib/banzai/filter/syntax_highlight_filter.rb | 45 +++++ lib/banzai/filter/table_of_contents_filter.rb | 63 ++++++ lib/banzai/filter/task_list_filter.rb | 24 +++ lib/banzai/filter/upload_link_filter.rb | 47 +++++ lib/banzai/filter/user_reference_filter.rb | 129 +++++++++++++ lib/banzai/lazy_reference.rb | 27 +++ lib/banzai/pipeline.rb | 10 + lib/banzai/pipeline/asciidoc_pipeline.rb | 13 ++ lib/banzai/pipeline/atom_pipeline.rb | 14 ++ lib/banzai/pipeline/base_pipeline.rb | 30 +++ lib/banzai/pipeline/combined_pipeline.rb | 27 +++ lib/banzai/pipeline/description_pipeline.rb | 14 ++ lib/banzai/pipeline/email_pipeline.rb | 13 ++ lib/banzai/pipeline/full_pipeline.rb | 9 + lib/banzai/pipeline/gfm_pipeline.rb | 41 ++++ lib/banzai/pipeline/note_pipeline.rb | 14 ++ lib/banzai/pipeline/plain_markdown_pipeline.rb | 13 ++ lib/banzai/pipeline/post_process_pipeline.rb | 20 ++ .../pipeline/reference_extraction_pipeline.rb | 13 ++ lib/banzai/pipeline/single_line_pipeline.rb | 9 + lib/banzai/reference_extractor.rb | 55 ++++++ lib/banzai/renderer.rb | 76 ++++++++ lib/gitlab/asciidoc.rb | 2 +- lib/gitlab/markdown.rb | 115 ----------- lib/gitlab/markdown/abstract_reference_filter.rb | 145 -------------- lib/gitlab/markdown/combined_pipeline.rb | 27 --- lib/gitlab/markdown/cross_project_reference.rb | 24 --- lib/gitlab/markdown/filter/autolink_filter.rb | 107 ----------- .../filter/commit_range_reference_filter.rb | 58 ------ .../markdown/filter/commit_reference_filter.rb | 63 ------ lib/gitlab/markdown/filter/emoji_filter.rb | 80 -------- .../filter/external_issue_reference_filter.rb | 69 ------- lib/gitlab/markdown/filter/external_link_filter.rb | 34 ---- .../markdown/filter/issue_reference_filter.rb | 23 --- .../markdown/filter/label_reference_filter.rb | 96 ---------- lib/gitlab/markdown/filter/markdown_filter.rb | 39 ---- .../filter/merge_request_reference_filter.rb | 41 ---- lib/gitlab/markdown/filter/redactor_filter.rb | 43 ----- .../markdown/filter/reference_gatherer_filter.rb | 63 ------ lib/gitlab/markdown/filter/relative_link_filter.rb | 157 --------------- lib/gitlab/markdown/filter/sanitization_filter.rb | 99 ---------- .../markdown/filter/snippet_reference_filter.rb | 25 --- .../markdown/filter/syntax_highlight_filter.rb | 45 ----- .../markdown/filter/table_of_contents_filter.rb | 63 ------ lib/gitlab/markdown/filter/task_list_filter.rb | 24 --- lib/gitlab/markdown/filter/upload_link_filter.rb | 47 ----- .../markdown/filter/user_reference_filter.rb | 129 ------------- lib/gitlab/markdown/pipeline.rb | 4 +- lib/gitlab/markdown/pipeline/asciidoc_pipeline.rb | 13 -- lib/gitlab/markdown/pipeline/atom_pipeline.rb | 14 -- .../markdown/pipeline/description_pipeline.rb | 14 -- lib/gitlab/markdown/pipeline/email_pipeline.rb | 13 -- lib/gitlab/markdown/pipeline/full_pipeline.rb | 9 - lib/gitlab/markdown/pipeline/gfm_pipeline.rb | 41 ---- lib/gitlab/markdown/pipeline/note_pipeline.rb | 14 -- .../markdown/pipeline/plain_markdown_pipeline.rb | 13 -- .../markdown/pipeline/post_process_pipeline.rb | 20 -- .../pipeline/reference_extraction_pipeline.rb | 13 -- .../markdown/pipeline/single_line_pipeline.rb | 9 - lib/gitlab/markdown/reference_filter.rb | 211 --------------------- lib/gitlab/reference_extractor.rb | 53 +----- 81 files changed, 2097 insertions(+), 2047 deletions(-) create mode 100644 lib/banzai.rb create mode 100644 lib/banzai/cross_project_reference.rb create mode 100644 lib/banzai/filter.rb create mode 100644 lib/banzai/filter/abstract_reference_filter.rb create mode 100644 lib/banzai/filter/autolink_filter.rb create mode 100644 lib/banzai/filter/commit_range_reference_filter.rb create mode 100644 lib/banzai/filter/commit_reference_filter.rb create mode 100644 lib/banzai/filter/emoji_filter.rb create mode 100644 lib/banzai/filter/external_issue_reference_filter.rb create mode 100644 lib/banzai/filter/external_link_filter.rb create mode 100644 lib/banzai/filter/issue_reference_filter.rb create mode 100644 lib/banzai/filter/label_reference_filter.rb create mode 100644 lib/banzai/filter/markdown_filter.rb create mode 100644 lib/banzai/filter/merge_request_reference_filter.rb create mode 100644 lib/banzai/filter/redactor_filter.rb create mode 100644 lib/banzai/filter/reference_filter.rb create mode 100644 lib/banzai/filter/reference_gatherer_filter.rb create mode 100644 lib/banzai/filter/relative_link_filter.rb create mode 100644 lib/banzai/filter/sanitization_filter.rb create mode 100644 lib/banzai/filter/snippet_reference_filter.rb create mode 100644 lib/banzai/filter/syntax_highlight_filter.rb create mode 100644 lib/banzai/filter/table_of_contents_filter.rb create mode 100644 lib/banzai/filter/task_list_filter.rb create mode 100644 lib/banzai/filter/upload_link_filter.rb create mode 100644 lib/banzai/filter/user_reference_filter.rb create mode 100644 lib/banzai/lazy_reference.rb create mode 100644 lib/banzai/pipeline.rb create mode 100644 lib/banzai/pipeline/asciidoc_pipeline.rb create mode 100644 lib/banzai/pipeline/atom_pipeline.rb create mode 100644 lib/banzai/pipeline/base_pipeline.rb create mode 100644 lib/banzai/pipeline/combined_pipeline.rb create mode 100644 lib/banzai/pipeline/description_pipeline.rb create mode 100644 lib/banzai/pipeline/email_pipeline.rb create mode 100644 lib/banzai/pipeline/full_pipeline.rb create mode 100644 lib/banzai/pipeline/gfm_pipeline.rb create mode 100644 lib/banzai/pipeline/note_pipeline.rb create mode 100644 lib/banzai/pipeline/plain_markdown_pipeline.rb create mode 100644 lib/banzai/pipeline/post_process_pipeline.rb create mode 100644 lib/banzai/pipeline/reference_extraction_pipeline.rb create mode 100644 lib/banzai/pipeline/single_line_pipeline.rb create mode 100644 lib/banzai/reference_extractor.rb create mode 100644 lib/banzai/renderer.rb delete mode 100644 lib/gitlab/markdown.rb delete mode 100644 lib/gitlab/markdown/abstract_reference_filter.rb delete mode 100644 lib/gitlab/markdown/combined_pipeline.rb delete mode 100644 lib/gitlab/markdown/cross_project_reference.rb delete mode 100644 lib/gitlab/markdown/filter/autolink_filter.rb delete mode 100644 lib/gitlab/markdown/filter/commit_range_reference_filter.rb delete mode 100644 lib/gitlab/markdown/filter/commit_reference_filter.rb delete mode 100644 lib/gitlab/markdown/filter/emoji_filter.rb delete mode 100644 lib/gitlab/markdown/filter/external_issue_reference_filter.rb delete mode 100644 lib/gitlab/markdown/filter/external_link_filter.rb delete mode 100644 lib/gitlab/markdown/filter/issue_reference_filter.rb delete mode 100644 lib/gitlab/markdown/filter/label_reference_filter.rb delete mode 100644 lib/gitlab/markdown/filter/markdown_filter.rb delete mode 100644 lib/gitlab/markdown/filter/merge_request_reference_filter.rb delete mode 100644 lib/gitlab/markdown/filter/redactor_filter.rb delete mode 100644 lib/gitlab/markdown/filter/reference_gatherer_filter.rb delete mode 100644 lib/gitlab/markdown/filter/relative_link_filter.rb delete mode 100644 lib/gitlab/markdown/filter/sanitization_filter.rb delete mode 100644 lib/gitlab/markdown/filter/snippet_reference_filter.rb delete mode 100644 lib/gitlab/markdown/filter/syntax_highlight_filter.rb delete mode 100644 lib/gitlab/markdown/filter/table_of_contents_filter.rb delete mode 100644 lib/gitlab/markdown/filter/task_list_filter.rb delete mode 100644 lib/gitlab/markdown/filter/upload_link_filter.rb delete mode 100644 lib/gitlab/markdown/filter/user_reference_filter.rb delete mode 100644 lib/gitlab/markdown/pipeline/asciidoc_pipeline.rb delete mode 100644 lib/gitlab/markdown/pipeline/atom_pipeline.rb delete mode 100644 lib/gitlab/markdown/pipeline/description_pipeline.rb delete mode 100644 lib/gitlab/markdown/pipeline/email_pipeline.rb delete mode 100644 lib/gitlab/markdown/pipeline/full_pipeline.rb delete mode 100644 lib/gitlab/markdown/pipeline/gfm_pipeline.rb delete mode 100644 lib/gitlab/markdown/pipeline/note_pipeline.rb delete mode 100644 lib/gitlab/markdown/pipeline/plain_markdown_pipeline.rb delete mode 100644 lib/gitlab/markdown/pipeline/post_process_pipeline.rb delete mode 100644 lib/gitlab/markdown/pipeline/reference_extraction_pipeline.rb delete mode 100644 lib/gitlab/markdown/pipeline/single_line_pipeline.rb delete mode 100644 lib/gitlab/markdown/reference_filter.rb (limited to 'lib') diff --git a/lib/banzai.rb b/lib/banzai.rb new file mode 100644 index 00000000000..093382261ae --- /dev/null +++ b/lib/banzai.rb @@ -0,0 +1,13 @@ +module Banzai + def self.render(text, context = {}) + Renderer.render(text, context) + end + + def self.render_result(text, context = {}) + Renderer.render_result(text, context) + end + + def self.post_process(html, context) + Renderer.post_process(html, context) + end +end diff --git a/lib/banzai/cross_project_reference.rb b/lib/banzai/cross_project_reference.rb new file mode 100644 index 00000000000..ba2866e1efa --- /dev/null +++ b/lib/banzai/cross_project_reference.rb @@ -0,0 +1,22 @@ +require 'banzai' + +module Banzai + # Common methods for ReferenceFilters that support an optional cross-project + # reference. + module CrossProjectReference + # Given a cross-project reference string, get the Project record + # + # Defaults to value of `context[:project]` if: + # * No reference is given OR + # * Reference given doesn't exist + # + # ref - String reference. + # + # Returns a Project, or nil if the reference can't be found + def project_from_ref(ref) + return context[:project] unless ref + + Project.find_with_namespace(ref) + end + end +end diff --git a/lib/banzai/filter.rb b/lib/banzai/filter.rb new file mode 100644 index 00000000000..fd4fe024252 --- /dev/null +++ b/lib/banzai/filter.rb @@ -0,0 +1,10 @@ +require 'active_support/core_ext/string/output_safety' +require 'banzai' + +module Banzai + module Filter + def self.[](name) + const_get("#{name.to_s.camelize}Filter") + end + end +end diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb new file mode 100644 index 00000000000..bdaa4721b4b --- /dev/null +++ b/lib/banzai/filter/abstract_reference_filter.rb @@ -0,0 +1,145 @@ +require 'banzai' + +module Banzai + module Filter + # Issues, Merge Requests, Snippets, Commits and Commit Ranges share + # similar functionality in reference filtering. + class AbstractReferenceFilter < ReferenceFilter + include CrossProjectReference + + def self.object_class + # Implement in child class + # Example: MergeRequest + end + + def self.object_name + object_class.name.underscore + end + + def self.object_sym + object_name.to_sym + end + + def self.data_reference + "data-#{object_name.dasherize}" + end + + # Public: Find references in text (like `!123` for merge requests) + # + # AnyReferenceFilter.references_in(text) do |match, id, project_ref, matches| + # object = find_object(project_ref, id) + # "#{object.to_reference}" + # end + # + # text - String text to search. + # + # Yields the String match, the Integer referenced object ID, an optional String + # of the external project reference, and all of the matchdata. + # + # Returns a String replaced with the return of the block. + def self.references_in(text, pattern = object_class.reference_pattern) + text.gsub(pattern) do |match| + yield match, $~[object_sym].to_i, $~[:project], $~ + end + end + + def self.referenced_by(node) + { object_sym => LazyReference.new(object_class, node.attr(data_reference)) } + end + + delegate :object_class, :object_sym, :references_in, to: :class + + def find_object(project, id) + # Implement in child class + # Example: project.merge_requests.find + end + + def url_for_object(object, project) + # Implement in child class + # Example: project_merge_request_url + end + + def call + # `#123` + replace_text_nodes_matching(object_class.reference_pattern) do |content| + object_link_filter(content, object_class.reference_pattern) + end + + # `[Issue](#123)`, which is turned into + # `Issue` + replace_link_nodes_with_href(object_class.reference_pattern) do |link, text| + object_link_filter(link, object_class.reference_pattern, link_text: text) + end + + # `http://gitlab.example.com/namespace/project/issues/123`, which is turned into + # `http://gitlab.example.com/namespace/project/issues/123` + replace_link_nodes_with_text(object_class.link_reference_pattern) do |text| + object_link_filter(text, object_class.link_reference_pattern) + end + + # `[Issue](http://gitlab.example.com/namespace/project/issues/123)`, which is turned into + # `Issue` + replace_link_nodes_with_href(object_class.link_reference_pattern) do |link, text| + object_link_filter(link, object_class.link_reference_pattern, link_text: text) + end + end + + # Replace references (like `!123` for merge requests) in text with links + # to the referenced object's details page. + # + # text - String text to replace references in. + # pattern - Reference pattern to match against. + # link_text - Original content of the link being replaced. + # + # Returns a String with references replaced with links. All links + # have `gfm` and `gfm-OBJECT_NAME` class names attached for styling. + def object_link_filter(text, pattern, link_text: nil) + references_in(text, pattern) do |match, id, project_ref, matches| + project = project_from_ref(project_ref) + + if project && object = find_object(project, id) + title = escape_once(object_link_title(object)) + klass = reference_class(object_sym) + + data = data_attribute( + original: link_text || match, + project: project.id, + object_sym => object.id + ) + + url = matches[:url] if matches.names.include?("url") + url ||= url_for_object(object, project) + + text = link_text + unless text + text = object.reference_link_text(context[:project]) + + extras = object_link_text_extras(object, matches) + text += " (#{extras.join(", ")})" if extras.any? + end + + %(#{text}) + else + match + end + end + end + + def object_link_text_extras(object, matches) + extras = [] + + if matches.names.include?("anchor") && matches[:anchor] && matches[:anchor] =~ /\A\#note_(\d+)\z/ + extras << "comment #{$1}" + end + + extras + end + + def object_link_title(object) + "#{object_class.name.titleize}: #{object.title}" + end + end + end +end diff --git a/lib/banzai/filter/autolink_filter.rb b/lib/banzai/filter/autolink_filter.rb new file mode 100644 index 00000000000..da4ee80c1b5 --- /dev/null +++ b/lib/banzai/filter/autolink_filter.rb @@ -0,0 +1,107 @@ +require 'banzai' +require 'html/pipeline/filter' +require 'uri' + +module Banzai + module Filter + # HTML Filter for auto-linking URLs in HTML. + # + # Based on HTML::Pipeline::AutolinkFilter + # + # Context options: + # :autolink - Boolean, skips all processing done by this filter when false + # :link_attr - Hash of attributes for the generated links + # + class AutolinkFilter < HTML::Pipeline::Filter + include ActionView::Helpers::TagHelper + + # Pattern to match text that should be autolinked. + # + # A URI scheme begins with a letter and may contain letters, numbers, + # plus, period and hyphen. Schemes are case-insensitive but we're being + # picky here and allowing only lowercase for autolinks. + # + # See http://en.wikipedia.org/wiki/URI_scheme + # + # The negative lookbehind ensures that users can paste a URL followed by a + # period or comma for punctuation without those characters being included + # in the generated link. + # + # Rubular: http://rubular.com/r/cxjPyZc7Sb + LINK_PATTERN = %r{([a-z][a-z0-9\+\.-]+://\S+)(?" + end + end + + private + + def emoji_url(name) + emoji_path = "emoji/#{emoji_filename(name)}" + if context[:asset_host] + # Asset host is specified. + url_to_image(emoji_path) + elsif context[:asset_root] + # Gitlab url is specified + File.join(context[:asset_root], url_to_image(emoji_path)) + else + # All other cases + url_to_image(emoji_path) + end + end + + def url_to_image(image) + ActionController::Base.helpers.url_to_image(image) + end + + # Build a regexp that matches all valid :emoji: names. + def self.emoji_pattern + @emoji_pattern ||= /:(#{Emoji.emojis_names.map { |name| Regexp.escape(name) }.join('|')}):/ + end + + def emoji_pattern + self.class.emoji_pattern + end + + def emoji_filename(name) + "#{Emoji.emoji_filename(name)}.png" + end + end + end +end diff --git a/lib/banzai/filter/external_issue_reference_filter.rb b/lib/banzai/filter/external_issue_reference_filter.rb new file mode 100644 index 00000000000..f5737a7ac19 --- /dev/null +++ b/lib/banzai/filter/external_issue_reference_filter.rb @@ -0,0 +1,69 @@ +require 'banzai' + +module Banzai + module Filter + # HTML filter that replaces external issue tracker references with links. + # References are ignored if the project doesn't use an external issue + # tracker. + class ExternalIssueReferenceFilter < ReferenceFilter + # Public: Find `JIRA-123` issue references in text + # + # ExternalIssueReferenceFilter.references_in(text) do |match, issue| + # "##{issue}" + # end + # + # text - String text to search. + # + # Yields the String match and the String issue reference. + # + # Returns a String replaced with the return of the block. + def self.references_in(text) + text.gsub(ExternalIssue.reference_pattern) do |match| + yield match, $~[:issue] + end + end + + def call + # Early return if the project isn't using an external tracker + return doc if project.nil? || project.default_issues_tracker? + + replace_text_nodes_matching(ExternalIssue.reference_pattern) do |content| + issue_link_filter(content) + end + + replace_link_nodes_with_href(ExternalIssue.reference_pattern) do |link, text| + issue_link_filter(link, link_text: text) + end + end + + # Replace `JIRA-123` issue references in text with links to the referenced + # issue's details page. + # + # text - String text to replace references in. + # + # Returns a String with `JIRA-123` references replaced with links. All + # links have `gfm` and `gfm-issue` class names attached for styling. + def issue_link_filter(text, link_text: nil) + project = context[:project] + + self.class.references_in(text) do |match, issue| + url = url_for_issue(issue, project, only_path: context[:only_path]) + + title = escape_once("Issue in #{project.external_issue_tracker.title}") + klass = reference_class(:issue) + data = data_attribute(project: project.id) + + text = link_text || match + + %(#{text}) + end + end + + def url_for_issue(*args) + IssuesHelper.url_for_issue(*args) + end + end + end +end diff --git a/lib/banzai/filter/external_link_filter.rb b/lib/banzai/filter/external_link_filter.rb new file mode 100644 index 00000000000..ac87b9820af --- /dev/null +++ b/lib/banzai/filter/external_link_filter.rb @@ -0,0 +1,34 @@ +require 'banzai' +require 'html/pipeline/filter' + +module Banzai + module Filter + # HTML Filter to add a `rel="nofollow"` attribute to external links + # + class ExternalLinkFilter < HTML::Pipeline::Filter + def call + doc.search('a').each do |node| + link = node.attr('href') + + next unless link + + # Skip non-HTTP(S) links + next unless link.start_with?('http') + + # Skip internal links + next if link.start_with?(internal_url) + + node.set_attribute('rel', 'nofollow') + end + + doc + end + + private + + def internal_url + @internal_url ||= Gitlab.config.gitlab.url + end + end + end +end diff --git a/lib/banzai/filter/issue_reference_filter.rb b/lib/banzai/filter/issue_reference_filter.rb new file mode 100644 index 00000000000..51180cb901a --- /dev/null +++ b/lib/banzai/filter/issue_reference_filter.rb @@ -0,0 +1,23 @@ +require 'banzai' + +module Banzai + module Filter + # HTML filter that replaces issue references with links. References to + # issues that do not exist are ignored. + # + # This filter supports cross-project references. + class IssueReferenceFilter < AbstractReferenceFilter + def self.object_class + Issue + end + + def find_object(project, id) + project.get_issue(id) + end + + def url_for_object(issue, project) + IssuesHelper.url_for_issue(issue.iid, project, only_path: context[:only_path]) + end + end + end +end diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb new file mode 100644 index 00000000000..07bac2dd7fd --- /dev/null +++ b/lib/banzai/filter/label_reference_filter.rb @@ -0,0 +1,96 @@ +require 'banzai' + +module Banzai + module Filter + # HTML filter that replaces label references with links. + class LabelReferenceFilter < ReferenceFilter + # Public: Find label references in text + # + # LabelReferenceFilter.references_in(text) do |match, id, name| + # "#{Label.find(id)}" + # end + # + # text - String text to search. + # + # Yields the String match, an optional Integer label ID, and an optional + # String label name. + # + # Returns a String replaced with the return of the block. + def self.references_in(text) + text.gsub(Label.reference_pattern) do |match| + yield match, $~[:label_id].to_i, $~[:label_name] + end + end + + def self.referenced_by(node) + { label: LazyReference.new(Label, node.attr("data-label")) } + end + + def call + replace_text_nodes_matching(Label.reference_pattern) do |content| + label_link_filter(content) + end + + replace_link_nodes_with_href(Label.reference_pattern) do |link, text| + label_link_filter(link, link_text: text) + end + end + + # Replace label references in text with links to the label specified. + # + # text - String text to replace references in. + # + # Returns a String with label references replaced with links. All links + # have `gfm` and `gfm-label` class names attached for styling. + def label_link_filter(text, link_text: nil) + project = context[:project] + + self.class.references_in(text) do |match, id, name| + params = label_params(id, name) + + if label = project.labels.find_by(params) + url = url_for_label(project, label) + klass = reference_class(:label) + data = data_attribute( + original: link_text || match, + project: project.id, + label: label.id + ) + + text = link_text || render_colored_label(label) + + %(#{text}) + else + match + end + end + end + + def url_for_label(project, label) + h = Gitlab::Application.routes.url_helpers + h.namespace_project_issues_url( project.namespace, project, label_name: label.name, + only_path: context[:only_path]) + end + + def render_colored_label(label) + LabelsHelper.render_colored_label(label) + end + + # Parameters to pass to `Label.find_by` based on the given arguments + # + # id - Integer ID to pass. If present, returns {id: id} + # name - String name to pass. If `id` is absent, finds by name without + # surrounding quotes. + # + # Returns a Hash. + def label_params(id, name) + if name + { name: name.tr('"', '') } + else + { id: id } + end + end + end + end +end diff --git a/lib/banzai/filter/markdown_filter.rb b/lib/banzai/filter/markdown_filter.rb new file mode 100644 index 00000000000..0072bab1f99 --- /dev/null +++ b/lib/banzai/filter/markdown_filter.rb @@ -0,0 +1,42 @@ +require 'banzai' +require 'html/pipeline/filter' + +module Banzai + module Filter + class MarkdownFilter < HTML::Pipeline::TextFilter + def initialize(text, context = nil, result = nil) + super text, context, result + @text = @text.gsub "\r", '' + end + + def call + html = self.class.renderer.render(@text) + html.rstrip! + html + end + + private + + def self.redcarpet_options + # https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use + @redcarpet_options ||= { + fenced_code_blocks: true, + footnotes: true, + lax_spacing: true, + no_intra_emphasis: true, + space_after_headers: true, + strikethrough: true, + superscript: true, + tables: true + }.freeze + end + + def self.renderer + @renderer ||= begin + renderer = Redcarpet::Render::HTML.new + Redcarpet::Markdown.new(renderer, redcarpet_options) + end + end + end + end +end diff --git a/lib/banzai/filter/merge_request_reference_filter.rb b/lib/banzai/filter/merge_request_reference_filter.rb new file mode 100644 index 00000000000..755b946a34b --- /dev/null +++ b/lib/banzai/filter/merge_request_reference_filter.rb @@ -0,0 +1,41 @@ +require 'banzai' + +module Banzai + module Filter + # HTML filter that replaces merge request references with links. References + # to merge requests that do not exist are ignored. + # + # This filter supports cross-project references. + class MergeRequestReferenceFilter < AbstractReferenceFilter + def self.object_class + MergeRequest + end + + def find_object(project, id) + project.merge_requests.find_by(iid: id) + end + + def url_for_object(mr, project) + h = Gitlab::Application.routes.url_helpers + h.namespace_project_merge_request_url(project.namespace, project, mr, + only_path: context[:only_path]) + end + + def object_link_text_extras(object, matches) + extras = super + + path = matches[:path] if matches.names.include?("path") + case path + when '/diffs' + extras.unshift "diffs" + when '/commits' + extras.unshift "commits" + when '/builds' + extras.unshift "builds" + end + + extras + end + end + end +end diff --git a/lib/banzai/filter/redactor_filter.rb b/lib/banzai/filter/redactor_filter.rb new file mode 100644 index 00000000000..89e7a79789a --- /dev/null +++ b/lib/banzai/filter/redactor_filter.rb @@ -0,0 +1,43 @@ +require 'banzai' +require 'html/pipeline/filter' + +module Banzai + module Filter + # HTML filter that removes references to records that the current user does + # not have permission to view. + # + # Expected to be run in its own post-processing pipeline. + # + class RedactorFilter < HTML::Pipeline::Filter + def call + doc.css('a.gfm').each do |node| + unless user_can_reference?(node) + # The reference should be replaced by the original text, + # which is not always the same as the rendered text. + text = node.attr('data-original') || node.text + node.replace(text) + end + end + + doc + end + + private + + def user_can_reference?(node) + if node.has_attribute?('data-reference-filter') + reference_type = node.attr('data-reference-filter') + reference_filter = Banzai::Filter.const_get(reference_type) + + reference_filter.user_can_reference?(current_user, node, context) + else + true + end + end + + def current_user + context[:current_user] + end + end + end +end diff --git a/lib/banzai/filter/reference_filter.rb b/lib/banzai/filter/reference_filter.rb new file mode 100644 index 00000000000..33457a3f361 --- /dev/null +++ b/lib/banzai/filter/reference_filter.rb @@ -0,0 +1,190 @@ +require 'active_support/core_ext/string/output_safety' +require 'banzai' +require 'html/pipeline/filter' + +module Banzai + module Filter + # Base class for GitLab Flavored Markdown reference filters. + # + # References within
    , , , and