summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJames Lopez <james@jameslopez.es>2016-03-21 09:20:55 +0100
committerJames Lopez <james@jameslopez.es>2016-03-21 09:20:55 +0100
commit5f86912ef032845ef2a08acf70b434c0e4d58631 (patch)
tree7b465b9d42c238c4a5978b4698a6ed71d1a7fcce /lib
parent735563329d1f86ee4d72b37cd22eed1168935e8e (diff)
parentb9fb48bc4597984710532e20f057920b0915d0c3 (diff)
downloadgitlab-ce-5f86912ef032845ef2a08acf70b434c0e4d58631.tar.gz
Merge branches 'fix/project-import_url' and 'master' of gitlab.com:gitlab-org/gitlab-ce into fix/project-import_url
# Conflicts: # db/schema.rb
Diffstat (limited to 'lib')
-rw-r--r--lib/api/commits.rb6
-rw-r--r--lib/api/entities.rb25
-rw-r--r--lib/api/issues.rb3
-rw-r--r--lib/api/projects.rb27
-rw-r--r--lib/api/users.rb8
-rw-r--r--lib/banzai.rb4
-rw-r--r--lib/banzai/filter/abstract_reference_filter.rb2
-rw-r--r--lib/banzai/filter/gollum_tags_filter.rb8
-rw-r--r--lib/banzai/filter/issue_reference_filter.rb5
-rw-r--r--lib/banzai/filter/label_reference_filter.rb79
-rw-r--r--lib/banzai/filter/sanitization_filter.rb9
-rw-r--r--lib/banzai/filter/yaml_front_matter_filter.rb28
-rw-r--r--lib/banzai/pipeline/pre_process_pipeline.rb17
-rw-r--r--lib/banzai/renderer.rb6
-rw-r--r--lib/ci/gitlab_ci_yaml_processor.rb29
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb2
-rw-r--r--lib/gitlab/compare_result.rb9
-rw-r--r--lib/gitlab/devise_failure.rb23
-rw-r--r--lib/gitlab/diff/file.rb6
-rw-r--r--lib/gitlab/diff/parser.rb81
-rw-r--r--lib/gitlab/email/message/repository_push.rb2
-rw-r--r--lib/gitlab/exclusive_lease.rb41
-rw-r--r--lib/gitlab/git_post_receive.rb60
-rw-r--r--lib/gitlab/github_import/importer.rb11
-rw-r--r--lib/gitlab/github_import/pull_request_formatter.rb10
-rw-r--r--lib/gitlab/middleware/go.rb50
-rw-r--r--lib/gitlab/project_search_results.rb11
-rw-r--r--lib/gitlab/push_data_builder.rb2
-rw-r--r--lib/gitlab/redis_config.rb30
-rw-r--r--lib/gitlab/search_results.rb28
-rw-r--r--lib/gitlab/snippet_search_results.rb10
-rw-r--r--lib/gitlab/user_access.rb2
-rw-r--r--lib/support/nginx/gitlab11
-rw-r--r--lib/support/nginx/gitlab-ssl10
-rw-r--r--lib/tasks/brakeman.rake2
-rw-r--r--lib/tasks/cache.rake6
-rw-r--r--lib/tasks/gemojione.rake122
-rw-r--r--lib/tasks/gitlab/check.rake2
-rw-r--r--lib/tasks/gitlab/web_hook.rake14
-rw-r--r--lib/tasks/scss-lint.rake10
-rw-r--r--lib/tasks/spec.rake13
-rw-r--r--lib/tasks/spinach.rake62
42 files changed, 671 insertions, 215 deletions
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index f4efb651eb6..4544a41b1e3 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -48,7 +48,7 @@ module API
sha = params[:sha]
commit = user_project.commit(sha)
not_found! "Commit" unless commit
- commit.diffs
+ commit.diffs.to_a
end
# Get a commit's comments
@@ -90,9 +90,9 @@ module API
}
if params[:path] && params[:line] && params[:line_type]
- commit.diffs.each do |diff|
+ commit.diffs(all_diffs: true).each do |diff|
next unless diff.new_path == params[:path]
- lines = Gitlab::Diff::Parser.new.parse(diff.diff.lines.to_a)
+ lines = Gitlab::Diff::Parser.new.parse(diff.diff.each_line)
lines.each do |line|
next unless line.new_pos == params[:line].to_i && line.type == params[:line_type]
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index a3b5f1eb8d3..71197205f34 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -23,12 +23,15 @@ module API
end
class UserFull < User
+ expose :last_sign_in_at
+ expose :confirmed_at
expose :email
expose :theme_id, :color_scheme_id, :projects_limit, :current_sign_in_at
expose :identities, using: Entities::Identity
expose :can_create_group?, as: :can_create_group
expose :can_create_project?, as: :can_create_project
expose :two_factor_enabled
+ expose :external
end
class UserLogin < UserFull
@@ -141,7 +144,10 @@ module API
class ProjectSnippet < Grape::Entity
expose :id, :title, :file_name
expose :author, using: Entities::UserBasic
- expose :expires_at, :updated_at, :created_at
+ expose :updated_at, :created_at
+
+ # TODO (rspeicher): Deprecated; remove in 9.0
+ expose(:expires_at) { |snippet| nil }
end
class ProjectEntity < Grape::Entity
@@ -181,7 +187,7 @@ module API
class MergeRequestChanges < MergeRequest
expose :diffs, as: :changes, using: Entities::RepoDiff do |compare, _|
- compare.diffs
+ compare.diffs(all_diffs: true).to_a
end
end
@@ -241,6 +247,10 @@ module API
end
end
+ class ProjectGroupLink < Grape::Entity
+ expose :id, :project_id, :group_id, :group_access
+ end
+
class Namespace < Grape::Entity
expose :id, :path, :kind
end
@@ -295,11 +305,11 @@ module API
end
expose :diffs, using: Entities::RepoDiff do |compare, options|
- compare.diffs
+ compare.diffs(all_diffs: true).to_a
end
expose :compare_timeout do |compare, options|
- compare.timeout
+ compare.diffs.overflow?
end
expose :same, as: :compare_same_ref
@@ -399,13 +409,6 @@ module API
expose :id, :status, :stage, :name, :ref, :tag, :coverage
expose :created_at, :started_at, :finished_at
expose :user, with: User
- # TODO: download_url in Ci:Build model is an GitLab Web Interface URL, not API URL. We should think on some API
- # for downloading of artifacts (see: https://gitlab.com/gitlab-org/gitlab-ce/issues/4255)
- expose :download_url do |repo_obj, options|
- if options[:user_can_download_artifacts]
- repo_obj.artifacts_download_url
- end
- end
expose :artifacts_file, using: BuildArtifactFile, if: -> (build, opts) { build.artifacts? }
expose :commit, with: RepoCommit do |repo_obj, _options|
if repo_obj.respond_to?(:commit)
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 252744515da..fda6f841438 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -82,7 +82,7 @@ module API
# GET /projects/:id/issues?milestone=1.0.0&state=closed
# GET /issues?iid=42
get ":id/issues" do
- issues = user_project.issues
+ issues = user_project.issues.visible_to_user(current_user)
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues = filter_by_iid(issues, params[:iid]) unless params[:iid].nil?
@@ -104,6 +104,7 @@ module API
# GET /projects/:id/issues/:issue_id
get ":id/issues/:issue_id" do
@issue = user_project.issues.find(params[:issue_id])
+ not_found! unless can?(current_user, :read_issue, @issue)
present @issue, with: Entities::Issue
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 6067c8b4a5e..6fcb5261e40 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -290,6 +290,33 @@ module API
end
end
+ # Share project with group
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # group_id (required) - The ID of a group
+ # group_access (required) - Level of permissions for sharing
+ #
+ # Example Request:
+ # POST /projects/:id/share
+ post ":id/share" do
+ authorize! :admin_project, user_project
+ required_attributes! [:group_id, :group_access]
+
+ unless user_project.allowed_to_share_with_group?
+ return render_api_error!("The project sharing with group is disabled", 400)
+ end
+
+ link = user_project.project_group_links.new
+ link.group_id = params[:group_id]
+ link.group_access = params[:group_access]
+ if link.save
+ present link, with: Entities::ProjectGroupLink
+ else
+ render_api_error!(link.errors.full_messages.first, 409)
+ end
+ end
+
# Upload a file
#
# Parameters:
diff --git a/lib/api/users.rb b/lib/api/users.rb
index fd2128bd179..13ab17c6904 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -61,19 +61,20 @@ module API
# admin - User is admin - true or false (default)
# can_create_group - User can create groups - true or false
# confirm - Require user confirmation - true (default) or false
+ # external - Flags the user as external - true or false(default)
# Example Request:
# POST /users
post do
authenticated_as_admin!
required_attributes! [:email, :password, :name, :username]
- attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :bio, :can_create_group, :admin, :confirm]
+ attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :bio, :can_create_group, :admin, :confirm, :external]
admin = attrs.delete(:admin)
confirm = !(attrs.delete(:confirm) =~ (/(false|f|no|0)$/i))
user = User.build_user(attrs)
user.admin = admin unless admin.nil?
user.skip_confirmation! unless confirm
-
identity_attrs = attributes_for_keys [:provider, :extern_uid]
+
if identity_attrs.any?
user.identities.build(identity_attrs)
end
@@ -107,12 +108,13 @@ module API
# bio - Bio
# admin - User is admin - true or false (default)
# can_create_group - User can create groups - true or false
+ # external - Flags the user as external - true or false(default)
# Example Request:
# PUT /users/:id
put ":id" do
authenticated_as_admin!
- attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :website_url, :projects_limit, :username, :bio, :can_create_group, :admin]
+ attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :website_url, :projects_limit, :username, :bio, :can_create_group, :admin, :external]
user = User.find(params[:id])
not_found!('User') unless user
diff --git a/lib/banzai.rb b/lib/banzai.rb
index 093382261ae..b467413a7dd 100644
--- a/lib/banzai.rb
+++ b/lib/banzai.rb
@@ -7,6 +7,10 @@ module Banzai
Renderer.render_result(text, context)
end
+ def self.pre_process(text, context)
+ Renderer.pre_process(text, context)
+ end
+
def self.post_process(html, context)
Renderer.post_process(html, context)
end
diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb
index cdbaecf8d90..34c38913474 100644
--- a/lib/banzai/filter/abstract_reference_filter.rb
+++ b/lib/banzai/filter/abstract_reference_filter.rb
@@ -94,6 +94,8 @@ module Banzai
object_link_filter(link, object_class.link_reference_pattern, link_text: text)
end
end
+
+ doc
end
# Replace references (like `!123` for merge requests) in text with links
diff --git a/lib/banzai/filter/gollum_tags_filter.rb b/lib/banzai/filter/gollum_tags_filter.rb
index bcf5297e382..f31f921903b 100644
--- a/lib/banzai/filter/gollum_tags_filter.rb
+++ b/lib/banzai/filter/gollum_tags_filter.rb
@@ -26,6 +26,10 @@ module Banzai
# * [[http://example.com/images/logo.png]]
# * [[http://example.com/images/logo.png|alt=Logo]]
#
+ # - Insert a Table of Contents list:
+ #
+ # * [[_TOC_]]
+ #
# Based on Gollum::Filter::Tags
#
# Context options:
@@ -61,8 +65,6 @@ module Banzai
# before this one, it will be converted into `[[<em>TOC</em>]]`, so it
# needs special-case handling
if toc_tag?(node)
- next unless result[:toc].present?
-
process_toc_tag(node)
else
content = node.content
@@ -85,7 +87,7 @@ module Banzai
# Replace an entire `[[<em>TOC</em>]]` node with the result generated by
# TableOfContentsFilter
def process_toc_tag(node)
- node.parent.parent.replace(result[:toc])
+ node.parent.parent.replace(result[:toc].presence || '')
end
# Process a single tag into its final HTML form.
diff --git a/lib/banzai/filter/issue_reference_filter.rb b/lib/banzai/filter/issue_reference_filter.rb
index 9f08aa36e8b..2732e0b5145 100644
--- a/lib/banzai/filter/issue_reference_filter.rb
+++ b/lib/banzai/filter/issue_reference_filter.rb
@@ -9,6 +9,11 @@ module Banzai
Issue
end
+ def self.user_can_see_reference?(user, node, context)
+ issue = Issue.find(node.attr('data-issue')) rescue nil
+ Ability.abilities.allowed?(user, :read_issue, issue)
+ end
+
def find_object(project, id)
project.get_issue(id)
end
diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb
index 95e7d209119..8147e5ed3c7 100644
--- a/lib/banzai/filter/label_reference_filter.rb
+++ b/lib/banzai/filter/label_reference_filter.rb
@@ -1,78 +1,47 @@
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|
- # "<a href=...>#{Label.find(id)}</a>"
- # 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
+ class LabelReferenceFilter < AbstractReferenceFilter
+ def self.object_class
+ Label
end
- def self.referenced_by(node)
- { label: LazyReference.new(Label, node.attr("data-label")) }
+ def find_object(project, id)
+ project.labels.find(id)
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)
+ def self.references_in(text, pattern = Label.reference_pattern)
+ text.gsub(pattern) do |match|
+ yield match, $~[:label_id].to_i, $~[:label_name], $~[:project], $~
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
- )
+ def references_in(text, pattern = Label.reference_pattern)
+ text.gsub(pattern) do |match|
+ project = project_from_ref($~[:project])
+ params = label_params($~[:label_id].to_i, $~[:label_name])
+ label = project.labels.find_by(params)
- text = link_text || render_colored_label(label)
-
- %(<a href="#{url}" #{data}
- class="#{klass}">#{escape_once(text)}</a>)
+ if label
+ yield match, label.id, $~[:project], $~
else
match
end
end
end
- def url_for_label(project, label)
+ def url_for_object(label, project)
h = Gitlab::Application.routes.url_helpers
- h.namespace_project_issues_url( project.namespace, project, label_name: label.name,
- only_path: context[:only_path])
+ 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)
+ def object_link_text(object, matches)
+ if context[:project] == object.project
+ LabelsHelper.render_colored_label(object)
+ else
+ LabelsHelper.render_colored_cross_project_label(object)
+ end
end
# Parameters to pass to `Label.find_by` based on the given arguments
diff --git a/lib/banzai/filter/sanitization_filter.rb b/lib/banzai/filter/sanitization_filter.rb
index abd79b329ae..e8011519608 100644
--- a/lib/banzai/filter/sanitization_filter.rb
+++ b/lib/banzai/filter/sanitization_filter.rb
@@ -7,7 +7,7 @@ module Banzai
#
# Extends HTML::Pipeline::SanitizationFilter with a custom whitelist.
class SanitizationFilter < HTML::Pipeline::SanitizationFilter
- UNSAFE_PROTOCOLS = %w(javascript :javascript data vbscript).freeze
+ UNSAFE_PROTOCOLS = %w(data javascript vbscript).freeze
def whitelist
whitelist = super
@@ -64,7 +64,12 @@ module Banzai
return unless node.name == 'a'
return unless node.has_attribute?('href')
- if node['href'].start_with?(*UNSAFE_PROTOCOLS)
+ begin
+ uri = Addressable::URI.parse(node['href'])
+ uri.scheme.strip! if uri.scheme
+
+ node.remove_attribute('href') if UNSAFE_PROTOCOLS.include?(uri.scheme)
+ rescue Addressable::URI::InvalidURIError
node.remove_attribute('href')
end
end
diff --git a/lib/banzai/filter/yaml_front_matter_filter.rb b/lib/banzai/filter/yaml_front_matter_filter.rb
new file mode 100644
index 00000000000..e4e2f3f228d
--- /dev/null
+++ b/lib/banzai/filter/yaml_front_matter_filter.rb
@@ -0,0 +1,28 @@
+require 'html/pipeline/filter'
+require 'yaml'
+
+module Banzai
+ module Filter
+ class YamlFrontMatterFilter < HTML::Pipeline::Filter
+ DELIM = '---'.freeze
+
+ # Hat-tip to Middleman: https://git.io/v2e0z
+ PATTERN = %r{
+ \A(?:[^\r\n]*coding:[^\r\n]*\r?\n)?
+ (?<start>#{DELIM})[ ]*\r?\n
+ (?<frontmatter>.*?)[ ]*\r?\n?
+ ^(?<stop>#{DELIM})[ ]*\r?\n?
+ \r?\n?
+ (?<content>.*)
+ }mx.freeze
+
+ def call
+ match = PATTERN.match(html)
+
+ return html unless match
+
+ "```yaml\n#{match['frontmatter']}\n```\n\n#{match['content']}"
+ end
+ end
+ end
+end
diff --git a/lib/banzai/pipeline/pre_process_pipeline.rb b/lib/banzai/pipeline/pre_process_pipeline.rb
new file mode 100644
index 00000000000..50dc978b452
--- /dev/null
+++ b/lib/banzai/pipeline/pre_process_pipeline.rb
@@ -0,0 +1,17 @@
+module Banzai
+ module Pipeline
+ class PreProcessPipeline < BasePipeline
+ def self.filters
+ FilterArray[
+ Filter::YamlFrontMatterFilter
+ ]
+ end
+
+ def self.transform_context(context)
+ context.merge(
+ pre_process: true
+ )
+ end
+ end
+ end
+end
diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb
index 891c0fd7749..ae714c87dc5 100644
--- a/lib/banzai/renderer.rb
+++ b/lib/banzai/renderer.rb
@@ -31,6 +31,12 @@ module Banzai
Pipeline[context[:pipeline]].call(text, context)
end
+ def self.pre_process(text, context)
+ pipeline = Pipeline[:pre_process]
+
+ pipeline.to_html(text, context)
+ end
+
# Perform post-processing on an HTML String
#
# This method is used to perform state-dependent changes to a String of
diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb
index 1a3f662811a..c89e1b51019 100644
--- a/lib/ci/gitlab_ci_yaml_processor.rb
+++ b/lib/ci/gitlab_ci_yaml_processor.rb
@@ -5,12 +5,14 @@ module Ci
DEFAULT_STAGES = %w(build test deploy)
DEFAULT_STAGE = 'test'
ALLOWED_YAML_KEYS = [:before_script, :image, :services, :types, :stages, :variables, :cache]
- ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services, :allow_failure, :type, :stage, :when, :artifacts, :cache]
+ ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services,
+ :allow_failure, :type, :stage, :when, :artifacts, :cache,
+ :dependencies]
attr_reader :before_script, :image, :services, :variables, :path, :cache
def initialize(config, path = nil)
- @config = YAML.safe_load(config, [Symbol])
+ @config = YAML.safe_load(config, [Symbol], [], true)
@path = path
unless @config.is_a? Hash
@@ -60,6 +62,7 @@ module Ci
@jobs = {}
@config.each do |key, job|
+ next if key.to_s.start_with?('.')
stage = job[:stage] || job[:type] || DEFAULT_STAGE
@jobs[key] = { stage: stage }.merge(job)
end
@@ -81,6 +84,7 @@ module Ci
services: job[:services] || @services,
artifacts: job[:artifacts],
cache: job[:cache] || @cache,
+ dependencies: job[:dependencies],
}.compact
}
end
@@ -143,6 +147,7 @@ module Ci
validate_job_stage!(name, job) if job[:stage]
validate_job_cache!(name, job) if job[:cache]
validate_job_artifacts!(name, job) if job[:artifacts]
+ validate_job_dependencies!(name, job) if job[:dependencies]
end
private
@@ -216,6 +221,10 @@ module Ci
end
def validate_job_artifacts!(name, job)
+ if job[:artifacts][:name] && !validate_string(job[:artifacts][:name])
+ raise ValidationError, "#{name} job: artifacts:name parameter should be a string"
+ end
+
if job[:artifacts][:untracked] && !validate_boolean(job[:artifacts][:untracked])
raise ValidationError, "#{name} job: artifacts:untracked parameter should be an boolean"
end
@@ -225,6 +234,22 @@ module Ci
end
end
+ def validate_job_dependencies!(name, job)
+ if !validate_array_of_strings(job[:dependencies])
+ raise ValidationError, "#{name} job: dependencies parameter should be an array of strings"
+ end
+
+ stage_index = stages.index(job[:stage])
+
+ job[:dependencies].each do |dependency|
+ raise ValidationError, "#{name} job: undefined dependency: #{dependency}" unless @jobs[dependency]
+
+ unless stages.index(@jobs[dependency][:stage]) < stage_index
+ raise ValidationError, "#{name} job: dependency #{dependency} is not defined in prior stages"
+ end
+ end
+ end
+
def validate_array_of_strings(values)
values.is_a?(Array) && values.all? { |value| validate_string(value) }
end
diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb
index 3f483847efa..46e51a4bf6d 100644
--- a/lib/gitlab/bitbucket_import/importer.rb
+++ b/lib/gitlab/bitbucket_import/importer.rb
@@ -76,7 +76,7 @@ module Gitlab
project.issues.create!(
description: body,
title: issue["title"],
- state: %w(resolved invalid duplicate wontfix).include?(issue["status"]) ? 'closed' : 'opened',
+ state: %w(resolved invalid duplicate wontfix closed).include?(issue["status"]) ? 'closed' : 'opened',
author_id: gl_user_id(project, reporter)
)
end
diff --git a/lib/gitlab/compare_result.rb b/lib/gitlab/compare_result.rb
deleted file mode 100644
index 0d696a1ee28..00000000000
--- a/lib/gitlab/compare_result.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-module Gitlab
- class CompareResult
- attr_reader :commits, :diffs
-
- def initialize(compare, diff_options = {})
- @commits, @diffs = compare.commits, compare.diffs(nil, diff_options)
- end
- end
-end
diff --git a/lib/gitlab/devise_failure.rb b/lib/gitlab/devise_failure.rb
new file mode 100644
index 00000000000..a78fde9d782
--- /dev/null
+++ b/lib/gitlab/devise_failure.rb
@@ -0,0 +1,23 @@
+module Gitlab
+ class DeviseFailure < Devise::FailureApp
+ protected
+
+ # Override `Devise::FailureApp#request_format` to handle a special case
+ #
+ # This tells Devise to handle an unauthenticated `.zip` request as an HTML
+ # request (i.e., redirect to sign in).
+ #
+ # Otherwise, Devise would respond with a 401 Unauthorized with
+ # `Content-Type: application/zip` and a response body in plaintext, and the
+ # browser would freak out.
+ #
+ # See https://gitlab.com/gitlab-org/gitlab-ce/issues/12944
+ def request_format
+ if request.format == :zip
+ Mime::Type.lookup_by_extension(:html).ref
+ else
+ super
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index a484177ae33..d2e85cabf72 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -21,7 +21,11 @@ module Gitlab
# Array of Gitlab::DIff::Line objects
def diff_lines
- @lines ||= parser.parse(raw_diff.lines)
+ @lines ||= parser.parse(raw_diff.each_line).to_a
+ end
+
+ def too_large?
+ diff.too_large?
end
def highlighted_diff_lines
diff --git a/lib/gitlab/diff/parser.rb b/lib/gitlab/diff/parser.rb
index 3666063bf8b..d0815fc7eea 100644
--- a/lib/gitlab/diff/parser.rb
+++ b/lib/gitlab/diff/parser.rb
@@ -4,53 +4,56 @@ module Gitlab
include Enumerable
def parse(lines)
+ return [] if lines.blank?
+
@lines = lines
- lines_obj = []
line_obj_index = 0
line_old = 1
line_new = 1
type = nil
- @lines.each do |line|
- next if filename?(line)
-
- full_line = line.gsub(/\n/, '')
-
- if line.match(/^@@ -/)
- type = "match"
-
- line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
- line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
-
- next if line_old <= 1 && line_new <= 1 #top of file
- lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
- line_obj_index += 1
- next
- elsif line[0] == '\\'
- type = 'nonewline'
- lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
- line_obj_index += 1
- else
- type = identification_type(line)
- lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
- line_obj_index += 1
- end
-
-
- case line[0]
- when "+"
- line_new += 1
- when "-"
- line_old += 1
- when "\\"
- # No increment
- else
- line_new += 1
- line_old += 1
+ # By returning an Enumerator we make it possible to search for a single line (with #find)
+ # without having to instantiate all the others that come after it.
+ Enumerator.new do |yielder|
+ @lines.each do |line|
+ next if filename?(line)
+
+ full_line = line.gsub(/\n/, '')
+
+ if line.match(/^@@ -/)
+ type = "match"
+
+ line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
+ line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
+
+ next if line_old <= 1 && line_new <= 1 #top of file
+ yielder << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
+ line_obj_index += 1
+ next
+ elsif line[0] == '\\'
+ type = 'nonewline'
+ yielder << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
+ line_obj_index += 1
+ else
+ type = identification_type(line)
+ yielder << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
+ line_obj_index += 1
+ end
+
+
+ case line[0]
+ when "+"
+ line_new += 1
+ when "-"
+ line_old += 1
+ when "\\"
+ # No increment
+ else
+ line_new += 1
+ line_old += 1
+ end
end
end
-
- lines_obj
end
def empty?
diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb
index a05ffeb9cd2..41f0edcaf7e 100644
--- a/lib/gitlab/email/message/repository_push.rb
+++ b/lib/gitlab/email/message/repository_push.rb
@@ -50,7 +50,7 @@ module Gitlab
end
def compare_timeout
- compare.timeout if compare
+ diffs.overflow? if diffs
end
def reverse_compare?
diff --git a/lib/gitlab/exclusive_lease.rb b/lib/gitlab/exclusive_lease.rb
new file mode 100644
index 00000000000..2ef50286b1d
--- /dev/null
+++ b/lib/gitlab/exclusive_lease.rb
@@ -0,0 +1,41 @@
+module Gitlab
+ # This class implements an 'exclusive lease'. We call it a 'lease'
+ # because it has a set expiry time. We call it 'exclusive' because only
+ # one caller may obtain a lease for a given key at a time. The
+ # implementation is intended to work across GitLab processes and across
+ # servers. It is a 'cheap' alternative to using SQL queries and updates:
+ # you do not need to change the SQL schema to start using
+ # ExclusiveLease.
+ #
+ # It is important to choose the timeout wisely. If the timeout is very
+ # high (1 hour) then the throughput of your operation gets very low (at
+ # most once an hour). If the timeout is lower than how long your
+ # operation may take then you cannot count on exclusivity. For example,
+ # if the timeout is 10 seconds and you do an operation which may take 20
+ # seconds then two overlapping operations may hold a lease for the same
+ # key at the same time.
+ #
+ class ExclusiveLease
+ def initialize(key, timeout:)
+ @key, @timeout = key, timeout
+ end
+
+ # Try to obtain the lease. Return true on success,
+ # false if the lease is already taken.
+ def try_obtain
+ # Performing a single SET is atomic
+ !!redis.set(redis_key, '1', nx: true, ex: @timeout)
+ end
+
+ private
+
+ def redis
+ # Maybe someday we want to use a connection pool...
+ @redis ||= Redis.new(url: Gitlab::RedisConfig.url)
+ end
+
+ def redis_key
+ "gitlab:exclusive_lease:#{@key}"
+ end
+ end
+end
diff --git a/lib/gitlab/git_post_receive.rb b/lib/gitlab/git_post_receive.rb
new file mode 100644
index 00000000000..a088e19d1e7
--- /dev/null
+++ b/lib/gitlab/git_post_receive.rb
@@ -0,0 +1,60 @@
+module Gitlab
+ class GitPostReceive
+ include Gitlab::Identifier
+ attr_reader :repo_path, :identifier, :changes, :project
+
+ def initialize(repo_path, identifier, changes)
+ repo_path.gsub!(/\.git\z/, '')
+ repo_path.gsub!(/\A\//, '')
+
+ @repo_path = repo_path
+ @identifier = identifier
+ @changes = deserialize_changes(changes)
+
+ retrieve_project_and_type
+ end
+
+ def wiki?
+ @type == :wiki
+ end
+
+ def regular_project?
+ @type == :project
+ end
+
+ def identify(revision)
+ super(identifier, project, revision)
+ end
+
+ private
+
+ def retrieve_project_and_type
+ @type = :project
+ @project = Project.find_with_namespace(@repo_path)
+
+ if @repo_path.end_with?('.wiki') && !@project
+ @type = :wiki
+ @project = Project.find_with_namespace(@repo_path.gsub(/\.wiki\z/, ''))
+ end
+ end
+
+ def deserialize_changes(changes)
+ changes = Base64.decode64(changes) unless changes.include?(' ')
+ changes = utf8_encode_changes(changes)
+ changes.lines
+ end
+
+ def utf8_encode_changes(changes)
+ changes = changes.dup
+
+ changes.force_encoding('UTF-8')
+ return changes if changes.valid_encoding?
+
+ # Convert non-UTF-8 branch/tag names to UTF-8 so they can be dumped as JSON.
+ detection = CharlockHolmes::EncodingDetector.detect(changes)
+ return changes unless detection && detection[:encoding]
+
+ CharlockHolmes::Converter.convert(changes, detection[:encoding], 'UTF-8')
+ end
+ end
+end
diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb
index d478d3b5398..a96cfa8af9d 100644
--- a/lib/gitlab/github_import/importer.rb
+++ b/lib/gitlab/github_import/importer.rb
@@ -44,10 +44,13 @@ module Gitlab
direction: :asc).each do |raw_data|
pull_request = PullRequestFormatter.new(project, raw_data)
- if !pull_request.cross_project? && pull_request.valid?
- merge_request = MergeRequest.create!(pull_request.attributes)
- import_comments(pull_request.number, merge_request)
- import_comments_on_diff(pull_request.number, merge_request)
+ if pull_request.valid?
+ merge_request = MergeRequest.new(pull_request.attributes)
+
+ if merge_request.save
+ import_comments(pull_request.number, merge_request)
+ import_comments_on_diff(pull_request.number, merge_request)
+ end
end
end
diff --git a/lib/gitlab/github_import/pull_request_formatter.rb b/lib/gitlab/github_import/pull_request_formatter.rb
index f96fed0f5cf..4e507b090e8 100644
--- a/lib/gitlab/github_import/pull_request_formatter.rb
+++ b/lib/gitlab/github_import/pull_request_formatter.rb
@@ -17,16 +17,12 @@ module Gitlab
}
end
- def cross_project?
- source_repo.id != target_repo.id
- end
-
def number
raw_data.number
end
def valid?
- source_branch.present? && target_branch.present?
+ !cross_project? && source_branch.present? && target_branch.present?
end
private
@@ -53,6 +49,10 @@ module Gitlab
raw_data.body || ""
end
+ def cross_project?
+ source_repo.present? && target_repo.present? && source_repo.id != target_repo.id
+ end
+
def description
formatter.author_line(author) + body
end
diff --git a/lib/gitlab/middleware/go.rb b/lib/gitlab/middleware/go.rb
new file mode 100644
index 00000000000..50b0dd32380
--- /dev/null
+++ b/lib/gitlab/middleware/go.rb
@@ -0,0 +1,50 @@
+# A dumb middleware that returns a Go HTML document if the go-get=1 query string
+# is used irrespective if the namespace/project exists
+module Gitlab
+ module Middleware
+ class Go
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ request = Rack::Request.new(env)
+
+ if go_request?(request)
+ render_go_doc(request)
+ else
+ @app.call(env)
+ end
+ end
+
+ private
+
+ def render_go_doc(request)
+ body = go_body(request)
+ response = Rack::Response.new(body, 200, { 'Content-Type' => 'text/html' })
+ response.finish
+ end
+
+ def go_request?(request)
+ request["go-get"].to_i == 1 && request.env["PATH_INFO"].present?
+ end
+
+ def go_body(request)
+ base_url = Gitlab.config.gitlab.url
+ # Go subpackages may be in the form of namespace/project/path1/path2/../pathN
+ # We can just ignore the paths and leave the namespace/project
+ path_info = request.env["PATH_INFO"]
+ path_info.sub!(/^\//, '')
+ project_path = path_info.split('/').first(2).join('/')
+ request_url = URI.join(base_url, project_path)
+ domain_path = strip_url(request_url.to_s)
+
+ "<!DOCTYPE html><html><head><meta content='#{domain_path} git #{request_url}.git' name='go-import'></head></html>\n";
+ end
+
+ def strip_url(url)
+ url.gsub(/\Ahttps?:\/\//, '')
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
index 70de6a74e76..71c5b6801fb 100644
--- a/lib/gitlab/project_search_results.rb
+++ b/lib/gitlab/project_search_results.rb
@@ -2,8 +2,9 @@ module Gitlab
class ProjectSearchResults < SearchResults
attr_reader :project, :repository_ref
- def initialize(project_id, query, repository_ref = nil)
- @project = Project.find(project_id)
+ def initialize(current_user, project, query, repository_ref = nil)
+ @current_user = current_user
+ @project = project
@repository_ref = if repository_ref.present?
repository_ref
else
@@ -73,7 +74,7 @@ module Gitlab
end
def notes
- Note.where(project_id: limit_project_ids).user.search(query).order('updated_at DESC')
+ project.notes.user.search(query).order('updated_at DESC')
end
def commits
@@ -84,8 +85,8 @@ module Gitlab
end
end
- def limit_project_ids
- [project.id]
+ def project_ids_relation
+ project
end
end
end
diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb
index da1c15fef61..97d1edab9c1 100644
--- a/lib/gitlab/push_data_builder.rb
+++ b/lib/gitlab/push_data_builder.rb
@@ -63,7 +63,7 @@ module Gitlab
end
# This method provide a sample data generated with
- # existing project and commits to test web hooks
+ # existing project and commits to test webhooks
def build_sample(project, user)
commits = project.repository.commits(project.default_branch, nil, 3)
ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{project.default_branch}"
diff --git a/lib/gitlab/redis_config.rb b/lib/gitlab/redis_config.rb
new file mode 100644
index 00000000000..4949c6db539
--- /dev/null
+++ b/lib/gitlab/redis_config.rb
@@ -0,0 +1,30 @@
+module Gitlab
+ class RedisConfig
+ attr_reader :url
+
+ def self.url
+ new.url
+ end
+
+ def self.redis_store_options
+ url = new.url
+ redis_config_hash = Redis::Store::Factory.extract_host_options_from_uri(url)
+ # Redis::Store does not handle Unix sockets well, so let's do it for them
+ redis_uri = URI.parse(url)
+ if redis_uri.scheme == 'unix'
+ redis_config_hash[:path] = redis_uri.path
+ end
+ redis_config_hash
+ end
+
+ def initialize(rails_env=nil)
+ rails_env ||= Rails.env
+ config_file = File.expand_path('../../../config/resque.yml', __FILE__)
+
+ @url = "redis://localhost:6379"
+ if File.exists?(config_file)
+ @url =YAML.load_file(config_file)[rails_env]
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb
index 2ab2d4af797..f8ab2b1f09e 100644
--- a/lib/gitlab/search_results.rb
+++ b/lib/gitlab/search_results.rb
@@ -1,13 +1,14 @@
module Gitlab
class SearchResults
- attr_reader :query
+ attr_reader :current_user, :query
- # Limit search results by passed project ids
+ # Limit search results by passed projects
# It allows us to search only for projects user has access to
- attr_reader :limit_project_ids
+ attr_reader :limit_projects
- def initialize(limit_project_ids, query)
- @limit_project_ids = limit_project_ids || Project.all
+ def initialize(current_user, limit_projects, query)
+ @current_user = current_user
+ @limit_projects = limit_projects || Project.all
@query = Shellwords.shellescape(query) if query.present?
end
@@ -27,7 +28,8 @@ module Gitlab
end
def total_count
- @total_count ||= projects_count + issues_count + merge_requests_count + milestones_count
+ @total_count ||= projects_count + issues_count + merge_requests_count +
+ milestones_count
end
def projects_count
@@ -53,27 +55,29 @@ module Gitlab
private
def projects
- Project.where(id: limit_project_ids).search(query)
+ limit_projects.search(query)
end
def issues
- issues = Issue.where(project_id: limit_project_ids)
+ issues = Issue.visible_to_user(current_user).where(project_id: project_ids_relation)
+
if query =~ /#(\d+)\z/
issues = issues.where(iid: $1)
else
issues = issues.full_search(query)
end
+
issues.order('updated_at DESC')
end
def milestones
- milestones = Milestone.where(project_id: limit_project_ids)
+ milestones = Milestone.where(project_id: project_ids_relation)
milestones = milestones.search(query)
milestones.order('updated_at DESC')
end
def merge_requests
- merge_requests = MergeRequest.in_projects(limit_project_ids)
+ merge_requests = MergeRequest.in_projects(project_ids_relation)
if query =~ /[#!](\d+)\z/
merge_requests = merge_requests.where(iid: $1)
else
@@ -89,5 +93,9 @@ module Gitlab
def per_page
20
end
+
+ def project_ids_relation
+ limit_projects.select(:id).reorder(nil)
+ end
end
end
diff --git a/lib/gitlab/snippet_search_results.rb b/lib/gitlab/snippet_search_results.rb
index addda95be2b..e0e74ff8359 100644
--- a/lib/gitlab/snippet_search_results.rb
+++ b/lib/gitlab/snippet_search_results.rb
@@ -2,10 +2,10 @@ module Gitlab
class SnippetSearchResults < SearchResults
include SnippetsHelper
- attr_reader :limit_snippet_ids
+ attr_reader :limit_snippets
- def initialize(limit_snippet_ids, query)
- @limit_snippet_ids = limit_snippet_ids
+ def initialize(limit_snippets, query)
+ @limit_snippets = limit_snippets
@query = query
end
@@ -35,11 +35,11 @@ module Gitlab
private
def snippet_titles
- Snippet.where(id: limit_snippet_ids).search(query).order('updated_at DESC')
+ limit_snippets.search(query).order('updated_at DESC')
end
def snippet_blobs
- Snippet.where(id: limit_snippet_ids).search_code(query).order('updated_at DESC')
+ limit_snippets.search_code(query).order('updated_at DESC')
end
def default_scope
diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb
index 4885baf9526..d1b42c1f9b9 100644
--- a/lib/gitlab/user_access.rb
+++ b/lib/gitlab/user_access.rb
@@ -3,7 +3,7 @@ module Gitlab
def self.allowed?(user)
return false if user.blocked?
- if user.requires_ldap_check?
+ if user.requires_ldap_check? && user.try_obtain_ldap_lease
return false unless Gitlab::LDAP::Access.allowed?(user)
end
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index fc5475c4eef..1324e4cd267 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -30,7 +30,6 @@ server {
listen [::]:80 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
- root /home/git/gitlab/public;
## See app/controllers/application_controller.rb for headers set
@@ -57,4 +56,14 @@ server {
proxy_pass http://gitlab-workhorse;
}
+
+ error_page 404 /404.html;
+ error_page 422 /422.html;
+ error_page 500 /500.html;
+ error_page 502 /502.html;
+ location ~ ^/(404|422|500|502)\.html$ {
+ root /home/git/gitlab/public;
+ internal;
+ }
+
}
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 1e5f85413ec..af6ea9ed706 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -45,7 +45,6 @@ server {
listen [::]:443 ipv6only=on ssl 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
- root /home/git/gitlab/public;
## Strong SSL Security
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
@@ -101,4 +100,13 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://gitlab-workhorse;
}
+
+ error_page 404 /404.html;
+ error_page 422 /422.html;
+ error_page 500 /500.html;
+ error_page 502 /502.html;
+ location ~ ^/(404|422|500|502)\.html$ {
+ root /home/git/gitlab/public;
+ internal;
+ }
}
diff --git a/lib/tasks/brakeman.rake b/lib/tasks/brakeman.rake
index 5d4e0740373..d5a402907d8 100644
--- a/lib/tasks/brakeman.rake
+++ b/lib/tasks/brakeman.rake
@@ -2,7 +2,7 @@ desc 'Security check via brakeman'
task :brakeman do
# We get 0 warnings at level 'w3' but we would like to reach 'w2'. Merge
# requests are welcome!
- if system(*%W(brakeman --skip-files lib/backup/repository.rb -w3 -z))
+ if system(*%W(brakeman --no-progress --skip-files lib/backup/repository.rb -w3 -z))
puts 'Security check succeed'
else
puts 'Security check failed'
diff --git a/lib/tasks/cache.rake b/lib/tasks/cache.rake
index f221afcf73a..51e746ef923 100644
--- a/lib/tasks/cache.rake
+++ b/lib/tasks/cache.rake
@@ -4,16 +4,16 @@ namespace :cache do
desc "GitLab | Clear redis cache"
task :clear => :environment do
- redis_store = Rails.cache.instance_variable_get(:@data)
+ redis = Redis.new(url: Gitlab::RedisConfig.url)
cursor = REDIS_SCAN_START_STOP
loop do
- cursor, keys = redis_store.scan(
+ cursor, keys = redis.scan(
cursor,
match: "#{Gitlab::REDIS_CACHE_NAMESPACE}*",
count: CLEAR_BATCH_SIZE
)
- redis_store.del(*keys) if keys.any?
+ redis.del(*keys) if keys.any?
break if cursor == REDIS_SCAN_START_STOP
end
diff --git a/lib/tasks/gemojione.rake b/lib/tasks/gemojione.rake
new file mode 100644
index 00000000000..cfaf4a129b1
--- /dev/null
+++ b/lib/tasks/gemojione.rake
@@ -0,0 +1,122 @@
+# This task will generate a standard and Retina sprite of all of the current
+# Gemojione Emojis, with the accompanying SCSS map.
+#
+# It will not appear in `rake -T` output, and the dependent gems are not
+# included in the Gemfile by default, because this task will only be needed
+# occasionally, such as when new Emojis are added to Gemojione.
+
+begin
+ require 'sprite_factory'
+ require 'rmagick'
+rescue LoadError
+ # noop
+end
+
+namespace :gemojione do
+ task sprite: :environment do
+ check_requirements!
+
+ SIZE = 20
+ RETINA = SIZE * 2
+
+ Dir.mktmpdir do |tmpdir|
+ # Copy the Gemojione assets to the temporary folder for resizing
+ FileUtils.cp_r(Gemojione.index.images_path, tmpdir)
+
+ Dir.chdir(tmpdir) do
+ Dir["**/*.png"].each do |png|
+ resize!(File.join(tmpdir, png), SIZE)
+ end
+ end
+
+ style_path = Rails.root.join(*%w(app assets stylesheets pages emojis.scss))
+
+ # Combine the resized assets into a packed sprite and re-generate the SCSS
+ SpriteFactory.cssurl = "image-url('$IMAGE')"
+ SpriteFactory.run!(File.join(tmpdir, 'images'), {
+ output_style: style_path,
+ output_image: "app/assets/images/emoji.png",
+ selector: '.emoji-',
+ style: :scss,
+ nocomments: true,
+ pngcrush: true,
+ layout: :packed
+ })
+
+ # SpriteFactory's SCSS is a bit too verbose for our purposes here, so
+ # let's simplify it
+ system(%Q(sed -i '' "s/width: #{SIZE}px; height: #{SIZE}px; background: image-url('emoji.png')/background-position:/" #{style_path}))
+ system(%Q(sed -i '' "s/ no-repeat//" #{style_path}))
+ system(%Q(sed -i '' "s/ 0px/ 0/" #{style_path}))
+
+ # Append a generic rule that applies to all Emojis
+ File.open(style_path, 'a') do |f|
+ f.puts
+ f.puts <<-CSS.strip_heredoc
+ .emoji-icon {
+ background-image: image-url('emoji.png');
+ background-repeat: no-repeat;
+ height: #{SIZE}px;
+ width: #{SIZE}px;
+
+ @media only screen and (-webkit-min-device-pixel-ratio: 2),
+ only screen and (min--moz-device-pixel-ratio: 2),
+ only screen and (-o-min-device-pixel-ratio: 2/1),
+ only screen and (min-device-pixel-ratio: 2),
+ only screen and (min-resolution: 192dpi),
+ only screen and (min-resolution: 2dppx) {
+ background-image: image-url('emoji@2x.png');
+ background-size: 840px 820px;
+ }
+ }
+ CSS
+ end
+ end
+
+ # Now do it again but for Retina
+ Dir.mktmpdir do |tmpdir|
+ # Copy the Gemojione assets to the temporary folder for resizing
+ FileUtils.cp_r(Gemojione.index.images_path, tmpdir)
+
+ Dir.chdir(tmpdir) do
+ Dir["**/*.png"].each do |png|
+ resize!(File.join(tmpdir, png), RETINA)
+ end
+ end
+
+ # Combine the resized assets into a packed sprite and re-generate the SCSS
+ SpriteFactory.run!(File.join(tmpdir, 'images'), {
+ output_image: "app/assets/images/emoji@2x.png",
+ style: false,
+ nocomments: true,
+ pngcrush: true,
+ layout: :packed
+ })
+ end
+ end
+
+ def check_requirements!
+ return if defined?(SpriteFactory) && defined?(Magick)
+
+ puts <<-MSG.strip_heredoc
+ This task is disabled by default and should only be run when the Gemojione
+ gem is updated with new Emojis.
+
+ To enable this task, *temporarily* add the following lines to Gemfile and
+ re-bundle:
+
+ gem 'sprite-factory'
+ gem 'rmagick'
+ MSG
+
+ exit 1
+ end
+
+ def resize!(image_path, size)
+ # Resize the image in-place, save it, and free the object
+ image = Magick::Image.read(image_path).first
+ image.resize!(size, size)
+ image.write(image_path) { self.quality = 100 }
+ image.destroy!
+ end
+end
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 581ab26db79..27ed57efe55 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -913,7 +913,7 @@ namespace :gitlab do
end
def check_git_version
- required_version = Gitlab::VersionInfo.new(1, 7, 10)
+ required_version = Gitlab::VersionInfo.new(2, 7, 3)
current_version = Gitlab::VersionInfo.parse(run(%W(#{Gitlab.config.git.bin_path} --version)))
puts "Your git bin path is \"#{Gitlab.config.git.bin_path}\""
diff --git a/lib/tasks/gitlab/web_hook.rake b/lib/tasks/gitlab/web_hook.rake
index 76e443e55ee..cc0f668474e 100644
--- a/lib/tasks/gitlab/web_hook.rake
+++ b/lib/tasks/gitlab/web_hook.rake
@@ -1,13 +1,13 @@
namespace :gitlab do
namespace :web_hook do
- desc "GitLab | Adds a web hook to the projects"
+ desc "GitLab | Adds a webhook to the projects"
task :add => :environment do
web_hook_url = ENV['URL']
namespace_path = ENV['NAMESPACE']
projects = find_projects(namespace_path)
- puts "Adding web hook '#{web_hook_url}' to:"
+ puts "Adding webhook '#{web_hook_url}' to:"
projects.find_each(batch_size: 1000) do |project|
print "- #{project.name} ... "
web_hook = project.hooks.new(url: web_hook_url)
@@ -20,7 +20,7 @@ namespace :gitlab do
end
end
- desc "GitLab | Remove a web hook from the projects"
+ desc "GitLab | Remove a webhook from the projects"
task :rm => :environment do
web_hook_url = ENV['URL']
namespace_path = ENV['NAMESPACE']
@@ -28,12 +28,12 @@ namespace :gitlab do
projects = find_projects(namespace_path)
projects_ids = projects.pluck(:id)
- puts "Removing web hooks with the url '#{web_hook_url}' ... "
+ puts "Removing webhooks with the url '#{web_hook_url}' ... "
count = WebHook.where(url: web_hook_url, project_id: projects_ids, type: 'ProjectHook').delete_all
- puts "#{count} web hooks were removed."
+ puts "#{count} webhooks were removed."
end
- desc "GitLab | List web hooks"
+ desc "GitLab | List webhooks"
task :list => :environment do
namespace_path = ENV['NAMESPACE']
@@ -43,7 +43,7 @@ namespace :gitlab do
puts "#{hook.project.name.truncate(20).ljust(20)} -> #{hook.url}"
end
- puts "\n#{web_hooks.size} web hooks found."
+ puts "\n#{web_hooks.size} webhooks found."
end
end
diff --git a/lib/tasks/scss-lint.rake b/lib/tasks/scss-lint.rake
new file mode 100644
index 00000000000..250fd8699e4
--- /dev/null
+++ b/lib/tasks/scss-lint.rake
@@ -0,0 +1,10 @@
+unless Rails.env.production?
+ require 'scss_lint/rake_task'
+
+ SCSSLint::RakeTask.new do |t|
+ t.config = '.scss-lint.yml'
+ # See https://github.com/brigade/scss-lint/issues/726
+ # Hack, otherwise linter won't respect scss_files option in config file.
+ t.files = []
+ end
+end
diff --git a/lib/tasks/spec.rake b/lib/tasks/spec.rake
index 0985ef3a669..2cf7a25a0fd 100644
--- a/lib/tasks/spec.rake
+++ b/lib/tasks/spec.rake
@@ -46,20 +46,11 @@ namespace :spec do
run_commands(cmds)
end
- desc 'GitLab | Rspec | Run benchmark specs'
- task :benchmark do
- cmds = [
- %W(rake gitlab:setup),
- %W(rspec spec --tag @benchmark)
- ]
- run_commands(cmds)
- end
-
desc 'GitLab | Rspec | Run other specs'
task :other do
cmds = [
%W(rake gitlab:setup),
- %W(rspec spec --tag ~@api --tag ~@feature --tag ~@models --tag ~@lib --tag ~@services --tag ~@benchmark)
+ %W(rspec spec --tag ~@api --tag ~@feature --tag ~@models --tag ~@lib --tag ~@services)
]
run_commands(cmds)
end
@@ -69,7 +60,7 @@ desc "GitLab | Run specs"
task :spec do
cmds = [
%W(rake gitlab:setup),
- %W(rspec spec --tag ~@benchmark),
+ %W(rspec spec),
]
run_commands(cmds)
end
diff --git a/lib/tasks/spinach.rake b/lib/tasks/spinach.rake
index 3acfc6e2075..01d23b89bb7 100644
--- a/lib/tasks/spinach.rake
+++ b/lib/tasks/spinach.rake
@@ -4,53 +4,59 @@ 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)
+ run_spinach_tests('@project_commits,@project_issues,@project_merge_requests')
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)
+ run_spinach_tests('~@admin,~@dashboard,~@profile,~@public,~@snippets,~@project_commits,~@project_issues,~@project_merge_requests')
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),
- ]
- run_commands(cmds)
+ run_spinach_tests('~@admin,~@dashboard,~@profile,~@public,~@snippets')
end
desc "GitLab | Spinach | Run other spinach features"
task :other do
- cmds = [
- %W(rake gitlab:setup),
- %W(spinach --tags @admin,@dashboard,@profile,@public,@snippets),
- ]
- run_commands(cmds)
+ run_spinach_tests('@admin,@dashboard,@profile,@public,@snippets')
+ end
+
+ desc "GitLab | Spinach | Run other spinach features"
+ task :builds do
+ run_spinach_tests('@builds')
end
end
desc "GitLab | Run spinach"
task :spinach do
- cmds = [
- %W(rake gitlab:setup),
- %W(spinach),
- ]
- run_commands(cmds)
+ run_spinach_tests(nil)
+end
+
+def run_command(cmd)
+ system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd)
end
-def run_commands(cmds)
- cmds.each do |cmd|
- system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd) or raise("#{cmd} failed!")
+def run_spinach_command(args)
+ run_command(%w(spinach -r rerun) + args)
+end
+
+def run_spinach_tests(tags)
+ #run_command(%w(rake gitlab:setup)) or raise('gitlab:setup failed!')
+
+ success = run_spinach_command(%W(--tags #{tags}))
+ 3.times do |_|
+ break if success
+ break unless File.exists?('tmp/spinach-rerun.txt')
+
+ tests = File.foreach('tmp/spinach-rerun.txt').map(&:chomp)
+ puts ''
+ puts "Spinach tests for #{tags}: Retrying tests... #{tests}".red
+ puts ''
+ sleep(3)
+ success = run_spinach_command(tests)
end
+
+ raise("spinach tests for #{tags} failed!") unless success
end