Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDouwe Maan <douwe@gitlab.com>2015-08-29 21:49:14 +0300
committerDouwe Maan <douwe@gitlab.com>2015-08-29 21:49:14 +0300
commitfe86c8dfbd81ef21d0d685105397f4bf6048b2f2 (patch)
tree106ff615898f09076cada653a8dfb5710ce593db /lib
parentd92f428024b2878682bb23b6b03bc671636b5afe (diff)
parenta429eb4d455cabde26c5cdf8a3b38e65966531dc (diff)
Merge branch 'master' into joelkoglin/gitlab-ce-feature_fix_ldap_auth_issue_993
Diffstat (limited to 'lib')
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb15
-rw-r--r--lib/gitlab/bitbucket_import/key_adder.rb7
-rw-r--r--lib/gitlab/bitbucket_import/key_deleter.rb7
-rw-r--r--lib/gitlab/bitbucket_import/project_creator.rb12
-rw-r--r--lib/gitlab/color_schemes.rb67
-rw-r--r--lib/gitlab/current_settings.rb2
-rw-r--r--lib/gitlab/email/attachment_uploader.rb35
-rw-r--r--lib/gitlab/email/receiver.rb106
-rw-r--r--lib/gitlab/email/reply_parser.rb79
-rw-r--r--lib/gitlab/github_import/importer.rb4
-rw-r--r--lib/gitlab/github_import/project_creator.rb13
-rw-r--r--lib/gitlab/gitlab_import/importer.rb14
-rw-r--r--lib/gitlab/gitlab_import/project_creator.rb12
-rw-r--r--lib/gitlab/markdown/autolink_filter.rb8
-rw-r--r--lib/gitlab/reply_by_email.rb49
-rw-r--r--lib/gitlab/search_results.rb14
-rw-r--r--lib/gitlab/themes.rb18
-rw-r--r--lib/redcarpet/render/gitlab_html.rb5
-rwxr-xr-xlib/support/init.d/gitlab105
-rwxr-xr-xlib/support/init.d/gitlab.default.example9
-rw-r--r--lib/tasks/gitlab/check.rake169
21 files changed, 690 insertions, 60 deletions
diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb
index 42c93707caa..d8a7d29f1bf 100644
--- a/lib/gitlab/bitbucket_import/importer.rb
+++ b/lib/gitlab/bitbucket_import/importer.rb
@@ -5,7 +5,10 @@ module Gitlab
def initialize(project)
@project = project
- @client = Client.new(project.creator.bitbucket_access_token, project.creator.bitbucket_access_token_secret)
+ import_data = project.import_data.try(:data)
+ bb_session = import_data["bb_session"] if import_data
+ @client = Client.new(bb_session["bitbucket_access_token"],
+ bb_session["bitbucket_access_token_secret"])
@formatter = Gitlab::ImportFormatter.new
end
@@ -16,12 +19,12 @@ module Gitlab
#Issues && Comments
issues = client.issues(project_identifier)
-
+
issues["issues"].each do |issue|
body = @formatter.author_line(issue["reported_by"]["username"], issue["content"])
-
+
comments = client.issue_comments(project_identifier, issue["local_id"])
-
+
if comments.any?
body += @formatter.comments_header
end
@@ -31,13 +34,13 @@ module Gitlab
end
project.issues.create!(
- description: body,
+ description: body,
title: issue["title"],
state: %w(resolved invalid duplicate wontfix).include?(issue["status"]) ? 'closed' : 'opened',
author_id: gl_user_id(project, issue["reported_by"]["username"])
)
end
-
+
true
end
diff --git a/lib/gitlab/bitbucket_import/key_adder.rb b/lib/gitlab/bitbucket_import/key_adder.rb
index 9931aa7e029..0b63f025d0a 100644
--- a/lib/gitlab/bitbucket_import/key_adder.rb
+++ b/lib/gitlab/bitbucket_import/key_adder.rb
@@ -3,14 +3,15 @@ module Gitlab
class KeyAdder
attr_reader :repo, :current_user, :client
- def initialize(repo, current_user)
+ def initialize(repo, current_user, access_params)
@repo, @current_user = repo, current_user
- @client = Client.new(current_user.bitbucket_access_token, current_user.bitbucket_access_token_secret)
+ @client = Client.new(access_params[:bitbucket_access_token],
+ access_params[:bitbucket_access_token_secret])
end
def execute
return false unless BitbucketImport.public_key.present?
-
+
project_identifier = "#{repo["owner"]}/#{repo["slug"]}"
client.add_deploy_key(project_identifier, BitbucketImport.public_key)
diff --git a/lib/gitlab/bitbucket_import/key_deleter.rb b/lib/gitlab/bitbucket_import/key_deleter.rb
index 1a24a86fc37..f4dd393ad29 100644
--- a/lib/gitlab/bitbucket_import/key_deleter.rb
+++ b/lib/gitlab/bitbucket_import/key_deleter.rb
@@ -6,12 +6,15 @@ module Gitlab
def initialize(project)
@project = project
@current_user = project.creator
- @client = Client.new(current_user.bitbucket_access_token, current_user.bitbucket_access_token_secret)
+ import_data = project.import_data.try(:data)
+ bb_session = import_data["bb_session"] if import_data
+ @client = Client.new(bb_session["bitbucket_access_token"],
+ bb_session["bitbucket_access_token_secret"])
end
def execute
return false unless BitbucketImport.public_key.present?
-
+
client.delete_deploy_key(project.import_source, BitbucketImport.public_key)
true
diff --git a/lib/gitlab/bitbucket_import/project_creator.rb b/lib/gitlab/bitbucket_import/project_creator.rb
index 54420e62c90..35e34d033e0 100644
--- a/lib/gitlab/bitbucket_import/project_creator.rb
+++ b/lib/gitlab/bitbucket_import/project_creator.rb
@@ -1,16 +1,17 @@
module Gitlab
module BitbucketImport
class ProjectCreator
- attr_reader :repo, :namespace, :current_user
+ attr_reader :repo, :namespace, :current_user, :session_data
- def initialize(repo, namespace, current_user)
+ def initialize(repo, namespace, current_user, session_data)
@repo = repo
@namespace = namespace
@current_user = current_user
+ @session_data = session_data
end
def execute
- ::Projects::CreateService.new(current_user,
+ project = ::Projects::CreateService.new(current_user,
name: repo["name"],
path: repo["slug"],
description: repo["description"],
@@ -18,8 +19,11 @@ module Gitlab
visibility_level: repo["is_private"] ? Gitlab::VisibilityLevel::PRIVATE : Gitlab::VisibilityLevel::PUBLIC,
import_type: "bitbucket",
import_source: "#{repo["owner"]}/#{repo["slug"]}",
- import_url: "ssh://git@bitbucket.org/#{repo["owner"]}/#{repo["slug"]}.git"
+ import_url: "ssh://git@bitbucket.org/#{repo["owner"]}/#{repo["slug"]}.git",
).execute
+
+ project.create_import_data(data: { "bb_session" => session_data } )
+ project
end
end
end
diff --git a/lib/gitlab/color_schemes.rb b/lib/gitlab/color_schemes.rb
new file mode 100644
index 00000000000..9c4664df903
--- /dev/null
+++ b/lib/gitlab/color_schemes.rb
@@ -0,0 +1,67 @@
+module Gitlab
+ # Module containing GitLab's syntax color scheme definitions and helper
+ # methods for accessing them.
+ module ColorSchemes
+ # Struct class representing a single Scheme
+ Scheme = Struct.new(:id, :name, :css_class)
+
+ SCHEMES = [
+ Scheme.new(1, 'White', 'white'),
+ Scheme.new(2, 'Dark', 'dark'),
+ Scheme.new(3, 'Solarized Light', 'solarized-light'),
+ Scheme.new(4, 'Solarized Dark', 'solarized-dark'),
+ Scheme.new(5, 'Monokai', 'monokai')
+ ].freeze
+
+ # Convenience method to get a space-separated String of all the color scheme
+ # classes that might be applied to a code block.
+ #
+ # Returns a String
+ def self.body_classes
+ SCHEMES.collect(&:css_class).uniq.join(' ')
+ end
+
+ # Get a Scheme by its ID
+ #
+ # If the ID is invalid, returns the default Scheme.
+ #
+ # id - Integer ID
+ #
+ # Returns a Scheme
+ def self.by_id(id)
+ SCHEMES.detect { |s| s.id == id } || default
+ end
+
+ # Returns the number of defined Schemes
+ def self.count
+ SCHEMES.size
+ end
+
+ # Get the default Scheme
+ #
+ # Returns a Scheme
+ def self.default
+ by_id(1)
+ end
+
+ # Iterate through each Scheme
+ #
+ # Yields the Scheme object
+ def self.each(&block)
+ SCHEMES.each(&block)
+ end
+
+ # Get the Scheme for the specified user, or the default
+ #
+ # user - User record
+ #
+ # Returns a Scheme
+ def self.for_user(user)
+ if user
+ by_id(user.color_scheme_id)
+ else
+ default
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 1a2a50a14d0..7ad3ed8728f 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -4,7 +4,7 @@ module Gitlab
key = :current_application_settings
RequestStore.store[key] ||= begin
- if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('application_settings')
+ if ActiveRecord::Base.connection.active? && ActiveRecord::Base.connection.table_exists?('application_settings')
ApplicationSetting.current || ApplicationSetting.create_from_defaults
else
fake_application_settings
diff --git a/lib/gitlab/email/attachment_uploader.rb b/lib/gitlab/email/attachment_uploader.rb
new file mode 100644
index 00000000000..32cece8316b
--- /dev/null
+++ b/lib/gitlab/email/attachment_uploader.rb
@@ -0,0 +1,35 @@
+module Gitlab
+ module Email
+ class AttachmentUploader
+ attr_accessor :message
+
+ def initialize(message)
+ @message = message
+ end
+
+ def execute(project)
+ attachments = []
+
+ message.attachments.each do |attachment|
+ tmp = Tempfile.new("gitlab-email-attachment")
+ begin
+ File.open(tmp.path, "w+b") { |f| f.write attachment.body.decoded }
+
+ file = {
+ tempfile: tmp,
+ filename: attachment.filename,
+ content_type: attachment.content_type
+ }
+
+ link = ::Projects::UploadService.new(project, file).execute
+ attachments << link if link
+ ensure
+ tmp.close!
+ end
+ end
+
+ attachments
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/email/receiver.rb b/lib/gitlab/email/receiver.rb
new file mode 100644
index 00000000000..355fbd27898
--- /dev/null
+++ b/lib/gitlab/email/receiver.rb
@@ -0,0 +1,106 @@
+# Inspired in great part by Discourse's Email::Receiver
+module Gitlab
+ module Email
+ class Receiver
+ class ProcessingError < StandardError; end
+ class EmailUnparsableError < ProcessingError; end
+ class SentNotificationNotFoundError < ProcessingError; end
+ class EmptyEmailError < ProcessingError; end
+ class AutoGeneratedEmailError < ProcessingError; end
+ class UserNotFoundError < ProcessingError; end
+ class UserBlockedError < ProcessingError; end
+ class UserNotAuthorizedError < ProcessingError; end
+ class NoteableNotFoundError < ProcessingError; end
+ class InvalidNoteError < ProcessingError; end
+
+ def initialize(raw)
+ @raw = raw
+ end
+
+ def execute
+ raise EmptyEmailError if @raw.blank?
+
+ raise SentNotificationNotFoundError unless sent_notification
+
+ raise AutoGeneratedEmailError if message.header.to_s =~ /auto-(generated|replied)/
+
+ author = sent_notification.recipient
+
+ raise UserNotFoundError unless author
+
+ raise UserBlockedError if author.blocked?
+
+ project = sent_notification.project
+
+ raise UserNotAuthorizedError unless project && author.can?(:create_note, project)
+
+ raise NoteableNotFoundError unless sent_notification.noteable
+
+ reply = ReplyParser.new(message).execute.strip
+
+ raise EmptyEmailError if reply.blank?
+
+ reply = add_attachments(reply)
+
+ note = create_note(reply)
+
+ unless note.persisted?
+ message = "The comment could not be created for the following reasons:"
+ note.errors.full_messages.each do |error|
+ message << "\n\n- #{error}"
+ end
+
+ raise InvalidNoteError, message
+ end
+ end
+
+ private
+
+ def message
+ @message ||= Mail::Message.new(@raw)
+ rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError => e
+ raise EmailUnparsableError, e
+ end
+
+ def reply_key
+ reply_key = nil
+ message.to.each do |address|
+ reply_key = Gitlab::ReplyByEmail.reply_key_from_address(address)
+ break if reply_key
+ end
+
+ reply_key
+ end
+
+ def sent_notification
+ return nil unless reply_key
+
+ SentNotification.for(reply_key)
+ end
+
+ def add_attachments(reply)
+ attachments = Email::AttachmentUploader.new(message).execute(sent_notification.project)
+
+ attachments.each do |link|
+ text = "[#{link[:alt]}](#{link[:url]})"
+ text.prepend("!") if link[:is_image]
+
+ reply << "\n\n#{text}"
+ end
+
+ reply
+ end
+
+ def create_note(reply)
+ Notes::CreateService.new(
+ sent_notification.project,
+ sent_notification.recipient,
+ note: reply,
+ noteable_type: sent_notification.noteable_type,
+ noteable_id: sent_notification.noteable_id,
+ commit_id: sent_notification.commit_id
+ ).execute
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/email/reply_parser.rb b/lib/gitlab/email/reply_parser.rb
new file mode 100644
index 00000000000..6ed36b51f12
--- /dev/null
+++ b/lib/gitlab/email/reply_parser.rb
@@ -0,0 +1,79 @@
+# Inspired in great part by Discourse's Email::Receiver
+module Gitlab
+ module Email
+ class ReplyParser
+ attr_accessor :message
+
+ def initialize(message)
+ @message = message
+ end
+
+ def execute
+ body = select_body(message)
+
+ encoding = body.encoding
+
+ body = discourse_email_trimmer(body)
+
+ body = EmailReplyParser.parse_reply(body)
+
+ body.force_encoding(encoding).encode("UTF-8")
+ end
+
+ private
+
+ def select_body(message)
+ text = message.text_part if message.multipart?
+ text ||= message if message.content_type !~ /text\/html/
+
+ return "" unless text
+
+ text = fix_charset(text)
+
+ # Certain trigger phrases that means we didn't parse correctly
+ if text =~ /(Content\-Type\:|multipart\/alternative|text\/plain)/
+ return ""
+ end
+
+ text
+ end
+
+ # Force encoding to UTF-8 on a Mail::Message or Mail::Part
+ def fix_charset(object)
+ return nil if object.nil?
+
+ if object.charset
+ object.body.decoded.force_encoding(object.charset.gsub(/utf8/i, "UTF-8")).encode("UTF-8").to_s
+ else
+ object.body.to_s
+ end
+ rescue
+ nil
+ end
+
+ REPLYING_HEADER_LABELS = %w(From Sent To Subject Reply To Cc Bcc Date)
+ REPLYING_HEADER_REGEX = Regexp.union(REPLYING_HEADER_LABELS.map { |label| "#{label}:" })
+
+ def discourse_email_trimmer(body)
+ lines = body.scrub.lines.to_a
+ range_end = 0
+
+ lines.each_with_index do |l, idx|
+ # This one might be controversial but so many reply lines have years, times and end with a colon.
+ # Let's try it and see how well it works.
+ break if (l =~ /\d{4}/ && l =~ /\d:\d\d/ && l =~ /\:$/) ||
+ (l =~ /On \w+ \d+,? \d+,?.*wrote:/)
+
+ # Headers on subsequent lines
+ break if (0..2).all? { |off| lines[idx+off] =~ REPLYING_HEADER_REGEX }
+ # Headers on the same line
+ break if REPLYING_HEADER_LABELS.count { |label| l.include?(label) } >= 3
+
+ range_end = idx
+ end
+
+ lines[0..range_end].join.strip
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb
index 98039a76dcd..8c106a61735 100644
--- a/lib/gitlab/github_import/importer.rb
+++ b/lib/gitlab/github_import/importer.rb
@@ -5,7 +5,9 @@ module Gitlab
def initialize(project)
@project = project
- @client = Client.new(project.creator.github_access_token)
+ import_data = project.import_data.try(:data)
+ github_session = import_data["github_session"] if import_data
+ @client = Client.new(github_session["github_access_token"])
@formatter = Gitlab::ImportFormatter.new
end
diff --git a/lib/gitlab/github_import/project_creator.rb b/lib/gitlab/github_import/project_creator.rb
index 2723eec933e..8c27ebd1ce8 100644
--- a/lib/gitlab/github_import/project_creator.rb
+++ b/lib/gitlab/github_import/project_creator.rb
@@ -1,16 +1,18 @@
module Gitlab
module GithubImport
class ProjectCreator
- attr_reader :repo, :namespace, :current_user
+ attr_reader :repo, :namespace, :current_user, :session_data
- def initialize(repo, namespace, current_user)
+ def initialize(repo, namespace, current_user, session_data)
@repo = repo
@namespace = namespace
@current_user = current_user
+ @session_data = session_data
end
def execute
- ::Projects::CreateService.new(current_user,
+ project = ::Projects::CreateService.new(
+ current_user,
name: repo.name,
path: repo.name,
description: repo.description,
@@ -18,8 +20,11 @@ module Gitlab
visibility_level: repo.private ? Gitlab::VisibilityLevel::PRIVATE : Gitlab::VisibilityLevel::PUBLIC,
import_type: "github",
import_source: repo.full_name,
- import_url: repo.clone_url.sub("https://", "https://#{current_user.github_access_token}@")
+ import_url: repo.clone_url.sub("https://", "https://#{@session_data[:github_access_token]}@")
).execute
+
+ project.create_import_data(data: { "github_session" => session_data } )
+ project
end
end
end
diff --git a/lib/gitlab/gitlab_import/importer.rb b/lib/gitlab/gitlab_import/importer.rb
index c5304a0699b..50594d2b24f 100644
--- a/lib/gitlab/gitlab_import/importer.rb
+++ b/lib/gitlab/gitlab_import/importer.rb
@@ -5,7 +5,9 @@ module Gitlab
def initialize(project)
@project = project
- @client = Client.new(project.creator.gitlab_access_token)
+ import_data = project.import_data.try(:data)
+ gitlab_session = import_data["gitlab_session"] if import_data
+ @client = Client.new(gitlab_session["gitlab_access_token"])
@formatter = Gitlab::ImportFormatter.new
end
@@ -14,12 +16,12 @@ module Gitlab
#Issues && Comments
issues = client.issues(project_identifier)
-
+
issues.each do |issue|
body = @formatter.author_line(issue["author"]["name"], issue["description"])
-
+
comments = client.issue_comments(project_identifier, issue["id"])
-
+
if comments.any?
body += @formatter.comments_header
end
@@ -29,13 +31,13 @@ module Gitlab
end
project.issues.create!(
- description: body,
+ description: body,
title: issue["title"],
state: issue["state"],
author_id: gl_user_id(project, issue["author"]["id"])
)
end
-
+
true
end
diff --git a/lib/gitlab/gitlab_import/project_creator.rb b/lib/gitlab/gitlab_import/project_creator.rb
index f0d7141bf56..d9452de6a50 100644
--- a/lib/gitlab/gitlab_import/project_creator.rb
+++ b/lib/gitlab/gitlab_import/project_creator.rb
@@ -1,16 +1,17 @@
module Gitlab
module GitlabImport
class ProjectCreator
- attr_reader :repo, :namespace, :current_user
+ attr_reader :repo, :namespace, :current_user, :session_data
- def initialize(repo, namespace, current_user)
+ def initialize(repo, namespace, current_user, session_data)
@repo = repo
@namespace = namespace
@current_user = current_user
+ @session_data = session_data
end
def execute
- ::Projects::CreateService.new(current_user,
+ project = ::Projects::CreateService.new(current_user,
name: repo["name"],
path: repo["path"],
description: repo["description"],
@@ -18,8 +19,11 @@ module Gitlab
visibility_level: repo["visibility_level"],
import_type: "gitlab",
import_source: repo["path_with_namespace"],
- import_url: repo["http_url_to_repo"].sub("://", "://oauth2:#{current_user.gitlab_access_token}@")
+ import_url: repo["http_url_to_repo"].sub("://", "://oauth2:#{@session_data[:gitlab_access_token]}@")
).execute
+
+ project.create_import_data(data: { "gitlab_session" => session_data } )
+ project
end
end
end
diff --git a/lib/gitlab/markdown/autolink_filter.rb b/lib/gitlab/markdown/autolink_filter.rb
index 4e14a048cfb..541f1d88ffc 100644
--- a/lib/gitlab/markdown/autolink_filter.rb
+++ b/lib/gitlab/markdown/autolink_filter.rb
@@ -87,8 +87,14 @@ module Gitlab
def autolink_filter(text)
text.gsub(LINK_PATTERN) do |match|
+ # Remove any trailing HTML entities and store them for appending
+ # outside the link element. The entity must be marked HTML safe in
+ # order to be output literally rather than escaped.
+ match.gsub!(/((?:&[\w#]+;)+)\z/, '')
+ dropped = ($1 || '').html_safe
+
options = link_options.merge(href: match)
- content_tag(:a, match, options)
+ content_tag(:a, match, options) + dropped
end
end
diff --git a/lib/gitlab/reply_by_email.rb b/lib/gitlab/reply_by_email.rb
new file mode 100644
index 00000000000..c3fe6778f06
--- /dev/null
+++ b/lib/gitlab/reply_by_email.rb
@@ -0,0 +1,49 @@
+module Gitlab
+ module ReplyByEmail
+ class << self
+ def enabled?
+ config.enabled && address_formatted_correctly?
+ end
+
+ def address_formatted_correctly?
+ config.address &&
+ config.address.include?("%{reply_key}")
+ end
+
+ def reply_key
+ return nil unless enabled?
+
+ SecureRandom.hex(16)
+ end
+
+ def reply_address(reply_key)
+ config.address.gsub('%{reply_key}', reply_key)
+ end
+
+ def reply_key_from_address(address)
+ regex = address_regex
+ return unless regex
+
+ match = address.match(regex)
+ return unless match
+
+ match[1]
+ end
+
+ private
+
+ def config
+ Gitlab.config.reply_by_email
+ end
+
+ def address_regex
+ wildcard_address = config.address
+ return nil unless wildcard_address
+
+ regex = Regexp.escape(wildcard_address)
+ regex = regex.gsub(Regexp.escape('%{reply_key}'), "(.+)")
+ Regexp.new(regex).freeze
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb
index 06245374bc8..2ab2d4af797 100644
--- a/lib/gitlab/search_results.rb
+++ b/lib/gitlab/search_results.rb
@@ -19,13 +19,15 @@ module Gitlab
issues.page(page).per(per_page)
when 'merge_requests'
merge_requests.page(page).per(per_page)
+ when 'milestones'
+ milestones.page(page).per(per_page)
else
Kaminari.paginate_array([]).page(page).per(per_page)
end
end
def total_count
- @total_count ||= projects_count + issues_count + merge_requests_count
+ @total_count ||= projects_count + issues_count + merge_requests_count + milestones_count
end
def projects_count
@@ -40,6 +42,10 @@ module Gitlab
@merge_requests_count ||= merge_requests.count
end
+ def milestones_count
+ @milestones_count ||= milestones.count
+ end
+
def empty?
total_count.zero?
end
@@ -60,6 +66,12 @@ module Gitlab
issues.order('updated_at DESC')
end
+ def milestones
+ milestones = Milestone.where(project_id: limit_project_ids)
+ milestones = milestones.search(query)
+ milestones.order('updated_at DESC')
+ end
+
def merge_requests
merge_requests = MergeRequest.in_projects(limit_project_ids)
if query =~ /[#!](\d+)\z/
diff --git a/lib/gitlab/themes.rb b/lib/gitlab/themes.rb
index 5209df92795..83f91de810c 100644
--- a/lib/gitlab/themes.rb
+++ b/lib/gitlab/themes.rb
@@ -37,6 +37,11 @@ module Gitlab
THEMES.detect { |t| t.id == id } || default
end
+ # Returns the number of defined Themes
+ def self.count
+ THEMES.size
+ end
+
# Get the default Theme
#
# Returns a Theme
@@ -51,6 +56,19 @@ module Gitlab
THEMES.each(&block)
end
+ # Get the Theme for the specified user, or the default
+ #
+ # user - User record
+ #
+ # Returns a Theme
+ def self.for_user(user)
+ if user
+ by_id(user.theme_id)
+ else
+ default
+ end
+ end
+
private
def self.default_id
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
index f57b56cbdf0..9cb8e91d6e3 100644
--- a/lib/redcarpet/render/gitlab_html.rb
+++ b/lib/redcarpet/render/gitlab_html.rb
@@ -4,9 +4,8 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
attr_reader :template
alias_method :h, :template
- def initialize(template, color_scheme, options = {})
+ def initialize(template, options = {})
@template = template
- @color_scheme = color_scheme
@options = options.dup
@options.reverse_merge!(
@@ -35,7 +34,7 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
end
formatter = Rouge::Formatters::HTMLGitlab.new(
- cssclass: "code highlight #{@color_scheme} #{lexer.tag}"
+ cssclass: "code highlight js-syntax-highlight #{lexer.tag}"
)
formatter.format(lexer.lex(code))
end
diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab
index a3455728a94..457bd31e23b 100755
--- a/lib/support/init.d/gitlab
+++ b/lib/support/init.d/gitlab
@@ -35,6 +35,8 @@ pid_path="$app_root/tmp/pids"
socket_path="$app_root/tmp/sockets"
web_server_pid_path="$pid_path/unicorn.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid"
+mail_room_enabled=false
+mail_room_pid_path="$pid_path/mail_room.pid"
shell_path="/bin/bash"
# Read configuration variable file if it is present
@@ -70,13 +72,20 @@ check_pids(){
else
spid=0
fi
+ if [ "$mail_room_enabled" = true ]; then
+ if [ -f "$mail_room_pid_path" ]; then
+ mpid=$(cat "$mail_room_pid_path")
+ else
+ mpid=0
+ fi
+ fi
}
## Called when we have started the two processes and are waiting for their pid files.
wait_for_pids(){
# We are sleeping a bit here mostly because sidekiq is slow at writing it's pid
i=0;
- while [ ! -f $web_server_pid_path -o ! -f $sidekiq_pid_path ]; do
+ while [ ! -f $web_server_pid_path ] || [ ! -f $sidekiq_pid_path ] || { [ "$mail_room_enabled" = true ] && [ ! -f $mail_room_pid_path ]; }; do
sleep 0.1;
i=$((i+1))
if [ $((i%10)) = 0 ]; then
@@ -111,7 +120,15 @@ check_status(){
else
sidekiq_status="-1"
fi
- if [ $web_status = 0 -a $sidekiq_status = 0 ]; then
+ if [ "$mail_room_enabled" = true ]; then
+ if [ $mpid -ne 0 ]; then
+ kill -0 "$mpid" 2>/dev/null
+ mail_room_status="$?"
+ else
+ mail_room_status="-1"
+ fi
+ fi
+ if [ $web_status = 0 ] && [ $sidekiq_status = 0 ] && { [ "$mail_room_enabled" != true ] || [ $mail_room_status = 0 ]; }; then
gitlab_status=0
else
# http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
@@ -125,26 +142,33 @@ check_stale_pids(){
check_status
# If there is a pid it is something else than 0, the service is running if
# *_status is == 0.
- if [ "$wpid" != "0" -a "$web_status" != "0" ]; then
+ if [ "$wpid" != "0" ] && [ "$web_status" != "0" ]; then
echo "Removing stale Unicorn web server pid. This is most likely caused by the web server crashing the last time it ran."
if ! rm "$web_server_pid_path"; then
echo "Unable to remove stale pid, exiting."
exit 1
fi
fi
- if [ "$spid" != "0" -a "$sidekiq_status" != "0" ]; then
+ if [ "$spid" != "0" ] && [ "$sidekiq_status" != "0" ]; then
echo "Removing stale Sidekiq job dispatcher pid. This is most likely caused by Sidekiq crashing the last time it ran."
if ! rm "$sidekiq_pid_path"; then
echo "Unable to remove stale pid, exiting"
exit 1
fi
fi
+ if [ "$mail_room_enabled" = true ] && [ "$mpid" != "0" ] && [ "$mail_room_status" != "0" ]; then
+ echo "Removing stale MailRoom job dispatcher pid. This is most likely caused by MailRoom crashing the last time it ran."
+ if ! rm "$mail_room_pid_path"; then
+ echo "Unable to remove stale pid, exiting"
+ exit 1
+ fi
+ fi
}
## If no parts of the service is running, bail out.
exit_if_not_running(){
check_stale_pids
- if [ "$web_status" != "0" -a "$sidekiq_status" != "0" ]; then
+ if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
echo "GitLab is not running."
exit
fi
@@ -154,12 +178,14 @@ exit_if_not_running(){
start_gitlab() {
check_stale_pids
- if [ "$web_status" != "0" -a "$sidekiq_status" != "0" ]; then
- echo -n "Starting both the GitLab Unicorn and Sidekiq"
- elif [ "$web_status" != "0" ]; then
- echo -n "Starting GitLab Unicorn"
- elif [ "$sidekiq_status" != "0" ]; then
- echo -n "Starting GitLab Sidekiq"
+ if [ "$web_status" != "0" ]; then
+ echo "Starting GitLab Unicorn"
+ fi
+ if [ "$sidekiq_status" != "0" ]; then
+ echo "Starting GitLab Sidekiq"
+ fi
+ if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" != "0" ]; then
+ echo "Starting GitLab MailRoom"
fi
# Then check if the service is running. If it is: don't start again.
@@ -179,22 +205,33 @@ start_gitlab() {
RAILS_ENV=$RAILS_ENV bin/background_jobs start &
fi
+ if [ "$mail_room_enabled" = true ]; then
+ # If MailRoom is already running, don't start it again.
+ if [ "$mail_room_status" = "0" ]; then
+ echo "The MailRoom email processor is already running with pid $mpid, not restarting"
+ else
+ RAILS_ENV=$RAILS_ENV bin/mail_room start &
+ fi
+ fi
+
# Wait for the pids to be planted
wait_for_pids
# Finally check the status to tell wether or not GitLab is running
print_status
}
-## Asks the Unicorn and the Sidekiq if they would be so kind as to stop, if not kills them.
+## Asks Unicorn, Sidekiq and MailRoom if they would be so kind as to stop, if not kills them.
stop_gitlab() {
exit_if_not_running
- if [ "$web_status" = "0" -a "$sidekiq_status" = "0" ]; then
- echo -n "Shutting down both Unicorn and Sidekiq"
- elif [ "$web_status" = "0" ]; then
- echo -n "Shutting down Unicorn"
- elif [ "$sidekiq_status" = "0" ]; then
- echo -n "Shutting down Sidekiq"
+ if [ "$web_status" = "0" ]; then
+ echo "Shutting down GitLab Unicorn"
+ fi
+ if [ "$sidekiq_status" = "0" ]; then
+ echo "Shutting down GitLab Sidekiq"
+ fi
+ if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; then
+ echo "Shutting down GitLab MailRoom"
fi
# If the Unicorn web server is running, tell it to stop;
@@ -205,13 +242,17 @@ stop_gitlab() {
if [ "$sidekiq_status" = "0" ]; then
RAILS_ENV=$RAILS_ENV bin/background_jobs stop
fi
+ # And do the same thing for the MailRoom.
+ if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; then
+ RAILS_ENV=$RAILS_ENV bin/mail_room stop
+ fi
# If something needs to be stopped, lets wait for it to stop. Never use SIGKILL in a script.
- while [ "$web_status" = "0" -o "$sidekiq_status" = "0" ]; do
+ while [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; do
sleep 1
check_status
printf "."
- if [ "$web_status" != "0" -a "$sidekiq_status" != "0" ]; then
+ if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
printf "\n"
break
fi
@@ -220,7 +261,10 @@ stop_gitlab() {
sleep 1
# Cleaning up unused pids
rm "$web_server_pid_path" 2>/dev/null
- # rm "$sidekiq_pid_path" # Sidekiq seems to be cleaning up it's own pid.
+ # rm "$sidekiq_pid_path" 2>/dev/null # Sidekiq seems to be cleaning up it's own pid.
+ if [ "$mail_room_enabled" = true ]; then
+ rm "$mail_room_pid_path" 2>/dev/null
+ fi
print_status
}
@@ -228,7 +272,7 @@ stop_gitlab() {
## Prints the status of GitLab and it's components.
print_status() {
check_status
- if [ "$web_status" != "0" -a "$sidekiq_status" != "0" ]; then
+ if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
echo "GitLab is not running."
return
fi
@@ -242,7 +286,14 @@ print_status() {
else
printf "The GitLab Sidekiq job dispatcher is \033[31mnot running\033[0m.\n"
fi
- if [ "$web_status" = "0" -a "$sidekiq_status" = "0" ]; then
+ if [ "$mail_room_enabled" = true ]; then
+ if [ "$mail_room_status" = "0" ]; then
+ echo "The GitLab MailRoom email processor with pid $mpid is running."
+ else
+ 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
printf "GitLab and all its components are \033[32mup and running\033[0m.\n"
fi
}
@@ -257,9 +308,15 @@ reload_gitlab(){
printf "Reloading GitLab Unicorn configuration... "
RAILS_ENV=$RAILS_ENV bin/web reload
echo "Done."
+
echo "Restarting GitLab Sidekiq since it isn't capable of reloading its config..."
RAILS_ENV=$RAILS_ENV bin/background_jobs restart
+ if [ "$mail_room_enabled" != true ]; then
+ echo "Restarting GitLab MailRoom since it isn't capable of reloading its config..."
+ RAILS_ENV=$RAILS_ENV bin/mail_room restart
+ fi
+
wait_for_pids
print_status
}
@@ -267,7 +324,7 @@ reload_gitlab(){
## Restarts Sidekiq and Unicorn.
restart_gitlab(){
check_status
- if [ "$web_status" = "0" -o "$sidekiq_status" = "0" ]; then
+ if [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; then
stop_gitlab
fi
start_gitlab
diff --git a/lib/support/init.d/gitlab.default.example b/lib/support/init.d/gitlab.default.example
index cf7f4198cbf..fd70cb7cc74 100755
--- a/lib/support/init.d/gitlab.default.example
+++ b/lib/support/init.d/gitlab.default.example
@@ -30,6 +30,15 @@ web_server_pid_path="$pid_path/unicorn.pid"
# The default is "$pid_path/sidekiq.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid"
+# mail_room_enabled specifies whether mail_room, which is used to process incoming email, is enabled.
+# This is required for the Reply by email feature.
+# The default is "false"
+mail_room_enabled=false
+
+# mail_room_pid_path defines the path in which to create the pid file for mail_room
+# The default is "$pid_path/mail_room.pid"
+mail_room_pid_path="$pid_path/mail_room.pid"
+
# shell_path defines the path of shell for "$app_user" in case you are using
# shell other than "bash"
# The default is "/bin/bash"
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 60aa50e8751..2b9688c1b40 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -2,6 +2,7 @@ namespace :gitlab do
desc "GitLab | Check the configuration of GitLab and its environment"
task check: %w{gitlab:gitlab_shell:check
gitlab:sidekiq:check
+ gitlab:reply_by_email:check
gitlab:ldap:check
gitlab:app:check}
@@ -629,6 +630,174 @@ namespace :gitlab do
end
end
+
+ namespace :reply_by_email do
+ desc "GitLab | Check the configuration of Reply by email"
+ task check: :environment do
+ warn_user_is_not_gitlab
+ start_checking "Reply by email"
+
+ if Gitlab.config.reply_by_email.enabled
+ check_address_formatted_correctly
+ check_mail_room_config_exists
+ check_imap_authentication
+
+ if Rails.env.production?
+ check_initd_configured_correctly
+ check_mail_room_running
+ else
+ check_foreman_configured_correctly
+ end
+ else
+ puts 'Reply by email is disabled in config/gitlab.yml'
+ end
+
+ finished_checking "Reply by email"
+ end
+
+
+ # Checks
+ ########################
+
+ def check_address_formatted_correctly
+ print "Address formatted correctly? ... "
+
+ if Gitlab::ReplyByEmail.address_formatted_correctly?
+ puts "yes".green
+ else
+ puts "no".red
+ try_fixing_it(
+ "Make sure that the address in config/gitlab.yml includes the '%{reply_key}' placeholder."
+ )
+ fix_and_rerun
+ end
+ end
+
+ def check_initd_configured_correctly
+ print "Init.d configured correctly? ... "
+
+ path = "/etc/default/gitlab"
+
+ if File.exist?(path) && File.read(path).include?("mail_room_enabled=true")
+ puts "yes".green
+ else
+ puts "no".red
+ try_fixing_it(
+ "Enable mail_room in the init.d configuration."
+ )
+ for_more_information(
+ "doc/reply_by_email/README.md"
+ )
+ fix_and_rerun
+ end
+ end
+
+ def check_foreman_configured_correctly
+ print "Foreman configured correctly? ... "
+
+ path = Rails.root.join("Procfile")
+
+ if File.exist?(path) && File.read(path) =~ /^mail_room:/
+ puts "yes".green
+ else
+ puts "no".red
+ try_fixing_it(
+ "Enable mail_room in your Procfile."
+ )
+ for_more_information(
+ "doc/reply_by_email/README.md"
+ )
+ fix_and_rerun
+ end
+ end
+
+ def check_mail_room_running
+ print "MailRoom running? ... "
+
+ path = "/etc/default/gitlab"
+
+ unless File.exist?(path) && File.read(path).include?("mail_room_enabled=true")
+ puts "can't check because of previous errors".magenta
+ return
+ end
+
+ if mail_room_running?
+ puts "yes".green
+ else
+ puts "no".red
+ try_fixing_it(
+ sudo_gitlab("RAILS_ENV=production bin/mail_room start")
+ )
+ for_more_information(
+ see_installation_guide_section("Install Init Script"),
+ "see log/mail_room.log for possible errors"
+ )
+ fix_and_rerun
+ end
+ end
+
+ def check_mail_room_config_exists
+ print "MailRoom config exists? ... "
+
+ mail_room_config_file = Rails.root.join("config", "mail_room.yml")
+
+ if File.exists?(mail_room_config_file)
+ puts "yes".green
+ else
+ puts "no".red
+ try_fixing_it(
+ "Copy config/mail_room.yml.example to config/mail_room.yml",
+ "Check that the information in config/mail_room.yml is correct"
+ )
+ for_more_information(
+ "doc/reply_by_email/README.md"
+ )
+ fix_and_rerun
+ end
+ end
+
+ def check_imap_authentication
+ print "IMAP server credentials are correct? ... "
+
+ mail_room_config_file = Rails.root.join("config", "mail_room.yml")
+
+ unless File.exists?(mail_room_config_file)
+ puts "can't check because of previous errors".magenta
+ return
+ end
+
+ config = YAML.load_file(mail_room_config_file)[:mailboxes].first rescue nil
+
+ if config
+ begin
+ imap = Net::IMAP.new(config[:host], port: config[:port], ssl: config[:ssl])
+ imap.login(config[:email], config[:password])
+ connected = true
+ rescue
+ connected = false
+ end
+ end
+
+ if connected
+ puts "yes".green
+ else
+ puts "no".red
+ try_fixing_it(
+ "Check that the information in config/mail_room.yml is correct"
+ )
+ for_more_information(
+ "doc/reply_by_email/README.md"
+ )
+ fix_and_rerun
+ end
+ end
+
+ def mail_room_running?
+ ps_ux, _ = Gitlab::Popen.popen(%W(ps ux))
+ ps_ux.include?("mail_room")
+ end
+ end
+
namespace :ldap do
task :check, [:limit] => :environment do |t, args|
# Only show up to 100 results because LDAP directories can be very big.