Commit 41d6b370 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into fix-milestone-snippet-header

parents 4df8477a d60047bb
...@@ -76,7 +76,7 @@ Style/BlockEndNewline: ...@@ -76,7 +76,7 @@ Style/BlockEndNewline:
Description: 'Put end statement of multiline block on its own line.' Description: 'Put end statement of multiline block on its own line.'
Enabled: true Enabled: true
Style/Blocks: Style/BlockDelimiters:
Description: >- Description: >-
Avoid using {...} for multi-line blocks (multiline chaining is Avoid using {...} for multi-line blocks (multiline chaining is
always ugly). always ugly).
...@@ -232,6 +232,10 @@ Style/EvenOdd: ...@@ -232,6 +232,10 @@ Style/EvenOdd:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods'
Enabled: false Enabled: false
Style/ExtraSpacing:
Description: 'Do not use unnecessary spacing.'
Enabled: false
Style/FileName: Style/FileName:
Description: 'Use snake_case for source file names.' Description: 'Use snake_case for source file names.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files'
...@@ -431,6 +435,14 @@ Style/OpMethod: ...@@ -431,6 +435,14 @@ Style/OpMethod:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#other-arg' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#other-arg'
Enabled: false Enabled: false
Style/ParallelAssignment:
Description: >-
Check for simple usages of parallel assignment.
It will only warn when the number of variables
matches on both sides of the assignment.
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parallel-assignment'
Enabled: false
Style/ParenthesesAroundCondition: Style/ParenthesesAroundCondition:
Description: >- Description: >-
Don't use parentheses around the condition of an Don't use parentheses around the condition of an
...@@ -669,6 +681,13 @@ Style/TrailingWhitespace: ...@@ -669,6 +681,13 @@ Style/TrailingWhitespace:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-whitespace' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-whitespace'
Enabled: false Enabled: false
Style/TrailingUnderscoreVariable:
Description: >-
Checks for the usage of unneeded trailing underscores at the
end of parallel variable assignment.
AllowNamedUnderscoreVariables: true
Enabled: false
Style/TrivialAccessors: Style/TrivialAccessors:
Description: 'Prefer attr_* methods to trivial readers/writers.' Description: 'Prefer attr_* methods to trivial readers/writers.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr_family' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr_family'
...@@ -690,11 +709,6 @@ Style/UnneededPercentQ: ...@@ -690,11 +709,6 @@ Style/UnneededPercentQ:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-q' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-q'
Enabled: false Enabled: false
Style/UnneededPercentX:
Description: 'Checks for %x when `` would do.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-x'
Enabled: false
Style/VariableInterpolation: Style/VariableInterpolation:
Description: >- Description: >-
Don't interpolate global, instance and class variables Don't interpolate global, instance and class variables
...@@ -778,6 +792,10 @@ Metrics/MethodLength: ...@@ -778,6 +792,10 @@ Metrics/MethodLength:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#short-methods' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#short-methods'
Enabled: false Enabled: false
Metrics/ModuleLength:
Description: 'Avoid modules longer than 100 lines of code.'
Enabled: false
#################### Lint ################################ #################### Lint ################################
### Warnings ### Warnings
...@@ -961,6 +979,12 @@ Rails/ActionFilter: ...@@ -961,6 +979,12 @@ Rails/ActionFilter:
Description: 'Enforces consistent use of action filter methods.' Description: 'Enforces consistent use of action filter methods.'
Enabled: true Enabled: true
Rails/Date:
Description: >-
Checks the correct usage of date aware methods,
such as Date.today, Date.current etc.
Enabled: false
Rails/DefaultScope: Rails/DefaultScope:
Description: 'Checks if the argument passed to default_scope is a block.' Description: 'Checks if the argument passed to default_scope is a block.'
Enabled: false Enabled: false
...@@ -987,6 +1011,12 @@ Rails/ScopeArgs: ...@@ -987,6 +1011,12 @@ Rails/ScopeArgs:
Description: 'Checks the arguments of ActiveRecord scopes.' Description: 'Checks the arguments of ActiveRecord scopes.'
Enabled: false Enabled: false
Rails/TimeZone:
Description: 'Checks the correct usage of time zone aware methods.'
StyleGuide: 'https://github.com/bbatsov/rails-style-guide#time'
Reference: 'http://danilenko.org/2012/7/6/rails_timezones'
Enabled: false
Rails/Validation: Rails/Validation:
Description: 'Use validates :attribute, hash of validations.' Description: 'Use validates :attribute, hash of validations.'
Enabled: false Enabled: false
......
...@@ -62,8 +62,6 @@ v 8.2.3 ...@@ -62,8 +62,6 @@ v 8.2.3
- Update documentation for "Guest" permissions - Update documentation for "Guest" permissions
- Properly convert Emoji-only comments into Award Emojis - Properly convert Emoji-only comments into Award Emojis
- Enable devise paranoid mode to prevent user enumeration attack - Enable devise paranoid mode to prevent user enumeration attack
v 8.2.3
- Webhook payload has an added, modified and removed properties for each commit - Webhook payload has an added, modified and removed properties for each commit
- Fix 500 error when creating a merge request that removes a submodule - Fix 500 error when creating a merge request that removes a submodule
......
...@@ -261,7 +261,7 @@ group :development, :test do ...@@ -261,7 +261,7 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.0.0' gem 'spring-commands-spinach', '~> 1.0.0'
gem 'spring-commands-teaspoon', '~> 0.0.2' gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.28.0', require: false gem 'rubocop', '~> 0.35.0', require: false
gem 'coveralls', '~> 0.8.2', require: false gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.10.0', require: false gem 'simplecov', '~> 0.10.0', require: false
gem 'flog', require: false gem 'flog', require: false
......
...@@ -513,7 +513,7 @@ GEM ...@@ -513,7 +513,7 @@ GEM
multi_json (~> 1.0) multi_json (~> 1.0)
websocket-driver (>= 0.2.0) websocket-driver (>= 0.2.0)
posix-spawn (0.3.11) posix-spawn (0.3.11)
powerpack (0.0.9) powerpack (0.1.1)
pry (0.10.3) pry (0.10.3)
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
...@@ -637,12 +637,13 @@ GEM ...@@ -637,12 +637,13 @@ GEM
rspec-mocks (~> 3.3.0) rspec-mocks (~> 3.3.0)
rspec-support (~> 3.3.0) rspec-support (~> 3.3.0)
rspec-support (3.3.0) rspec-support (3.3.0)
rubocop (0.28.0) rubocop (0.35.1)
astrolabe (~> 1.3) astrolabe (~> 1.3)
parser (>= 2.2.0.pre.7, < 3.0) parser (>= 2.2.3.0, < 3.0)
powerpack (~> 0.0.6) powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0) rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.4) ruby-progressbar (~> 1.7)
tins (<= 1.6.0)
ruby-fogbugz (0.2.1) ruby-fogbugz (0.2.1)
crack (~> 0.4) crack (~> 0.4)
ruby-progressbar (1.7.5) ruby-progressbar (1.7.5)
...@@ -945,7 +946,7 @@ DEPENDENCIES ...@@ -945,7 +946,7 @@ DEPENDENCIES
rouge (~> 1.10.1) rouge (~> 1.10.1)
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.3.0) rspec-rails (~> 3.3.0)
rubocop (~> 0.28.0) rubocop (~> 0.35.0)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
sanitize (~> 2.0) sanitize (~> 2.0)
sass-rails (~> 4.0.5) sass-rails (~> 4.0.5)
......
...@@ -401,6 +401,11 @@ table { ...@@ -401,6 +401,11 @@ table {
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
height: 57px; height: 57px;
} }
&.wide {
margin-left: -$gl-padding;
margin-right: -$gl-padding;
}
} }
.center-middle-menu { .center-middle-menu {
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
.panel-heading { .panel-heading {
padding: 7px $gl-padding; padding: 7px $gl-padding;
line-height: 42px !important;
} }
.panel-body { .panel-body {
...@@ -15,3 +14,7 @@ ...@@ -15,3 +14,7 @@
} }
} }
} }
.container-blank .panel .panel-heading {
line-height: 42px !important;
}
...@@ -19,7 +19,7 @@ $border-color: #dce0e6; ...@@ -19,7 +19,7 @@ $border-color: #dce0e6;
$table-border-color: #eef0f2; $table-border-color: #eef0f2;
$background-color: #F7F8FA; $background-color: #F7F8FA;
$header-height: 58px; $header-height: 58px;
$fixed-layout-width: 1200px; $fixed-layout-width: 1280px;
$gl-gray: #7f8fa4; $gl-gray: #7f8fa4;
$gl-padding: 16px; $gl-padding: 16px;
$gl-avatar-size: 46px; $gl-avatar-size: 46px;
......
...@@ -191,7 +191,7 @@ ...@@ -191,7 +191,7 @@
.btn-clipboard { .btn-clipboard {
@extend .pull-right; @extend .pull-right;
margin-right: 18px; margin-right: 20px;
margin-top: 5px; margin-top: 5px;
position: absolute; position: absolute;
right: 0; right: 0;
......
class Dashboard::SnippetsController < Dashboard::ApplicationController class Dashboard::SnippetsController < Dashboard::ApplicationController
def index def index
@snippets = SnippetsFinder.new.execute(current_user, @snippets = SnippetsFinder.new.execute(
current_user,
filter: :by_user, filter: :by_user,
user: current_user, user: current_user,
scope: params[:scope] scope: params[:scope]
......
...@@ -69,7 +69,7 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -69,7 +69,7 @@ class Projects::NotesController < Projects::ApplicationController
data = { data = {
author: current_user, author: current_user,
is_award: true, is_award: true,
note: note_params[:note].gsub(":", '') note: note_params[:note].delete(":")
} }
note = noteable.notes.find_by(data) note = noteable.notes.find_by(data)
......
...@@ -61,7 +61,7 @@ module ApplicationHelper ...@@ -61,7 +61,7 @@ module ApplicationHelper
options[:class] ||= '' options[:class] ||= ''
options[:class] << ' identicon' options[:class] << ' identicon'
bg_key = project.id % 7 bg_key = project.id % 7
style = "background-color: ##{ allowed_colors.values[bg_key] }; color: #555" style = "background-color: ##{allowed_colors.values[bg_key]}; color: #555"
content_tag(:div, class: options[:class], style: style) do content_tag(:div, class: options[:class], style: style) do
project.name[0, 1].upcase project.name[0, 1].upcase
...@@ -204,12 +204,16 @@ module ApplicationHelper ...@@ -204,12 +204,16 @@ module ApplicationHelper
# Returns an HTML-safe String # Returns an HTML-safe String
def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false) def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false)
element = content_tag :time, time.to_s, element = content_tag :time, time.to_s,
class: "#{html_class} js-timeago", class: "#{html_class} js-timeago js-timeago-pending",
datetime: time.getutc.iso8601, datetime: time.getutc.iso8601,
title: time.in_time_zone.stamp('Aug 21, 2011 9:23pm'), title: time.in_time_zone.stamp('Aug 21, 2011 9:23pm'),
data: { toggle: 'tooltip', placement: placement, container: 'body' } data: { toggle: 'tooltip', placement: placement, container: 'body' }
element += javascript_tag "$('.js-timeago').last().timeago()" unless skip_js unless skip_js
element << javascript_tag(
"$('.js-timeago-pending').removeClass('js-timeago-pending').timeago()"
)
end
element element
end end
......
...@@ -10,8 +10,8 @@ module ButtonHelper ...@@ -10,8 +10,8 @@ module ButtonHelper
# # => "<button class='...' data-clipboard-text='Foo'>...</button>" # # => "<button class='...' data-clipboard-text='Foo'>...</button>"
# #
# # Define the target element # # Define the target element
# clipboard_button(clipboard_target: "#foo") # clipboard_button(clipboard_target: "div#foo")
# # => "<button class='...' data-clipboard-target='#foo'>...</button>" # # => "<button class='...' data-clipboard-target='div#foo'>...</button>"
# #
# See http://clipboardjs.com/#usage # See http://clipboardjs.com/#usage
def clipboard_button(data = {}) def clipboard_button(data = {})
......
module ExternalWikiHelper module ExternalWikiHelper
def get_project_wiki_path(project) def get_project_wiki_path(project)
external_wiki_service = project.services. external_wiki_service = project.services.
select { |service| service.to_param == 'external_wiki' }.first find { |service| service.to_param == 'external_wiki' }
if external_wiki_service.present? && external_wiki_service.active? if external_wiki_service.present? && external_wiki_service.active?
external_wiki_service.properties['external_wiki_url'] external_wiki_service.properties['external_wiki_url']
else else
......
...@@ -20,7 +20,7 @@ module GitlabMarkdownHelper ...@@ -20,7 +20,7 @@ module GitlabMarkdownHelper
end end
user = current_user if defined?(current_user) user = current_user if defined?(current_user)
gfm_body = Gitlab::Markdown.render(escaped_body, project: @project, current_user: user, pipeline: :single_line) gfm_body = Banzai.render(escaped_body, project: @project, current_user: user, pipeline: :single_line)
fragment = Nokogiri::HTML::DocumentFragment.parse(gfm_body) fragment = Nokogiri::HTML::DocumentFragment.parse(gfm_body)
if fragment.children.size == 1 && fragment.children[0].name == 'a' if fragment.children.size == 1 && fragment.children[0].name == 'a'
...@@ -50,7 +50,7 @@ module GitlabMarkdownHelper ...@@ -50,7 +50,7 @@ module GitlabMarkdownHelper
context[:project] ||= @project context[:project] ||= @project
html = Gitlab::Markdown.render(text, context) html = Banzai.render(text, context)
context.merge!( context.merge!(
current_user: (current_user if defined?(current_user)), current_user: (current_user if defined?(current_user)),
...@@ -61,11 +61,12 @@ module GitlabMarkdownHelper ...@@ -61,11 +61,12 @@ module GitlabMarkdownHelper
ref: @ref ref: @ref
) )
Gitlab::Markdown.post_process(html, context) Banzai.post_process(html, context)
end end
def asciidoc(text) def asciidoc(text)
Gitlab::Asciidoc.render(text, Gitlab::Asciidoc.render(
text,
project: @project, project: @project,
current_user: (current_user if defined?(current_user)), current_user: (current_user if defined?(current_user)),
......
...@@ -121,6 +121,6 @@ module IssuesHelper ...@@ -121,6 +121,6 @@ module IssuesHelper
end end
end end
# Required for Gitlab::Markdown::IssueReferenceFilter # Required for Banzai::Filter::IssueReferenceFilter
module_function :url_for_issue module_function :url_for_issue
end end
...@@ -107,6 +107,6 @@ module LabelsHelper ...@@ -107,6 +107,6 @@ module LabelsHelper
options_from_collection_for_select(grouped_labels, 'name', 'title', params[:label_name]) options_from_collection_for_select(grouped_labels, 'name', 'title', params[:label_name])
end end
# Required for Gitlab::Markdown::LabelReferenceFilter # Required for Banzai::Filter::LabelReferenceFilter
module_function :render_colored_label, :text_color_for_bg, :escape_once module_function :render_colored_label, :text_color_for_bg, :escape_once
end end
...@@ -332,8 +332,7 @@ module ProjectsHelper ...@@ -332,8 +332,7 @@ module ProjectsHelper
namespace_project_blob_path( namespace_project_blob_path(
project.namespace, project.namespace,
project, project,
tree_join(project.default_branch, tree_join(project.default_branch, blob.name)
blob.name)
) )
end end
end end
......
...@@ -79,7 +79,7 @@ module TreeHelper ...@@ -79,7 +79,7 @@ module TreeHelper
part_path = File.join(part_path, part) unless part_path.empty? part_path = File.join(part_path, part) unless part_path.empty?
part_path = part if part_path.empty? part_path = part if part_path.empty?
next unless parts.last(2).include?(part) if parts.count > max_links next if parts.count > max_links && !parts.last(2).include?(part)
yield(part, tree_join(@ref, part_path)) yield(part, tree_join(@ref, part_path))
end end
end end
......
...@@ -23,7 +23,7 @@ module Mentionable ...@@ -23,7 +23,7 @@ module Mentionable
included do included do
if self < Participable if self < Participable
participant ->(current_user) { mentioned_users(current_user, load_lazy_references: false) } participant ->(current_user) { mentioned_users(current_user) }
end end
end end
...@@ -43,8 +43,8 @@ module Mentionable ...@@ -43,8 +43,8 @@ module Mentionable
self self
end end
def all_references(current_user = self.author, text = nil, load_lazy_references: true) def all_references(current_user = self.author, text = nil)
ext = Gitlab::ReferenceExtractor.new(self.project, current_user, load_lazy_references: load_lazy_references) ext = Gitlab::ReferenceExtractor.new(self.project, current_user)
if text if text
ext.analyze(text) ext.analyze(text)
...@@ -59,13 +59,13 @@ module Mentionable ...@@ -59,13 +59,13 @@ module Mentionable
ext ext
end end
def mentioned_users(current_user = nil, load_lazy_references: true) def mentioned_users(current_user = nil)
all_references(current_user, load_lazy_references: load_lazy_references).users all_references(current_user).users
end end
# Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference. # Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
def referenced_mentionables(current_user = self.author, text = nil, load_lazy_references: true) def referenced_mentionables(current_user = self.author, text = nil)
refs = all_references(current_user, text, load_lazy_references: load_lazy_references) refs = all_references(current_user, text)
refs = (refs.issues + refs.merge_requests + refs.commits) refs = (refs.issues + refs.merge_requests + refs.commits)
# We're using this method instead of Array diffing because that requires # We're using this method instead of Array diffing because that requires
......
...@@ -38,7 +38,9 @@ module Participable ...@@ -38,7 +38,9 @@ module Participable
# Be aware that this method makes a lot of sql queries. # Be aware that this method makes a lot of sql queries.
# Save result into variable if you are going to reuse it inside same request # Save result into variable if you are going to reuse it inside same request
def participants(current_user = self.author, load_lazy_references: true) def participants(current_user = self.author, load_lazy_references: true)
participants = self.class.participant_attrs.flat_map do |attr| participants =
Gitlab::ReferenceExtractor.lazily do
self.class.participant_attrs.flat_map do |attr|
value = value =
if attr.respond_to?(:call) if attr.respond_to?(:call)
instance_exec(current_user, &attr) instance_exec(current_user, &attr)
...@@ -48,10 +50,9 @@ module Participable ...@@ -48,10 +50,9 @@ module Participable
participants_for(value, current_user) participants_for(value, current_user)
end.compact.uniq end.compact.uniq
end
if load_lazy_references unless Gitlab::ReferenceExtractor.lazy?
participants = Gitlab::Markdown::ReferenceFilter::LazyReference.load(participants).uniq
participants.select! do |user| participants.select! do |user|
user.can?(:read_project, project) user.can?(:read_project, project)
end end
...@@ -64,12 +65,12 @@ module Participable ...@@ -64,12 +65,12 @@ module Participable
def participants_for(value, current_user = nil) def participants_for(value, current_user = nil)
case value case value
when User, Gitlab::Markdown::ReferenceFilter::LazyReference when User, Banzai::LazyReference
[value] [value]
when Enumerable, ActiveRecord::Relation when Enumerable, ActiveRecord::Relation
value.flat_map { |v| participants_for(v, current_user) } value.flat_map { |v| participants_for(v, current_user) }
when Participable when Participable
value.participants(current_user, load_lazy_references: false) value.participants(current_user)
end end
end end
end end
...@@ -13,7 +13,7 @@ module TokenAuthenticatable ...@@ -13,7 +13,7 @@ module TokenAuthenticatable
@token_fields << token_field @token_fields << token_field
define_singleton_method("find_by_#{token_field}") do |token| define_singleton_method("find_by_#{token_field}") do |token|
where(token_field => token).first if token find_by(token_field => token) if token
end end
define_method("ensure_#{token_field}") do define_method("ensure_#{token_field}") do
...@@ -37,7 +37,7 @@ module TokenAuthenticatable ...@@ -37,7 +37,7 @@ module TokenAuthenticatable
def generate_token_for(token_field) def generate_token_for(token_field)
loop do loop do
token = Devise.friendly_token token = Devise.friendly_token
break token unless self.class.unscoped.where(token_field => token).first break token unless self.class.unscoped.find_by(token_field => token)
end end
end end
end end
...@@ -84,11 +84,11 @@ class Issue < ActiveRecord::Base ...@@ -84,11 +84,11 @@ class Issue < ActiveRecord::Base
end end
def referenced_merge_requests def referenced_merge_requests
references = [self, *notes].flat_map do |note| Gitlab::ReferenceExtractor.lazily do
[self, *notes].flat_map do |note|
note.all_references(load_lazy_references: false).merge_requests note.all_references(load_lazy_references: false).merge_requests
end.uniq end
end.sort_by(&:iid)
Gitlab::Markdown::ReferenceFilter::LazyReference.load(references).uniq.sort_by(&:iid)
end end
# Reset issue events cache # Reset issue events cache
......
...@@ -194,9 +194,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -194,9 +194,7 @@ class MergeRequest < ActiveRecord::Base
similar_mrs = similar_mrs.where('id not in (?)', self.id) if self.id similar_mrs = similar_mrs.where('id not in (?)', self.id) if self.id
if similar_mrs.any? if similar_mrs.any?
errors.add :validate_branches, errors.add :validate_branches,
"Cannot Create: This merge request already exists: #{ "Cannot Create: This merge request already exists: #{similar_mrs.pluck(:title)}"
similar_mrs.pluck(:title)
}"
end end
end end
end end
......
...@@ -45,7 +45,7 @@ class Namespace < ActiveRecord::Base ...@@ -45,7 +45,7 @@ class Namespace < ActiveRecord::Base
class << self class << self
def by_path(path) def by_path(path)
where('lower(path) = :value', value: path.downcase).first find_by('lower(path) = :value', value: path.downcase)
end end
# Case insensetive search for namespace by path or name # Case insensetive search for namespace by path or name
...@@ -148,6 +148,6 @@ class Namespace < ActiveRecord::Base ...@@ -148,6 +148,6 @@ class Namespace < ActiveRecord::Base
end end
def find_fork_of(project) def find_fork_of(project)
projects.joins(:forked_project_link).where('forked_project_links.forked_from_project_id = ?', project.id).first projects.joins(:forked_project_link).find_by('forked_project_links.forked_from_project_id = ?', project.id)
end end
end end
...@@ -373,11 +373,11 @@ class Note < ActiveRecord::Base ...@@ -373,11 +373,11 @@ class Note < ActiveRecord::Base
end end
def contains_emoji_only? def contains_emoji_only?
note =~ /\A#{Gitlab::Markdown::EmojiFilter.emoji_pattern}\s?\Z/ note =~ /\A#{Banzai::Filter::EmojiFilter.emoji_pattern}\s?\Z/
end end
def award_emoji_name def award_emoji_name
original_name = note.match(Gitlab::Markdown::EmojiFilter.emoji_pattern)[1] original_name = note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1]
AwardEmoji.normilize_emoji_name(original_name) AwardEmoji.normilize_emoji_name(original_name)
end end
end end
...@@ -265,7 +265,7 @@ class Project < ActiveRecord::Base ...@@ -265,7 +265,7 @@ class Project < ActiveRecord::Base
joins(:namespace). joins(:namespace).
iwhere('namespaces.path' => namespace_path) iwhere('namespaces.path' => namespace_path)
projects.where('projects.path' => project_path).take || projects.find_by('projects.path' => project_path) ||
projects.iwhere('projects.path' => project_path).take projects.iwhere('projects.path' => project_path).take
end end
...@@ -450,7 +450,7 @@ class Project < ActiveRecord::Base ...@@ -450,7 +450,7 @@ class Project < ActiveRecord::Base
end end
def external_issue_tracker def external_issue_tracker
@external_issues_tracker ||= external_issues_trackers.select(&:activated?).first @external_issues_tracker ||= external_issues_trackers.find(&:activated?)
end end
def can_have_issues_tracker_id? def can_have_issues_tracker_id?
...@@ -496,7 +496,7 @@ class Project < ActiveRecord::Base ...@@ -496,7 +496,7 @@ class Project < ActiveRecord::Base
end end
def ci_service def ci_service
@ci_service ||= ci_services.select(&:activated?).first @ci_service ||= ci_services.find(&:activated?)
end end
def avatar_type def avatar_type
...@@ -547,7 +547,7 @@ class Project < ActiveRecord::Base ...@@ -547,7 +547,7 @@ class Project < ActiveRecord::Base
end end
def project_member_by_name_or_email(name = nil, email = nil) def project_member_by_name_or_email(name = nil, email = nil)
user = users.where('name like ? or email like ?', name, email).first user = users.find_by('name like ? or email like ?', name, email)
project_members.where(user: user) if user project_members.where(user: user) if user
end end
...@@ -722,7 +722,7 @@ class Project < ActiveRecord::Base ...@@ -722,7 +722,7 @@ class Project < ActiveRecord::Base
end end
def project_member(user) def project_member(user)
project_members.where(user_id: user).first project_members.find_by(user_id: user)
end end
def default_branch def default_branch
......
...@@ -27,12 +27,10 @@ class BambooService < CiService ...@@ -27,12 +27,10 @@ class BambooService < CiService
validates :build_key, presence: true, if: :activated? validates :build_key, presence: true, if: :activated?
validates :username, validates :username,
presence: true, presence: true,
if: ->(service) { service.password? }, if: ->(service) { service.activated? && service.password }
if: :activated?
validates :password, validates :password,
presence: true, presence: true,
if: ->(service) { service.username? }, if: ->(service) { service.activated? && service.username }
if: :activated?
attr_accessor :response attr_accessor :response
......
...@@ -27,12 +27,10 @@ class TeamcityService < CiService ...@@ -27,12 +27,10 @@ class TeamcityService < CiService
validates :build_type, presence: true, if: :activated? validates :build_type, presence: true, if: :activated?
validates :username, validates :username,
presence: true, presence: true,
if: ->(service) { service.password? }, if: ->(service) { service.activated? && service.password }
if: :activated?
validates :password, validates :password,
presence: true, presence: true,
if: ->(service) { service.username? }, if: ->(service) { service.activated? && service.username }
if: :activated?
attr_accessor :response attr_accessor :response
......
...@@ -220,9 +220,9 @@ class User < ActiveRecord::Base ...@@ -220,9 +220,9 @@ class User < ActiveRecord::Base
def find_for_database_authentication(warden_conditions) def find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup conditions = warden_conditions.dup
if login = conditions.delete(:login) if login = conditions.delete(:login)
where(conditions).where(["lower(username) = :value OR lower(email) = :value", { value: login.downcase }]).first where(conditions).find_by("lower(username) = :value OR lower(email) = :value", value: login.downcase)
else else
where(conditions).first find_by(conditions)
end end
end end
...@@ -285,7 +285,7 @@ class User < ActiveRecord::Base ...@@ -285,7 +285,7 @@ class User < ActiveRecord::Base
end end
def by_username_or_id(name_or_id) def by_username_or_id(name_or_id)
where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first find_by('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i)
end end
def build_user(attrs = {}) def build_user(attrs = {})
......
%div
"#{link_to @note.author_name, user_url(@note.author)} wrote:"
%div %div
= markdown(@note.note, pipeline: :email) = markdown(@note.note, pipeline: :email)
...@@ -20,8 +20,8 @@ ...@@ -20,8 +20,8 @@
%p %p
%span.light Commit %span.light Commit
= link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace", data: { clipboard_text: @commit.id } = link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
= clipboard_button = clipboard_button(clipboard_text: @commit.id)
.commit-info-row .commit-info-row
%span.light Authored by %span.light Authored by
%strong %strong
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
%p %p
%strong Step 1. %strong Step 1.
Fetch and check out the branch for this merge request Fetch and check out the branch for this merge request
= clipboard_button = clipboard_button(clipboard_target: 'pre#merge-info-1')
%pre.dark %pre.dark#merge-info-1
- if @merge_request.for_fork? - if @merge_request.for_fork?
:preserve :preserve
git fetch #{h @merge_request.source_project.http_url_to_repo} #{h @merge_request.source_branch} git fetch #{h @merge_request.source_project.http_url_to_repo} #{h @merge_request.source_branch}
...@@ -25,8 +25,8 @@ ...@@ -25,8 +25,8 @@
%p %p
%strong Step 3. %strong Step 3.
Merge the branch and fix any conflicts that come up Merge the branch and fix any conflicts that come up
= clipboard_button = clipboard_button(clipboard_target: 'pre#merge-info-3')
%pre.dark %pre.dark#merge-info-3
- if @merge_request.for_fork? - if @merge_request.for_fork?
:preserve :preserve
git checkout #{h @merge_request.target_branch} git checkout #{h @merge_request.target_branch}
...@@ -38,8 +38,8 @@ ...@@ -38,8 +38,8 @@
%p %p
%strong Step 4. %strong Step 4.
Push the result of the merge to GitLab Push the result of the merge to GitLab
= clipboard_button = clipboard_button(clipboard_target: 'pre#merge-info-4')
%pre.dark %pre.dark#merge-info-4
:preserve :preserve
git push origin #{h @merge_request.target_branch} git push origin #{h @merge_request.target_branch}
- unless @merge_request.can_be_merged_by?(current_user) - unless @merge_request.can_be_merged_by?(current_user)
......
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
.user-calendar-activities .user-calendar-activities
%ul.center-top-menu.no-top.no-bottom.bottom-border %ul.center-top-menu.no-top.no-bottom.bottom-border.wide
%li.active %li.active
= link_to "#activity", 'data-toggle' => 'tab' do = link_to "#activity", 'data-toggle' => 'tab' do
Activity Activity
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
- [GitLab Basics](gitlab-basics/README.md) Find step by step how to start working on your commandline and on GitLab. - [GitLab Basics](gitlab-basics/README.md) Find step by step how to start working on your commandline and on GitLab.
- [Importing to GitLab](workflow/importing/README.md). - [Importing to GitLab](workflow/importing/README.md).
- [Markdown](markdown/markdown.md) GitLab's advanced formatting system. - [Markdown](markdown/markdown.md) GitLab's advanced formatting system.
- [Migrating from SVN](migration/README.md) Convert a SVN repository to Git and GitLab
- [Permissions](permissions/permissions.md) Learn what each role in a project (guest/reporter/developer/master/owner) can do. - [Permissions](permissions/permissions.md) Learn what each role in a project (guest/reporter/developer/master/owner) can do.
- [Profile Settings](profile/README.md) - [Profile Settings](profile/README.md)
- [Project Services](project_services/project_services.md) Integrate a project with external services, such as CI and chat. - [Project Services](project_services/project_services.md) Integrate a project with external services, such as CI and chat.
......
...@@ -348,7 +348,7 @@ GitLab Shell is an SSH access and repository management software developed speci ...@@ -348,7 +348,7 @@ GitLab Shell is an SSH access and repository management software developed speci
cd /home/git cd /home/git
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
cd gitlab-workhorse cd gitlab-workhorse
sudo -u git -H git checkout 0.4.2 sudo -u git -H git checkout 0.5.0
sudo -u git -H make sudo -u git -H make
### Initialize Database and Activate Advanced Features ### Initialize Database and Activate Advanced Features
......
# Rake tasks # Rake tasks
- [Backup restore](backup_restore.md) - [Backup restore](backup_restore.md)
- [Check](check.md)
- [Cleanup](cleanup.md) - [Cleanup](cleanup.md)
- [Features](features.md) - [Features](features.md)
- [Maintenance](maintenance.md) and self-checks - [Maintenance](maintenance.md) and self-checks
......
# Check Rake Tasks
## Repository Integrity
Even though Git is very resilient and tries to prevent data integrity issues,
there are times when things go wrong. The following Rake tasks intend to
help GitLab administrators diagnose problem repositories so they can be fixed.
There are 3 things that are checked to determine integrity.
1. Git repository file system check ([git fsck](https://git-scm.com/docs/git-fsck)).
This step verifies the connectivity and validity of objects in the repository.
1. Check for `config.lock` in the repository directory.
1. Check for any branch/references lock files in `refs/heads`.
It's important to note that the existence of `config.lock` or reference locks
alone do not necessarily indicate a problem. Lock files are routinely created
and removed as Git and GitLab perform operations on the repository. They serve
to prevent data integrity issues. However, if a Git operation is interrupted these
locks may not be cleaned up properly.
The following symptoms may indicate a problem with repository integrity. If users
experience these symptoms you may use the rake tasks described below to determine
exactly which repositories are causing the trouble.
- Receiving an error when trying to push code - `remote: error: cannot lock ref`
- A 500 error when viewing the GitLab dashboard or when accessing a specific project.
### Check all GitLab repositories
This task loops through all repositories on the GitLab server and runs the
3 integrity checks described previously.
```
# omnibus-gitlab
sudo gitlab-rake gitlab:repo:check
# installation from source
bundle exec rake gitlab:repo:check RAILS_ENV=production
```
### Check repositories for a specific user
This task checks all repositories that a specific user has access to. This is important
because sometimes you know which user is experiencing trouble but you don't know
which project might be the cause.
If the rake task is executed without brackets at the end, you will be prompted
to enter a username.
```bash
# omnibus-gitlab
sudo gitlab-rake gitlab:user:check_repos
sudo gitlab-rake gitlab:user:check_repos[<username>]
# installation from source
bundle exec rake gitlab:user:check_repos RAILS_ENV=production
bundle exec rake gitlab:user:check_repos[<username>] RAILS_ENV=production
```
Example output:
![gitlab:user:check_repos output](check_repos_output.png)
...@@ -78,7 +78,7 @@ which should already be on your system from GitLab 8.1. ...@@ -78,7 +78,7 @@ which should already be on your system from GitLab 8.1.
```bash ```bash
cd /home/git/gitlab-workhorse cd /home/git/gitlab-workhorse
sudo -u git -H git fetch --all sudo -u git -H git fetch --all
sudo -u git -H git checkout 0.4.2 sudo -u git -H git checkout 0.5.0
sudo -u git -H make sudo -u git -H make
``` ```
...@@ -115,6 +115,12 @@ git diff origin/8-2-stable:config/gitlab.yml.example origin/8-3-stable:config/gi ...@@ -115,6 +115,12 @@ git diff origin/8-2-stable:config/gitlab.yml.example origin/8-3-stable:config/gi
#### Nginx configuration #### Nginx configuration
GitLab 8.3 introduces major changes in the NGINX configuration.
Because all HTTP requests pass through gitlab-workhorse now a lot of
directives need to be removed from NGINX. During future upgrades there
should be much less changes in the NGINX configuration because of
this.
View changes between the previous recommended Nginx configuration and the View changes between the previous recommended Nginx configuration and the
current one: current one:
...@@ -134,6 +140,18 @@ via [/etc/default/gitlab]. ...@@ -134,6 +140,18 @@ via [/etc/default/gitlab].
[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache [Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache
[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-3-stable/lib/support/init.d/gitlab.default.example#L34 [/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-3-stable/lib/support/init.d/gitlab.default.example#L34
#### Init script
We updated the init script for GitLab in order to pass new
configuration options to gitlab-workhorse. We let gitlab-workhorse
connect to the Rails application via a Unix domain socket and we tell
it where the 'public' directory of GitLab is.
```
cd /home/git/gitlab
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
```
### 8. Use Redis v2.8.0+ ### 8. Use Redis v2.8.0+
Previous versions of GitLab allowed Redis versions >= 2.0 to be used, but Previous versions of GitLab allowed Redis versions >= 2.0 to be used, but
......
...@@ -19,3 +19,4 @@ ...@@ -19,3 +19,4 @@
- ["Work In Progress" Merge Requests](wip_merge_requests.md) - ["Work In Progress" Merge Requests](wip_merge_requests.md)
- [Merge When Build Succeeds](merge_when_build_succeeds.md) - [Merge When Build Succeeds](merge_when_build_succeeds.md)
- [Manage large binaries with Git LFS](lfs/manage_large_binaries_with_git_lfs.md) - [Manage large binaries with Git LFS](lfs/manage_large_binaries_with_git_lfs.md)
- [Importing from SVN, GitHub, BitBucket, etc](importing/README.md)
# Migrating projects to a GitLab instance # Migrating projects to a GitLab instance
1. [Bitbucket](import_projects_from_bitbucket.md) 1. [Bitbucket](import_projects_from_bitbucket.md)
2. [GitHub](import_projects_from_github.md) 1. [GitHub](import_projects_from_github.md)
3. [GitLab.com](import_projects_from_gitlab_com.md) 1. [GitLab.com](import_projects_from_gitlab_com.md)
4. [FogBugz](import_projects_from_fogbugz.md) 1. [FogBugz](import_projects_from_fogbugz.md)
4. [SVN](migrating_from_svn.md) 1. [SVN](migrating_from_svn.md)
### Note In addition to the specific migration documentation above, you can import any
* If you'd like to migrate from a self-hosted GitLab instance to GitLab.com, you can copy your repos by changing the remote and pushing to the new server; but issues and merge requests can't be imported. Git repository via HTTP from the New Project page. Be aware that if the
repository is too large the import can timeout.
### Migrating from self-hosted GitLab to GitLab.com
You can copy your repos by changing the remote and pushing to the new server;
but issues and merge requests can't be imported.
* You can import any Git repository via HTTP from the New Project page.
If the repository is too large, it can timeout.
# Migrating from SVN to GitLab # Migrating from SVN to GitLab
SVN stands for Subversion and is a version control system (VCS). Subversion (SVN) is a central version control system (VCS) while
Git is a distributed version control system. Git is a distributed version control system. There are some major differences
between the two, for more information consult your favorite search engine.
There are some major differences between the two, for more information consult your favorite search engine. If you are currently using an SVN repository, you can migrate the repository
to Git and GitLab. We recommend a hard cut over - run the migration command once
and then have all developers start using the new GitLab repository immediately.
Otherwise, it's hard to keep changing in sync in both directions. The conversion
process should be run on a local workstation.
Git has tools for migrating SVN repositories to git, namely `git svn`. You can read more about this at Install `svn2git`. On all systems you can install as a Ruby gem if you already
[git documentation pages](https://git-scm.com/book/en/Git-and-Other-Systems-Git-and-Subversion). have Ruby and Git installed.
Apart from the [official git documentation](https://git-scm.com/book/en/Git-and-Other-Systems-Migrating-to-Git) there is also ```bash
user created step by step guide for migrating from SVN to GitLab. sudo gem install svn2git
```
[Benjamin New](https://github.com/leftclickben) wrote [a guide that shows how to do a migration](https://gist.github.com/leftclickben/322b7a3042cbe97ed2af). Mirrors can be found [here](https://gitlab.com/snippets/2168) and [here](https://gist.github.com/maxlazio/f1b593b0d00aa966e9ca). On Debian-based Linux distributions you can install the native packages:
```bash
sudo apt-get install git-core git-svn ruby
```
Optionally, prepare an authors file so `svn2git` can map SVN authors to Git authors.
If you choose not to create the authors file then commits will not be attributed
to the correct GitLab user. Some users may not consider this a big issue while
others will want to ensure they complete this step. If you choose to map authors
you will be required to map every author that is present on changes in the SVN
repository. If you don't, the conversion will fail and you will have to update
the author file accordingly. The following command will search through the
repository and output a list of authors.
```bash
svn log --quiet | grep -E "r[0-9]+ \| .+ \|" | cut -d'|' -f2 | sed 's/ //g' | sort | uniq
```
Use the output from the last command to construct the authors file.
Create a file called `authors.txt` and add one mapping per line.
```
janedoe = Jane Doe <janedoe@example.com>
johndoe = John Doe <johndoe@example.com>
```
If your SVN repository is in the standard format (trunk, branches, tags,
not nested) the conversion is simple. For a non-standard repository see
[svn2git documentation](https://github.com/nirvdrum/svn2git). The following
command will checkout the repository and do the conversion in the current
working directory. Be sure to create a new directory for each repository before
running the `svn2git` command. The conversion process will take some time.
```bash
svn2git https://svn.example.com/path/to/repo --authors /path/to/authors.txt
```
If your SVN repository requires a username and password add the
`--username <username>` and `--password <password` flags to the above command.
`svn2git` also supports excluding certain file paths, branches, tags, etc. See
[svn2git documentation](https://github.com/nirvdrum/svn2git) or run
`svn2git --help` for full documentation on all of the available options.
Create a new GitLab project, where you will eventually push your converted code.
Copy the SSH or HTTP(S) repository URL from the project page. Add the GitLab
repository as a Git remote and push all the changes. This will push all commits,
branches and tags.
```bash
git remote add origin git@gitlab.com:<group>/<project>.git
git push --all origin
```
## Contribute to this guide ## Contribute to this guide
We welcome all contributions that would expand this guide with instructions on how to migrate from SVN and other version control systems. We welcome all contributions that would expand this guide with instructions on
how to migrate from SVN and other version control systems.
...@@ -85,7 +85,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps ...@@ -85,7 +85,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
step 'I should see new group "Owned" avatar' do step 'I should see new group "Owned" avatar' do
expect(owned_group.avatar).to be_instance_of AvatarUploader expect(owned_group.avatar).to be_instance_of AvatarUploader
expect(owned_group.avatar.url).to eq "/uploads/group/avatar/#{ Group.find_by(name:"Owned").id }/banana_sample.gif" expect(owned_group.avatar.url).to eq "/uploads/group/avatar/#{Group.find_by(name:"Owned").id}/banana_sample.gif"
end end
step 'I should see the "Remove avatar" button' do step 'I should see the "Remove avatar" button' do
......
...@@ -34,7 +34,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps ...@@ -34,7 +34,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
step 'I should see new avatar' do step 'I should see new avatar' do
expect(@user.avatar).to be_instance_of AvatarUploader expect(@user.avatar).to be_instance_of AvatarUploader
expect(@user.avatar.url).to eq "/uploads/user/avatar/#{ @user.id }/banana_sample.gif" expect(@user.avatar.url).to eq "/uploads/user/avatar/#{@user.id}/banana_sample.gif"
end end
step 'I should see the "Remove avatar" button' do step 'I should see the "Remove avatar" button' do
......
...@@ -37,7 +37,7 @@ class Spinach::Features::Project < Spinach::FeatureSteps ...@@ -37,7 +37,7 @@ class Spinach::Features::Project < Spinach::FeatureSteps
step 'I should see new project avatar' do step 'I should see new project avatar' do
expect(@project.avatar).to be_instance_of AvatarUploader expect(@project.avatar).to be_instance_of AvatarUploader
url = @project.avatar.url url = @project.avatar.url
expect(url).to eq "/uploads/project/avatar/#{ @project.id }/banana_sample.gif" expect(url).to eq "/uploads/project/avatar/#{@project.id}/banana_sample.gif"
end end
step 'I should see the "Remove avatar" button' do step 'I should see the "Remove avatar" button' do
......
...@@ -238,13 +238,13 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -238,13 +238,13 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end end
step 'I am redirected to the new file' do step 'I am redirected to the new file' do
expect(current_path).to eq(namespace_project_blob_path( expect(current_path).to eq(
@project.namespace, @project, 'master/' + new_file_name)) namespace_project_blob_path(@project.namespace, @project, 'master/' + new_file_name))
end end
step 'I am redirected to the new file with directory' do step 'I am redirected to the new file with directory' do
expect(current_path).to eq(namespace_project_blob_path( expect(current_path).to eq(
@project.namespace, @project, 'master/' + new_file_name_with_directory)) namespace_project_blob_path(@project.namespace, @project, 'master/' + new_file_name_with_directory))
end end
step 'I am redirected to the new merge request page' do step 'I am redirected to the new merge request page' do
...@@ -252,8 +252,8 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -252,8 +252,8 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end end
step 'I am redirected to the root directory' do step 'I am redirected to the root directory' do
expect(current_path).to eq(namespace_project_tree_path( expect(current_path).to eq(
@project.namespace, @project, 'master/')) namespace_project_tree_path(@project.namespace, @project, 'master/'))
end end
step "I don't see the permalink link" do step "I don't see the permalink link" do
......
...@@ -212,8 +212,8 @@ module SharedPaths ...@@ -212,8 +212,8 @@ module SharedPaths
end end
step 'I visit a binary file in the repo' do step 'I visit a binary file in the repo' do
visit namespace_project_blob_path(@project.namespace, @project, File.join( visit namespace_project_blob_path(@project.namespace, @project,
root_ref, 'files/images/logo-black.png')) File.join(root_ref, 'files/images/logo-black.png'))
end end
step "I visit my project's commits page" do step "I visit my project's commits page" do
...@@ -316,8 +316,8 @@ module SharedPaths ...@@ -316,8 +316,8 @@ module SharedPaths
end end
step 'I am on the ".gitignore" edit file page' do step 'I am on the ".gitignore" edit file page' do
expect(current_path).to eq(namespace_project_edit_blob_path( expect(current_path).to eq(
@project.namespace, @project, File.join(root_ref, '.gitignore'))) namespace_project_edit_blob_path(@project.namespace, @project, File.join(root_ref, '.gitignore')))
end end
step 'I visit project source page for "6d39438"' do step 'I visit project source page for "6d39438"' do
......
...@@ -67,7 +67,7 @@ module API ...@@ -67,7 +67,7 @@ module API
expose :shared_runners_enabled expose :shared_runners_enabled
expose :creator_id expose :creator_id
expose :namespace 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 :avatar_url
expose :star_count, :forks_count expose :star_count, :forks_count
end end
......
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
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
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
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Filter
# Issues, Merge Requests, Snippets, Commits and Commit Ranges share # Issues, Merge Requests, Snippets, Commits and Commit Ranges share
# similar functionality in reference filtering. # similar functionality in reference filtering.
class AbstractReferenceFilter < ReferenceFilter class AbstractReferenceFilter < ReferenceFilter
......
require 'gitlab/markdown' require 'banzai'
require 'html/pipeline/filter' require 'html/pipeline/filter'
require 'uri' require 'uri'
module Gitlab module Banzai
module Markdown module Filter
# HTML Filter for auto-linking URLs in HTML. # HTML Filter for auto-linking URLs in HTML.
# #
# Based on HTML::Pipeline::AutolinkFilter # Based on HTML::Pipeline::AutolinkFilter
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that replaces commit range references with links. # HTML filter that replaces commit range references with links.
# #
# This filter supports cross-project references. # This filter supports cross-project references.
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that replaces commit references with links. # HTML filter that replaces commit references with links.
# #
# This filter supports cross-project references. # This filter supports cross-project references.
......
require 'action_controller' require 'action_controller'
require 'gitlab/markdown' require 'banzai'
require 'gitlab_emoji' require 'gitlab_emoji'
require 'html/pipeline/filter' require 'html/pipeline/filter'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that replaces :emoji: with images. # HTML filter that replaces :emoji: with images.
# #
# Based on HTML::Pipeline::EmojiFilter # Based on HTML::Pipeline::EmojiFilter
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that replaces external issue tracker references with links. # HTML filter that replaces external issue tracker references with links.
# References are ignored if the project doesn't use an external issue # References are ignored if the project doesn't use an external issue
# tracker. # tracker.
......
require 'gitlab/markdown' require 'banzai'
require 'html/pipeline/filter' require 'html/pipeline/filter'
module Gitlab module Banzai
module Markdown module Filter
# HTML Filter to add a `rel="nofollow"` attribute to external links # HTML Filter to add a `rel="nofollow"` attribute to external links
# #
class ExternalLinkFilter < HTML::Pipeline::Filter class ExternalLinkFilter < HTML::Pipeline::Filter
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that replaces issue references with links. References to # HTML filter that replaces issue references with links. References to
# issues that do not exist are ignored. # issues that do not exist are ignored.
# #
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that replaces label references with links. # HTML filter that replaces label references with links.
class LabelReferenceFilter < ReferenceFilter class LabelReferenceFilter < ReferenceFilter
# Public: Find label references in text # Public: Find label references in text
......
module Gitlab require 'banzai'
module Markdown require 'html/pipeline/filter'
module Banzai
module Filter
class MarkdownFilter < HTML::Pipeline::TextFilter class MarkdownFilter < HTML::Pipeline::TextFilter
def initialize(text, context = nil, result = nil) def initialize(text, context = nil, result = nil)
super text, context, result super text, context, result
@text = @text.gsub "\r", '' @text = @text.delete "\r"
end end
def call def call
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that replaces merge request references with links. References # HTML filter that replaces merge request references with links. References
# to merge requests that do not exist are ignored. # to merge requests that do not exist are ignored.
# #
......
require 'gitlab/markdown' require 'banzai'
require 'html/pipeline/filter' require 'html/pipeline/filter'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that removes references to records that the current user does # HTML filter that removes references to records that the current user does
# not have permission to view. # not have permission to view.
# #
...@@ -27,7 +27,7 @@ module Gitlab ...@@ -27,7 +27,7 @@ module Gitlab
def user_can_reference?(node) def user_can_reference?(node)
if node.has_attribute?('data-reference-filter') if node.has_attribute?('data-reference-filter')
reference_type = node.attr('data-reference-filter') reference_type = node.attr('data-reference-filter')
reference_filter = Gitlab::Markdown.const_get(reference_type) reference_filter = Banzai::Filter.const_get(reference_type)
reference_filter.user_can_reference?(current_user, node, context) reference_filter.user_can_reference?(current_user, node, context)
else else
......
require 'active_support/core_ext/string/output_safety' require 'active_support/core_ext/string/output_safety'
require 'gitlab/markdown' require 'banzai'
require 'html/pipeline/filter' require 'html/pipeline/filter'
module Gitlab module Banzai
module Markdown module Filter
# Base class for GitLab Flavored Markdown reference filters. # Base class for GitLab Flavored Markdown reference filters.
# #
# References within <pre>, <code>, <a>, and <style> elements are ignored. # References within <pre>, <code>, <a>, and <style> elements are ignored.
...@@ -12,27 +12,6 @@ module Gitlab ...@@ -12,27 +12,6 @@ module Gitlab
# :project (required) - Current project, ignored if reference is cross-project. # :project (required) - Current project, ignored if reference is cross-project.
# :only_path - Generate path-only links. # :only_path - Generate path-only links.
class ReferenceFilter < HTML::Pipeline::Filter class ReferenceFilter < HTML::Pipeline::Filter
LazyReference = Struct.new(:klass, :ids) do
def self.load(refs)
lazy_references, values = refs.partition { |ref| ref.is_a?(self) }
lazy_values = lazy_references.group_by(&:klass).flat_map do |klass, refs|
ids = refs.flat_map(&:ids)
klass.where(id: ids)
end
values + lazy_values
end
def load
self.klass.where(id: self.ids)
end
end
def self.[](name)
Markdown.const_get("#{name.to_s.camelize}ReferenceFilter")
end
def self.user_can_reference?(user, node, context) def self.user_can_reference?(user, node, context)
if node.has_attribute?('data-project') if node.has_attribute?('data-project')
project_id = node.attr('data-project').to_i project_id = node.attr('data-project').to_i
......
require 'gitlab/markdown' require 'banzai'
require 'html/pipeline/filter' require 'html/pipeline/filter'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that gathers all referenced records that the current user has # HTML filter that gathers all referenced records that the current user has
# permission to view. # permission to view.
# #
...@@ -20,7 +20,7 @@ module Gitlab ...@@ -20,7 +20,7 @@ module Gitlab
gather_references(node) gather_references(node)
end end
load_lazy_references unless context[:load_lazy_references] == false load_lazy_references unless ReferenceExtractor.lazy?
doc doc
end end
...@@ -31,7 +31,7 @@ module Gitlab ...@@ -31,7 +31,7 @@ module Gitlab
return unless node.has_attribute?('data-reference-filter') return unless node.has_attribute?('data-reference-filter')
reference_type = node.attr('data-reference-filter') reference_type = node.attr('data-reference-filter')
reference_filter = Gitlab::Markdown.const_get(reference_type) reference_filter = Banzai::Filter.const_get(reference_type)
return if context[:reference_filter] && reference_filter != context[:reference_filter] return if context[:reference_filter] && reference_filter != context[:reference_filter]
...@@ -47,11 +47,10 @@ module Gitlab ...@@ -47,11 +47,10 @@ module Gitlab
end end
end end
# Will load all references of one type using one query.
def load_lazy_references def load_lazy_references
refs = result[:references] refs = result[:references]
refs.each do |type, values| refs.each do |type, values|
refs[type] = ReferenceFilter::LazyReference.load(values) refs[type] = ReferenceExtractor.lazily(values)
end end
end end
......
require 'gitlab/markdown' require 'banzai'
require 'html/pipeline/filter' require 'html/pipeline/filter'
require 'uri' require 'uri'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that "fixes" relative links to files in a repository. # HTML filter that "fixes" relative links to files in a repository.
# #
# Context options: # Context options:
......
require 'gitlab/markdown' require 'banzai'
require 'html/pipeline/filter' require 'html/pipeline/filter'
require 'html/pipeline/sanitization_filter' require 'html/pipeline/sanitization_filter'
module Gitlab module Banzai
module Markdown module Filter
# Sanitize HTML # Sanitize HTML
# #
# Extends HTML::Pipeline::SanitizationFilter with a custom whitelist. # Extends HTML::Pipeline::SanitizationFilter with a custom whitelist.
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that replaces snippet references with links. References to # HTML filter that replaces snippet references with links. References to
# snippets that do not exist are ignored. # snippets that do not exist are ignored.
# #
......
require 'gitlab/markdown' require 'banzai'
require 'html/pipeline/filter' require 'html/pipeline/filter'
require 'rouge/plugins/redcarpet' require 'rouge/plugins/redcarpet'
module Gitlab module Banzai
module Markdown module Filter
# HTML Filter to highlight fenced code blocks # HTML Filter to highlight fenced code blocks
# #
class SyntaxHighlightFilter < HTML::Pipeline::Filter class SyntaxHighlightFilter < HTML::Pipeline::Filter
......
require 'gitlab/markdown' require 'banzai'
require 'html/pipeline/filter' require 'html/pipeline/filter'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that adds an anchor child element to all Headers in a # HTML filter that adds an anchor child element to all Headers in a
# document, so that they can be linked to. # document, so that they can be linked to.
# #
...@@ -31,7 +31,7 @@ module Gitlab ...@@ -31,7 +31,7 @@ module Gitlab
id = text.downcase id = text.downcase
id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation 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 id.squeeze!('-') # replace multiple dashes with one
uniq = (headers[id] > 0) ? "-#{headers[id]}" : '' uniq = (headers[id] > 0) ? "-#{headers[id]}" : ''
......
require 'gitlab/markdown' require 'banzai'
require 'task_list/filter' require 'task_list/filter'
module Gitlab module Banzai
module Markdown module Filter
# Work around a bug in the default TaskList::Filter that adds a `task-list` # 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 # class to every list element, regardless of whether or not it contains a
# task list. # task list.
......
require 'gitlab/markdown' require 'banzai'
require 'html/pipeline/filter' require 'html/pipeline/filter'
require 'uri' require 'uri'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that "fixes" relative upload links to files. # HTML filter that "fixes" relative upload links to files.
# Context options: # Context options:
# :project (required) - Current project # :project (required) - Current project
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Filter
# HTML filter that replaces user or group references with links. # HTML filter that replaces user or group references with links.
# #
# A special `@all` reference is also supported. # A special `@all` reference is also supported.
......
require 'banzai'
module Banzai
class LazyReference
def self.load(refs)
lazy_references, values = refs.partition { |ref| ref.is_a?(self) }
lazy_values = lazy_references.group_by(&:klass).flat_map do |klass, refs|
ids = refs.flat_map(&:ids)
klass.where(id: ids)
end
values + lazy_values
end
attr_reader :klass, :ids
def initialize(klass, ids)
@klass = klass
@ids = Array.wrap(ids).map(&:to_i)
end
def load
self.klass.where(id: self.ids)
end
end
end
require 'banzai'
module Banzai
module Pipeline
def self.[](name)
name ||= :full
const_get("#{name.to_s.camelize}Pipeline")
end
end
end
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Pipeline
class AsciidocPipeline < Pipeline class AsciidocPipeline < BasePipeline
def self.filters def self.filters
[ [
Gitlab::Markdown::RelativeLinkFilter Filter::RelativeLinkFilter
] ]
end end
end end
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Pipeline
class AtomPipeline < FullPipeline class AtomPipeline < FullPipeline
def self.transform_context(context) def self.transform_context(context)
super(context).merge( super(context).merge(
......
require 'banzai'
require 'html/pipeline'
module Banzai
module Pipeline
class BasePipeline
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
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Pipeline
module CombinedPipeline module CombinedPipeline
def self.new(*pipelines) def self.new(*pipelines)
Class.new(Pipeline) do Class.new(BasePipeline) do
const_set :PIPELINES, pipelines const_set :PIPELINES, pipelines
def self.pipelines def self.pipelines
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Pipeline
class DescriptionPipeline < FullPipeline class DescriptionPipeline < FullPipeline
def self.transform_context(context) def self.transform_context(context)
super(context).merge( super(context).merge(
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Pipeline
class EmailPipeline < FullPipeline class EmailPipeline < FullPipeline
def self.transform_context(context) def self.transform_context(context)
super(context).merge( super(context).merge(
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Pipeline
class FullPipeline < CombinedPipeline.new(PlainMarkdownPipeline, GfmPipeline) class FullPipeline < CombinedPipeline.new(PlainMarkdownPipeline, GfmPipeline)
end end
......
require 'banzai'
module Banzai
module Pipeline
class GfmPipeline < BasePipeline
def self.filters
@filters ||= [
Filter::SyntaxHighlightFilter,
Filter::SanitizationFilter,
Filter::UploadLinkFilter,
Filter::EmojiFilter,
Filter::TableOfContentsFilter,
Filter::AutolinkFilter,
Filter::ExternalLinkFilter,
Filter::UserReferenceFilter,
Filter::IssueReferenceFilter,
Filter::ExternalIssueReferenceFilter,
Filter::MergeRequestReferenceFilter,
Filter::SnippetReferenceFilter,
Filter::CommitRangeReferenceFilter,
Filter::CommitReferenceFilter,
Filter::LabelReferenceFilter,
Filter::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
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Pipeline
class NotePipeline < FullPipeline class NotePipeline < FullPipeline
def self.transform_context(context) def self.transform_context(context)
super(context).merge( super(context).merge(
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Pipeline
class PlainMarkdownPipeline < Pipeline class PlainMarkdownPipeline < BasePipeline
def self.filters def self.filters
[ [
Gitlab::Markdown::MarkdownFilter Filter::MarkdownFilter
] ]
end end
end end
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Pipeline
class PostProcessPipeline < Pipeline class PostProcessPipeline < BasePipeline
def self.filters def self.filters
[ [
Gitlab::Markdown::RelativeLinkFilter, Filter::RelativeLinkFilter,
Gitlab::Markdown::RedactorFilter Filter::RedactorFilter
] ]
end end
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Pipeline
class ReferenceExtractionPipeline < Pipeline class ReferenceExtractionPipeline < BasePipeline
def self.filters def self.filters
[ [
Gitlab::Markdown::ReferenceGathererFilter Filter::ReferenceGathererFilter
] ]
end end
end end
......
require 'gitlab/markdown' require 'banzai'
module Gitlab module Banzai
module Markdown module Pipeline
class SingleLinePipeline < GfmPipeline class SingleLinePipeline < GfmPipeline
end end
......
require 'banzai'
module Banzai
# Extract possible GFM references from an arbitrary String for further processing.
class ReferenceExtractor
class << self
LAZY_KEY = :banzai_reference_extractor_lazy
def lazy?
Thread.current[LAZY_KEY]
end
def lazily(values = nil, &block)
return (values || block.call).uniq if lazy?
begin
Thread.current[LAZY_KEY] = true
values ||= block.call
Banzai::LazyReference.load(values.uniq).uniq
ensure
Thread.current[LAZY_KEY] = false
end
end
end
def initialize
@texts = []
end
def analyze(text, context = {})
@texts << Renderer.render(text, context)
end
def references(type, context = {})
filter = Banzai::Filter["#{type}_reference"]
context.merge!(
pipeline: :reference_extraction,
# ReferenceGathererFilter
reference_filter: filter
)
self.class.lazily do
@texts.flat_map do |html|
text_context = context.dup
result = Renderer.render_result(html, text_context)
result[:references][type]
end.uniq
end
end
end
end
require 'html/pipeline' module Banzai
module Renderer
module Gitlab
# Custom parser for GitLab-flavored Markdown
#
# See the files in `lib/gitlab/markdown/` for specific processing information.
module Markdown
# Convert a Markdown String into an HTML-safe String of HTML # Convert a Markdown String into an HTML-safe String of HTML
# #
# Note that while the returned HTML will have been sanitized of dangerous # Note that while the returned HTML will have been sanitized of dangerous
...@@ -75,41 +70,7 @@ module Gitlab ...@@ -75,41 +70,7 @@ module Gitlab
def self.full_cache_key(cache_key, pipeline_name) def self.full_cache_key(cache_key, pipeline_name)
return unless cache_key return unless cache_key
["markdown", *cache_key, pipeline_name || :full] ["banzai", *cache_key, pipeline_name || :full]
end end
# Provide autoload paths for filters to prevent a circular dependency error
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/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
end end
...@@ -32,7 +32,7 @@ module Gitlab ...@@ -32,7 +32,7 @@ module Gitlab
html = ::Asciidoctor.convert(input, asciidoc_opts) html = ::Asciidoctor.convert(input, asciidoc_opts)
if context[:project] if context[:project]
html = Gitlab::Markdown.render(html, context.merge(pipeline: :asciidoc)) html = Banzai.render(html, context.merge(pipeline: :asciidoc))
end end
html.html_safe html.html_safe
......
...@@ -2,7 +2,7 @@ module Gitlab ...@@ -2,7 +2,7 @@ module Gitlab
class Shell class Shell
class Error < StandardError; end class Error < StandardError; end
class KeyAdder < Struct.new(:io) KeyAdder = Struct.new(:io) do
def add_key(id, key) def add_key(id, key)
key.gsub!(/[[:space:]]+/, ' ').strip! key.gsub!(/[[:space:]]+/, ' ').strip!
io.puts("#{id}\t#{key}") io.puts("#{id}\t#{key}")
......
...@@ -11,7 +11,8 @@ module Gitlab ...@@ -11,7 +11,8 @@ module Gitlab
end end
def execute def execute
project = ::Projects::CreateService.new(current_user, project = ::Projects::CreateService.new(
current_user,
name: repo["name"], name: repo["name"],
path: repo["slug"], path: repo["slug"],
description: repo["description"], description: repo["description"],
......
...@@ -46,11 +46,11 @@ module Gitlab ...@@ -46,11 +46,11 @@ module Gitlab
end end
def added_lines def added_lines
diff_lines.select(&:added?).size diff_lines.count(&:added?)
end end
def removed_lines def removed_lines
diff_lines.select(&:removed?).size diff_lines.count(&:removed?)
end end
end end
end end
......
...@@ -199,7 +199,7 @@ module Gitlab ...@@ -199,7 +199,7 @@ module Gitlab
s = s.gsub(/^#/, "\\#") s = s.gsub(/^#/, "\\#")
s = s.gsub(/^-/, "\\-") s = s.gsub(/^-/, "\\-")
s = s.gsub("`", "\\~") s = s.gsub("`", "\\~")
s = s.gsub("\r", "") s = s.delete("\r")
s = s.gsub("\n", " \n") s = s.gsub("\n", " \n")
s s
end end
......
...@@ -12,7 +12,8 @@ module Gitlab ...@@ -12,7 +12,8 @@ module Gitlab
end end
def execute def execute
project = ::Projects::CreateService.new(current_user, project = ::Projects::CreateService.new(
current_user,
name: repo.safe_name, name: repo.safe_name,
path: repo.path, path: repo.path,
namespace: namespace, namespace: namespace,
......
...@@ -11,7 +11,8 @@ module Gitlab ...@@ -11,7 +11,8 @@ module Gitlab
end end
def execute def execute
project = ::Projects::CreateService.new(current_user, project = ::Projects::CreateService.new(
current_user,
name: repo["name"], name: repo["name"],
path: repo["path"], path: repo["path"],
description: repo["description"], description: repo["description"],
......
...@@ -10,7 +10,8 @@ module Gitlab ...@@ -10,7 +10,8 @@ module Gitlab
end end
def execute def execute
::Projects::CreateService.new(current_user, ::Projects::CreateService.new(
current_user,
name: repo.name, name: repo.name,
path: repo.path, path: repo.path,
description: repo.description, description: repo.description,
......
...@@ -171,8 +171,6 @@ module Gitlab ...@@ -171,8 +171,6 @@ module Gitlab
when /\AMilestone:/ when /\AMilestone:/
"#fee3ff" "#fee3ff"
when *@closed_statuses.map { |s| nice_status_name(s) }
"#cfcfcf"
when "Status: New" when "Status: New"
"#428bca" "#428bca"
when "Status: Accepted" when "Status: Accepted"
...@@ -199,6 +197,8 @@ module Gitlab ...@@ -199,6 +197,8 @@ module Gitlab
"#8e44ad" "#8e44ad"
when "Type: Other" when "Type: Other"
"#7f8c8d" "#7f8c8d"
when *@closed_statuses.map { |s| nice_status_name(s) }
"#cfcfcf"
else else
"#e2e2e2" "#e2e2e2"
end end
...@@ -227,7 +227,7 @@ module Gitlab ...@@ -227,7 +227,7 @@ module Gitlab
s = s.gsub("`", "\\`") s = s.gsub("`", "\\`")
# Carriage returns make me sad # Carriage returns make me sad
s = s.gsub("\r", "") s = s.delete("\r")
# Markdown ignores single newlines, but we need them as <br />. # Markdown ignores single newlines, but we need them as <br />.
s = s.gsub("\n", " \n") s = s.gsub("\n", " \n")
......
...@@ -11,7 +11,8 @@ module Gitlab ...@@ -11,7 +11,8 @@ module Gitlab
end end
def execute def execute
project = ::Projects::CreateService.new(current_user, project = ::Projects::CreateService.new(
current_user,
name: repo.name, name: repo.name,
path: repo.name, path: repo.name,
description: repo.summary, description: repo.summary,
......
require 'gitlab/markdown'
module Gitlab
module Markdown
# 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
end
require 'gitlab/markdown' require 'banzai'
module Gitlab module Gitlab
module Markdown module Markdown
class Pipeline class Pipeline
def self.[](name) def self.[](name)
name ||= :full name ||= :full
Markdown.const_get("#{name.to_s.camelize}Pipeline") const_get("#{name.to_s.camelize}Pipeline")
end end
def self.filters def self.filters
......
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
require 'gitlab/markdown' require 'banzai'
module Gitlab module Gitlab
# Extract possible GFM references from an arbitrary String for further processing. # Extract possible GFM references from an arbitrary String for further processing.
class ReferenceExtractor class ReferenceExtractor < Banzai::ReferenceExtractor
attr_accessor :project, :current_user, :load_lazy_references attr_accessor :project, :current_user
def initialize(project, current_user = nil, load_lazy_references: true) def initialize(project, current_user = nil)
@project = project @project = project
@current_user = current_user @current_user = current_user
@load_lazy_references = load_lazy_references
@texts = []
@references = {} @references = {}
super()
end end
def analyze(text, options = {}) def analyze(text, context = {})
@texts << Gitlab::Markdown.render(text, options.merge(project: project)) super(text, context.merge(project: project))
end end
%i(user label issue merge_request snippet commit commit_range).each do |type| %i(user label issue merge_request snippet commit commit_range).each do |type|
define_method("#{type}s") do define_method("#{type}s") do
@references[type] ||= pipeline_result(type) @references[type] ||= references(type, project: project, current_user: current_user)
end
end end
private
# Instantiate and call HTML::Pipeline with a single reference filter type,
# returning the result
#
# filter_type - Symbol reference type (e.g., :commit, :issue, etc.)
#
# Returns the results Array for the requested filter type
def pipeline_result(filter_type)
filter = Gitlab::Markdown::ReferenceFilter[filter_type]
context = {
pipeline: :reference_extraction,
project: project,
current_user: current_user,
# ReferenceGathererFilter
load_lazy_references: false,
reference_filter: filter
}
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
end
values
end end
end end
end end
...@@ -33,12 +33,13 @@ app_user="git" ...@@ -33,12 +33,13 @@ app_user="git"
app_root="/home/$app_user/gitlab" app_root="/home/$app_user/gitlab"
pid_path="$app_root/tmp/pids" pid_path="$app_root/tmp/pids"
socket_path="$app_root/tmp/sockets" socket_path="$app_root/tmp/sockets"
rails_socket="$socket_path/gitlab.socket"
web_server_pid_path="$pid_path/unicorn.pid" web_server_pid_path="$pid_path/unicorn.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid" sidekiq_pid_path="$pid_path/sidekiq.pid"
mail_room_enabled=false mail_room_enabled=false
mail_room_pid_path="$pid_path/mail_room.pid" mail_room_pid_path="$pid_path/mail_room.pid"
gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid" gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080" gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080 -authSocket $rails_socket -documentRoot $app_root/public"
gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log" gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log"
shell_path="/bin/bash" shell_path="/bin/bash"
......
...@@ -36,7 +36,7 @@ gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid" ...@@ -36,7 +36,7 @@ gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
# '-listenNetwork tcp -listenAddr localhost:8181'. # '-listenNetwork tcp -listenAddr localhost:8181'.
# The -authBackend setting tells gitlab-workhorse where it can reach # The -authBackend setting tells gitlab-workhorse where it can reach
# Unicorn. # Unicorn.
gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080" gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080 -authSocket $socket_path/gitlab.socket -documentRoot $app_root/public"
gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log" gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log"
# mail_room_enabled specifies whether mail_room, which is used to process incoming email, is enabled. # mail_room_enabled specifies whether mail_room, which is used to process incoming email, is enabled.
......
...@@ -10,34 +10,12 @@ ...@@ -10,34 +10,12 @@
## If you change this file in a Merge Request, please also create ## 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 ## 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 ## ## configuration ##
################################### ###################################
## ##
## See installation.md#using-https for additional HTTPS configuration details. ## 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 { upstream gitlab-workhorse {
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0; server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
} }
...@@ -54,10 +32,6 @@ server { ...@@ -54,10 +32,6 @@ server {
server_tokens off; ## Don't show the nginx version number, a security best practice server_tokens off; ## Don't show the nginx version number, a security best practice
root /home/git/gitlab/public; 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 ## See app/controllers/application_controller.rb for headers set
## Individual nginx logs for this GitLab vhost ## Individual nginx logs for this GitLab vhost
...@@ -65,103 +39,8 @@ server { ...@@ -65,103 +39,8 @@ server {
error_log /var/log/nginx/gitlab_error.log; error_log /var/log/nginx/gitlab_error.log;
location / { 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; client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block gzip off;
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 ## https://github.com/gitlabhq/gitlabhq/issues/694
## Some requests take more than 30 seconds. ## Some requests take more than 30 seconds.
...@@ -169,14 +48,7 @@ server { ...@@ -169,14 +48,7 @@ server {
proxy_connect_timeout 300; proxy_connect_timeout 300;
proxy_redirect off; proxy_redirect off;
# Do not buffer Git HTTP responses proxy_http_version 1.1;
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_set_header Host $http_host; proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
...@@ -185,18 +57,4 @@ server { ...@@ -185,18 +57,4 @@ server {
proxy_pass http://gitlab-workhorse; 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;
} }
...@@ -14,34 +14,12 @@ ...@@ -14,34 +14,12 @@
## If you change this file in a Merge Request, please also create ## 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 ## 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 ## ## configuration ##
################################### ###################################
## ##
## See installation.md#using-https for additional HTTPS configuration details. ## 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 { upstream gitlab-workhorse {
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0; server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
} }
...@@ -61,7 +39,6 @@ server { ...@@ -61,7 +39,6 @@ server {
error_log /var/log/nginx/gitlab_error.log; error_log /var/log/nginx/gitlab_error.log;
} }
## HTTPS host ## HTTPS host
server { server {
listen 0.0.0.0:443 ssl; listen 0.0.0.0:443 ssl;
...@@ -70,10 +47,6 @@ server { ...@@ -70,10 +47,6 @@ server {
server_tokens off; ## Don't show the nginx version number, a security best practice server_tokens off; ## Don't show the nginx version number, a security best practice
root /home/git/gitlab/public; 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 ## Strong SSL Security
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/ ## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
ssl on; ssl on;
...@@ -110,104 +83,7 @@ server { ...@@ -110,104 +83,7 @@ server {
error_log /var/log/nginx/gitlab_error.log; error_log /var/log/nginx/gitlab_error.log;
location / { 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; 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 ## https://github.com/gitlabhq/gitlabhq/issues/694
...@@ -216,14 +92,7 @@ server { ...@@ -216,14 +92,7 @@ server {
proxy_connect_timeout 300; proxy_connect_timeout 300;
proxy_redirect off; proxy_redirect off;
# Do not buffer Git HTTP responses proxy_http_version 1.1;
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_set_header Host $http_host; proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
...@@ -232,18 +101,4 @@ server { ...@@ -232,18 +101,4 @@ server {
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://gitlab-workhorse; 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;
} }
...@@ -822,12 +822,29 @@ namespace :gitlab do ...@@ -822,12 +822,29 @@ namespace :gitlab do
namespace_dirs.each do |namespace_dir| namespace_dirs.each do |namespace_dir|
repo_dirs = Dir.glob(File.join(namespace_dir, '*')) repo_dirs = Dir.glob(File.join(namespace_dir, '*'))
repo_dirs.each do |dir| repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) }
puts "\nChecking repo at #{dir}"
system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: dir)
end end
end 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 end
# Helper methods # Helper methods
...@@ -952,4 +969,35 @@ namespace :gitlab do ...@@ -952,4 +969,35 @@ namespace :gitlab do
false false
end end
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 end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::ReferenceFilter, benchmark: true do describe Banzai::Filter::ReferenceFilter, benchmark: true do
let(:input) do let(:input) do
html = <<-EOF html = <<-EOF
<p>Hello @alice and @bob, how are you doing today?</p> <p>Hello @alice and @bob, how are you doing today?</p>
......
...@@ -43,7 +43,8 @@ FactoryGirl.define do ...@@ -43,7 +43,8 @@ FactoryGirl.define do
end end
after(:create) do |user, evaluator| after(:create) do |user, evaluator|
user.identities << create(:identity, user.identities << create(
:identity,
provider: evaluator.provider, provider: evaluator.provider,
extern_uid: evaluator.extern_uid extern_uid: evaluator.extern_uid
) )
......
...@@ -16,11 +16,11 @@ describe 'Group access', feature: true do ...@@ -16,11 +16,11 @@ describe 'Group access', feature: true do
end end
end end
def group_member(access_level, group = group) def group_member(access_level, grp = group())
level = Object.const_get("Gitlab::Access::#{access_level.upcase}") level = Object.const_get("Gitlab::Access::#{access_level.upcase}")
create(:user).tap do |user| create(:user).tap do |user|
group.add_user(user, level) grp.add_user(user, level)
end end
end end
......
...@@ -263,11 +263,12 @@ describe ApplicationHelper do ...@@ -263,11 +263,12 @@ describe ApplicationHelper do
end end
it 'includes a default js-timeago class' do it 'includes a default js-timeago class' do
expect(element.attr('class')).to eq 'time_ago js-timeago' expect(element.attr('class')).to eq 'time_ago js-timeago js-timeago-pending'
end end
it 'accepts a custom html_class' do it 'accepts a custom html_class' do
expect(element(html_class: 'custom_class').attr('class')).to eq 'custom_class js-timeago' expect(element(html_class: 'custom_class').attr('class')).
to eq 'custom_class js-timeago js-timeago-pending'
end end
it 'accepts a custom tooltip placement' do it 'accepts a custom tooltip placement' do
...@@ -278,7 +279,7 @@ describe ApplicationHelper do ...@@ -278,7 +279,7 @@ describe ApplicationHelper do
el = element.next_element el = element.next_element
expect(el.name).to eq 'script' expect(el.name).to eq 'script'
expect(el.text).to include "$('.js-timeago').last().timeago()" expect(el.text).to include "$('.js-timeago-pending').removeClass('js-timeago-pending').timeago()"
end end
it 'allows the script tag to be excluded' do it 'allows the script tag to be excluded' do
......
...@@ -9,7 +9,7 @@ describe GroupsHelper do ...@@ -9,7 +9,7 @@ describe GroupsHelper do
group.avatar = File.open(avatar_file_path) group.avatar = File.open(avatar_file_path)
group.save! group.save!
expect(group_icon(group.path).to_s). expect(group_icon(group.path).to_s).
to match("/uploads/group/avatar/#{ group.id }/banana_sample.gif") to match("/uploads/group/avatar/#{group.id}/banana_sample.gif")
end end
it 'should give default avatar_icon when no avatar is present' do it 'should give default avatar_icon when no avatar is present' do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::CrossProjectReference, lib: true do describe Banzai::CrossProjectReference, lib: true do
include described_class include described_class
describe '#project_from_ref' do describe '#project_from_ref' do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::AutolinkFilter, lib: true do describe Banzai::Filter::AutolinkFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
let(:link) { 'http://about.gitlab.com/' } let(:link) { 'http://about.gitlab.com/' }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::CommitRangeReferenceFilter, lib: true do describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::CommitReferenceFilter, lib: true do describe Banzai::Filter::CommitReferenceFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::EmojiFilter, lib: true do describe Banzai::Filter::EmojiFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
before do before do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::ExternalIssueReferenceFilter, lib: true do describe Banzai::Filter::ExternalIssueReferenceFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
def helper def helper
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::ExternalLinkFilter, lib: true do describe Banzai::Filter::ExternalLinkFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
it 'ignores elements without an href attribute' do it 'ignores elements without an href attribute' do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::IssueReferenceFilter, lib: true do describe Banzai::Filter::IssueReferenceFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
def helper def helper
......
require 'spec_helper' require 'spec_helper'
require 'html/pipeline' require 'html/pipeline'
describe Gitlab::Markdown::LabelReferenceFilter, lib: true do describe Banzai::Filter::LabelReferenceFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
let(:project) { create(:empty_project, :public) } let(:project) { create(:empty_project, :public) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::MergeRequestReferenceFilter, lib: true do describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::RedactorFilter, lib: true do describe Banzai::Filter::RedactorFilter, lib: true do
include ActionView::Helpers::UrlHelper include ActionView::Helpers::UrlHelper
include FilterSpecHelper include FilterSpecHelper
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::ReferenceGathererFilter, lib: true do describe Banzai::Filter::ReferenceGathererFilter, lib: true do
include ActionView::Helpers::UrlHelper include ActionView::Helpers::UrlHelper
include FilterSpecHelper include FilterSpecHelper
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::RelativeLinkFilter, lib: true do describe Banzai::Filter::RelativeLinkFilter, lib: true do
def filter(doc, contexts = {}) def filter(doc, contexts = {})
contexts.reverse_merge!({ contexts.reverse_merge!({
commit: project.commit, commit: project.commit,
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::SanitizationFilter, lib: true do describe Banzai::Filter::SanitizationFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
describe 'default whitelist' do describe 'default whitelist' do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::SnippetReferenceFilter, lib: true do describe Banzai::Filter::SnippetReferenceFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
let(:project) { create(:empty_project, :public) } let(:project) { create(:empty_project, :public) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::SyntaxHighlightFilter, lib: true do describe Banzai::Filter::SyntaxHighlightFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
it 'highlights valid code blocks' do it 'highlights valid code blocks' do
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::TableOfContentsFilter, lib: true do describe Banzai::Filter::TableOfContentsFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
def header(level, text) def header(level, text)
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::TaskListFilter, lib: true do describe Banzai::Filter::TaskListFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
it 'does not apply `task-list` class to non-task lists' do it 'does not apply `task-list` class to non-task lists' do
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::UploadLinkFilter, lib: true do describe Banzai::Filter::UploadLinkFilter, lib: true do
def filter(doc, contexts = {}) def filter(doc, contexts = {})
contexts.reverse_merge!({ contexts.reverse_merge!({
project: project project: project
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Markdown::UserReferenceFilter, lib: true do describe Banzai::Filter::UserReferenceFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
let(:project) { create(:empty_project, :public) } let(:project) { create(:empty_project, :public) }
......
...@@ -50,7 +50,7 @@ module Gitlab ...@@ -50,7 +50,7 @@ module Gitlab
filtered_html = '<b>ASCII</b>' filtered_html = '<b>ASCII</b>'
allow(Asciidoctor).to receive(:convert).and_return(html) allow(Asciidoctor).to receive(:convert).and_return(html)
expect(Gitlab::Markdown).to receive(:render) expect(Banzai).to receive(:render)
.with(html, context.merge(pipeline: :asciidoc)) .with(html, context.merge(pipeline: :asciidoc))
.and_return(filtered_html) .and_return(filtered_html)
......
...@@ -37,14 +37,14 @@ describe Ci::Commit, models: true do ...@@ -37,14 +37,14 @@ describe Ci::Commit, models: true do
it 'returns ordered list of commits' do it 'returns ordered list of commits' do
commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hours.ago, project: project
expect(project.ci_commits.ordered).to eq([commit2, commit1]) expect(project.ci_commits.ordered).to eq([commit2, commit1])
end end
it 'returns commits ordered by committed_at and id, with nulls last' do it 'returns commits ordered by committed_at and id, with nulls last' do
commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
commit2 = FactoryGirl.create :ci_commit, committed_at: nil, project: project commit2 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hours.ago, project: project
commit4 = FactoryGirl.create :ci_commit, committed_at: nil, project: project commit4 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
expect(project.ci_commits.ordered).to eq([commit2, commit4, commit3, commit1]) expect(project.ci_commits.ordered).to eq([commit2, commit4, commit3, commit1])
end end
......
...@@ -81,7 +81,7 @@ describe Key, models: true do ...@@ -81,7 +81,7 @@ describe Key, models: true do
it 'rejects the multiple line key' do it 'rejects the multiple line key' do
key = build(:key) key = build(:key)
key.key.gsub!(' ', "\n") key.key.tr!(' ', "\n")
expect(key).not_to be_valid expect(key).not_to be_valid
end end
end end
......
...@@ -57,23 +57,21 @@ describe HipchatService, models: true do ...@@ -57,23 +57,21 @@ describe HipchatService, models: true do
it 'should use v1 if version is provided' do it 'should use v1 if version is provided' do
allow(hipchat).to receive(:api_version).and_return('v1') allow(hipchat).to receive(:api_version).and_return('v1')
expect(HipChat::Client).to receive(:new). expect(HipChat::Client).to receive(:new).with(
with(token, token,
api_version: 'v1', api_version: 'v1',
server_url: server_url). server_url: server_url
and_return( ).and_return(double(:hipchat_service).as_null_object)
double(:hipchat_service).as_null_object)
hipchat.execute(push_sample_data) hipchat.execute(push_sample_data)
end end
it 'should use v2 as the version when nothing is provided' do it 'should use v2 as the version when nothing is provided' do
allow(hipchat).to receive(:api_version).and_return('') allow(hipchat).to receive(:api_version).and_return('')
expect(HipChat::Client).to receive(:new). expect(HipChat::Client).to receive(:new).with(
with(token, token,
api_version: 'v2', api_version: 'v2',
server_url: server_url). server_url: server_url
and_return( ).and_return(double(:hipchat_service).as_null_object)
double(:hipchat_service).as_null_object)
hipchat.execute(push_sample_data) hipchat.execute(push_sample_data)
end end
......
...@@ -462,8 +462,8 @@ describe User, models: true do ...@@ -462,8 +462,8 @@ describe User, models: true do
expect(User.search(user1.username.downcase).to_a).to eq([user1]) expect(User.search(user1.username.downcase).to_a).to eq([user1])
expect(User.search(user2.username.upcase).to_a).to eq([user2]) expect(User.search(user2.username.upcase).to_a).to eq([user2])
expect(User.search(user2.username.downcase).to_a).to eq([user2]) expect(User.search(user2.username.downcase).to_a).to eq([user2])
expect(User.search(user1.username.downcase).to_a.count).to eq(2) expect(User.search(user1.username.downcase).to_a.size).to eq(2)
expect(User.search(user2.username.downcase).to_a.count).to eq(1) expect(User.search(user2.username.downcase).to_a.size).to eq(1)
end end
end end
......
...@@ -6,7 +6,7 @@ describe API::API, api: true do ...@@ -6,7 +6,7 @@ describe API::API, api: true do
let(:user) { create(:user) } let(:user) { create(:user) }
let!(:project) {create(:project, creator_id: user.id, namespace: user.namespace) } let!(:project) {create(:project, creator_id: user.id, namespace: user.namespace) }
let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) } let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) }
let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.seconds) } let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) }
let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, target_project: project, title: "Merged test", created_at: base_time + 2.seconds) } let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, target_project: project, title: "Merged test", created_at: base_time + 2.seconds) }
let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") } let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") }
let!(:note2) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") } let!(:note2) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") }
......
...@@ -29,7 +29,7 @@ describe API::API, api: true do ...@@ -29,7 +29,7 @@ describe API::API, api: true do
if required_attributes.empty? if required_attributes.empty?
expected_code = 200 expected_code = 200
else else
attrs.delete(required_attributes.shuffle.first) attrs.delete(required_attributes.sample)
expected_code = 400 expected_code = 400
end end
......
...@@ -42,7 +42,7 @@ describe UpdateSnippetService, services: true do ...@@ -42,7 +42,7 @@ describe UpdateSnippetService, services: true do
CreateSnippetService.new(project, user, opts).execute CreateSnippetService.new(project, user, opts).execute
end end
def update_snippet(project = nil, user, snippet, opts) def update_snippet(project, user, snippet, opts)
UpdateSnippetService.new(project, user, snippet, opts).execute UpdateSnippetService.new(project, user, snippet, opts).execute
end end
end end
# Helper methods for Gitlab::Markdown filter specs # Helper methods for Banzai filter specs
# #
# Must be included into specs manually # Must be included into specs manually
module FilterSpecHelper module FilterSpecHelper
...@@ -10,49 +10,49 @@ module FilterSpecHelper ...@@ -10,49 +10,49 @@ module FilterSpecHelper
# if none is provided. # if none is provided.
# #
# html - HTML String to pass to the filter's `call` method. # html - HTML String to pass to the filter's `call` method.
# contexts - Hash context for the filter. (default: {project: project}) # context - Hash context for the filter. (default: {project: project})
# #
# Returns a Nokogiri::XML::DocumentFragment # Returns a Nokogiri::XML::DocumentFragment
def filter(html, contexts = {}) def filter(html, context = {})
if defined?(project) if defined?(project)
contexts.reverse_merge!(project: project) context.reverse_merge!(project: project)
end end
described_class.call(html, contexts) described_class.call(html, context)
end end
# Run text through HTML::Pipeline with the current filter and return the # Run text through HTML::Pipeline with the current filter and return the
# result Hash # result Hash
# #
# body - String text to run through the pipeline # body - String text to run through the pipeline
# contexts - Hash context for the filter. (default: {project: project}) # context - Hash context for the filter. (default: {project: project})
# #
# Returns the Hash # Returns the Hash
def pipeline_result(body, contexts = {}) def pipeline_result(body, context = {})
contexts.reverse_merge!(project: project) if defined?(project) context.reverse_merge!(project: project) if defined?(project)
pipeline = HTML::Pipeline.new([described_class], contexts) pipeline = HTML::Pipeline.new([described_class], context)
pipeline.call(body) pipeline.call(body)
end end
def reference_pipeline(contexts = {}) def reference_pipeline(context = {})
contexts.reverse_merge!(project: project) if defined?(project) context.reverse_merge!(project: project) if defined?(project)
filters = [ filters = [
Gitlab::Markdown::AutolinkFilter, Banzai::Filter::AutolinkFilter,
described_class, described_class,
Gitlab::Markdown::ReferenceGathererFilter Banzai::Filter::ReferenceGathererFilter
] ]
HTML::Pipeline.new(filters, contexts) HTML::Pipeline.new(filters, context)
end end
def reference_pipeline_result(body, contexts = {}) def reference_pipeline_result(body, context = {})
reference_pipeline(contexts).call(body) reference_pipeline(context).call(body)
end end
def reference_filter(html, contexts = {}) def reference_filter(html, context = {})
reference_pipeline(contexts).to_document(html) reference_pipeline(context).to_document(html)
end end
# Modify a String reference to make it invalid # Modify a String reference to make it invalid
......
...@@ -10,17 +10,19 @@ describe RepositoryForkWorker do ...@@ -10,17 +10,19 @@ describe RepositoryForkWorker do
it "creates a new repository from a fork" do it "creates a new repository from a fork" do
expect_any_instance_of(Gitlab::Shell).to receive(:fork_repository).with( expect_any_instance_of(Gitlab::Shell).to receive(:fork_repository).with(
project.path_with_namespace, project.path_with_namespace,
fork_project.namespace.path). fork_project.namespace.path
and_return(true) ).and_return(true)
subject.perform(project.id, subject.perform(
project.id,
project.path_with_namespace, project.path_with_namespace,
fork_project.namespace.path) fork_project.namespace.path)
end end
it "handles bad fork" do it "handles bad fork" do
expect_any_instance_of(Gitlab::Shell).to receive(:fork_repository).and_return(false) expect_any_instance_of(Gitlab::Shell).to receive(:fork_repository).and_return(false)
subject.perform(project.id, subject.perform(
project.id,
project.path_with_namespace, project.path_with_namespace,
fork_project.namespace.path) fork_project.namespace.path)
end end
......
...@@ -15,7 +15,7 @@ describe StuckCiBuildsWorker do ...@@ -15,7 +15,7 @@ describe StuckCiBuildsWorker do
end end
it 'gets dropped if it was updated over 2 days ago' do it 'gets dropped if it was updated over 2 days ago' do
build.update!(updated_at: 2.day.ago) build.update!(updated_at: 2.days.ago)
StuckCiBuildsWorker.new.perform StuckCiBuildsWorker.new.perform
is_expected.to eq('failed') is_expected.to eq('failed')
end end
...@@ -35,7 +35,7 @@ describe StuckCiBuildsWorker do ...@@ -35,7 +35,7 @@ describe StuckCiBuildsWorker do
end end
it "is still #{status}" do it "is still #{status}" do
build.update!(updated_at: 2.day.ago) build.update!(updated_at: 2.days.ago)
StuckCiBuildsWorker.new.perform StuckCiBuildsWorker.new.perform
is_expected.to eq(status) is_expected.to eq(status)
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment