Commit b6edaeba authored by Robert Speicher's avatar Robert Speicher

Merge branch 'master' into 8-3-stable

parents 838097a4 76642d7a
......@@ -76,7 +76,7 @@ Style/BlockEndNewline:
Description: 'Put end statement of multiline block on its own line.'
Enabled: true
Style/Blocks:
Style/BlockDelimiters:
Description: >-
Avoid using {...} for multi-line blocks (multiline chaining is
always ugly).
......@@ -232,6 +232,10 @@ Style/EvenOdd:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods'
Enabled: false
Style/ExtraSpacing:
Description: 'Do not use unnecessary spacing.'
Enabled: false
Style/FileName:
Description: 'Use snake_case for source file names.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files'
......@@ -431,6 +435,14 @@ Style/OpMethod:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#other-arg'
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:
Description: >-
Don't use parentheses around the condition of an
......@@ -669,6 +681,13 @@ Style/TrailingWhitespace:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-whitespace'
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:
Description: 'Prefer attr_* methods to trivial readers/writers.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr_family'
......@@ -690,11 +709,6 @@ Style/UnneededPercentQ:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-q'
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:
Description: >-
Don't interpolate global, instance and class variables
......@@ -778,6 +792,10 @@ Metrics/MethodLength:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#short-methods'
Enabled: false
Metrics/ModuleLength:
Description: 'Avoid modules longer than 100 lines of code.'
Enabled: false
#################### Lint ################################
### Warnings
......@@ -961,6 +979,12 @@ Rails/ActionFilter:
Description: 'Enforces consistent use of action filter methods.'
Enabled: true
Rails/Date:
Description: >-
Checks the correct usage of date aware methods,
such as Date.today, Date.current etc.
Enabled: false
Rails/DefaultScope:
Description: 'Checks if the argument passed to default_scope is a block.'
Enabled: false
......@@ -987,6 +1011,12 @@ Rails/ScopeArgs:
Description: 'Checks the arguments of ActiveRecord scopes.'
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:
Description: 'Use validates :attribute, hash of validations.'
Enabled: false
......
Please view this file on the master branch, on stable branches it's out of date.
v 8.3.0 (unreleased)
- Add open_issues_count to project API (Stan Hu)
- Expand character set of usernames created by Omniauth (Corey Hinshaw)
- Add button to automatically merge a merge request when the build succeeds (Zeger-Jan van de Weg)
- Merge when build succeeds (Zeger-Jan van de Weg)
......
......@@ -215,7 +215,7 @@ group :development do
gem "annotate", "~> 2.6.0"
gem "letter_opener", '~> 1.1.2'
gem 'quiet_assets', '~> 1.0.2'
gem 'rerun', '~> 0.10.0'
gem 'rerun', '~> 0.11.0'
gem 'bullet', require: false
gem 'rblineprof', platform: :mri, require: false
gem 'web-console', '~> 2.0'
......@@ -261,7 +261,7 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.0.0'
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 'simplecov', '~> 0.10.0', require: false
gem 'flog', require: false
......
......@@ -117,23 +117,6 @@ GEM
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
json (>= 1.7)
celluloid (0.17.2)
celluloid-essentials
celluloid-extras
celluloid-fsm
celluloid-pool
celluloid-supervision
timers (>= 4.1.1)
celluloid-essentials (0.20.5)
timers (>= 4.1.1)
celluloid-extras (0.20.5)
timers (>= 4.1.1)
celluloid-fsm (0.20.5)
timers (>= 4.1.1)
celluloid-pool (0.20.5)
timers (>= 4.1.1)
celluloid-supervision (0.20.5)
timers (>= 4.1.1)
charlock_holmes (0.7.3)
chunky_png (1.3.5)
cliver (0.3.2)
......@@ -369,7 +352,6 @@ GEM
hipchat (1.5.2)
httparty
mimemagic
hitimes (1.2.3)
html-pipeline (1.11.0)
activesupport (>= 2)
nokogiri (~> 1.4)
......@@ -410,8 +392,7 @@ GEM
addressable (~> 2.3)
letter_opener (1.1.2)
launchy (~> 2.2)
listen (2.9.0)
celluloid (>= 0.15.2)
listen (3.0.5)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
loofah (2.0.3)
......@@ -513,7 +494,7 @@ GEM
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
posix-spawn (0.3.11)
powerpack (0.0.9)
powerpack (0.1.1)
pry (0.10.3)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
......@@ -601,8 +582,8 @@ GEM
redis-store (1.1.7)
redis (>= 2.2)
request_store (1.2.1)
rerun (0.10.0)
listen (~> 2.7, >= 2.7.3)
rerun (0.11.0)
listen (~> 3.0)
responders (2.1.0)
railties (>= 4.2.0, < 5)
rest-client (1.8.0)
......@@ -637,12 +618,13 @@ GEM
rspec-mocks (~> 3.3.0)
rspec-support (~> 3.3.0)
rspec-support (3.3.0)
rubocop (0.28.0)
rubocop (0.35.1)
astrolabe (~> 1.3)
parser (>= 2.2.0.pre.7, < 3.0)
powerpack (~> 0.0.6)
parser (>= 2.2.3.0, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.4)
ruby-progressbar (~> 1.7)
tins (<= 1.6.0)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-progressbar (1.7.5)
......@@ -758,8 +740,6 @@ GEM
thor (0.19.1)
thread_safe (0.3.5)
tilt (1.4.1)
timers (4.1.1)
hitimes
timfel-krb5-auth (0.8.3)
tinder (1.10.1)
eventmachine (~> 1.0)
......@@ -940,12 +920,12 @@ DEPENDENCIES
redis-namespace
redis-rails (~> 4.0.0)
request_store (~> 1.2.0)
rerun (~> 0.10.0)
rerun (~> 0.11.0)
responders (~> 2.0)
rouge (~> 1.10.1)
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.3.0)
rubocop (~> 0.28.0)
rubocop (~> 0.35.0)
ruby-fogbugz (~> 0.2.1)
sanitize (~> 2.0)
sass-rails (~> 4.0.5)
......
......@@ -10,12 +10,12 @@ class @Issue
@initTaskList()
initTaskList: ->
$('.issue-details .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.issue-details .js-task-list-container', @updateTaskList
$('.detail-page-description .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList
disableTaskList: ->
$('.issue-details .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.issue-details .js-task-list-container'
$('.detail-page-description .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container'
# TODO (rspeicher): Make the issue description inline-editable like a note so
# that we can re-use its form here
......
......@@ -40,12 +40,12 @@ class @MergeRequest
this.$('.all-commits').removeClass 'hide'
initTaskList: ->
$('.merge-request-details .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.merge-request-details .js-task-list-container', @updateTaskList
$('.detail-page-description .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList
disableTaskList: ->
$('.merge-request-details .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.merge-request-details .js-task-list-container'
$('.detail-page-description .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container'
# TODO (rspeicher): Make the merge request description inline-editable like a
# note so that we can re-use its form here
......
......@@ -401,6 +401,11 @@ table {
border-bottom: 1px solid $border-color;
height: 57px;
}
&.wide {
margin-left: -$gl-padding;
margin-right: -$gl-padding;
}
}
.center-middle-menu {
......
......@@ -4,7 +4,7 @@
*
*/
.issue-box {
.status-box {
@include border-radius(2px);
display: block;
......@@ -14,22 +14,22 @@
margin-right: 10px;
font-size: $gl-font-size;
&.issue-box-closed {
&.status-box-closed {
background-color: $gl-danger;
color: #FFF;
}
&.issue-box-merged {
&.status-box-merged {
background-color: $gl-primary;
color: #FFF;
}
&.issue-box-open {
&.status-box-open {
background-color: #019875;
color: #FFF;
}
&.issue-box-expired {
&.status-box-expired {
background: #cea61b;
color: #FFF;
}
......
......@@ -143,7 +143,11 @@ ul.controls {
> li {
float: left;
padding-right: 10px;
margin-right: 10px;
&:last-child {
margin-right: 0;
}
.author_link {
display: inline-block;
......
......@@ -87,7 +87,7 @@
.new_note,
.edit_note,
.issuable-description,
.detail-page-description,
.milestone-description,
.wiki-content,
.merge-request-form {
......
......@@ -10,8 +10,7 @@
margin-left: -$gl-padding;
margin-right: -$gl-padding;
color: $gl-gray;
border-bottom: 1px solid #ECEEF1;
border-right: 1px solid #ECEEF1;
border-bottom: 1px solid $border-white-light;
&:target {
background: $hover;
......
.detail-page-header {
margin: -$gl-padding;
padding: 7px $gl-padding;
margin-bottom: 0px;
border-bottom: 1px solid $border-color;
color: #5c5d5e;
font-size: 16px;
line-height: 42px;
.author {
color: #5c5d5e;
}
.identifier {
color: #5c5d5e;
}
}
.detail-page-description {
.title {
margin: 0;
font-size: 23px;
color: #313236;
}
.description {
margin-top: 6px;
p:last-child {
margin-bottom: 0;
}
}
}
......@@ -36,22 +36,8 @@
}
.issuable-details {
.issue-title {
margin: 0;
font-size: 23px;
color: #313236;
}
.description {
margin-top: 6px;
p:last-child {
margin-bottom: 0;
}
}
section {
border-right: 1px solid #ECEEF1;
border-right: 1px solid $border-white-light;
> .tab-content {
margin-right: 1px;
......@@ -136,21 +122,3 @@
margin-right: 2px;
}
}
.issuable-title {
margin: -$gl-padding;
padding: 7px $gl-padding;
margin-bottom: 0px;
border-bottom: 1px solid $border-color;
color: #5c5d5e;
font-size: 16px;
line-height: 42px;
.author {
color: #5c5d5e;
}
.issuable-id {
color: #5c5d5e;
}
}
......@@ -149,3 +149,10 @@ form.edit-issue {
.issue-form .select2-container {
width: 250px !important;
}
.issue-discussion {
.common-note-form {
border-right: 1px solid $border-white-light;
}
}
......@@ -191,7 +191,7 @@
.btn-clipboard {
@extend .pull-right;
margin-right: 18px;
margin-right: 20px;
margin-top: 5px;
position: absolute;
right: 0;
......
......@@ -79,7 +79,6 @@
padding: $gl-padding;
margin-left: -$gl-padding;
margin-right: -$gl-padding;
border-right: 1px solid $border-color;
border-top: 1px solid $border-color;
margin-bottom: -$gl-padding;
}
......
......@@ -35,3 +35,20 @@
border-color: $gl-warning;
}
}
.ci-status-icon-success {
@extend .cgreen;
}
.ci-status-icon-failed {
@extend .cred;
}
.ci-status-icon-running,
.ci-status-icon-pending {
// These are standard text color
}
.ci-status-icon-canceled,
.ci-status-icon-disabled,
.ci-status-icon-not-found,
.ci-status-icon-skipped {
@extend .cgray;
}
class Dashboard::SnippetsController < Dashboard::ApplicationController
def index
@snippets = SnippetsFinder.new.execute(current_user,
@snippets = SnippetsFinder.new.execute(
current_user,
filter: :by_user,
user: current_user,
scope: params[:scope]
......
......@@ -7,7 +7,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits, :builds]
before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds]
before_action :define_show_vars, only: [:show, :diffs, :commits, :builds]
before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds]
before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds, :merge_check]
before_action :ensure_ref_fetched, only: [:show, :diffs, :commits, :builds]
# Allow read any merge_request
......@@ -153,11 +153,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def merge_check
if @merge_request.unchecked?
@merge_request.check_if_can_be_merged
end
closes_issues
@merge_request.check_if_can_be_merged if @merge_request.unchecked?
render partial: "projects/merge_requests/widget/show.html.haml", layout: false
end
......@@ -178,7 +174,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request.update(merge_error: nil)
if params[:merge_when_build_succeeds] && @merge_request.ci_commit && @merge_request.ci_commit.active?
if params[:merge_when_build_succeeds].present? && @merge_request.ci_commit && @merge_request.ci_commit.active?
MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params)
.execute(@merge_request)
@status = :merge_when_build_succeeds
......@@ -299,6 +295,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def define_widget_vars
@ci_commit = @merge_request.ci_commit
closes_issues
end
def invalid_mr
......
......@@ -69,7 +69,7 @@ class Projects::NotesController < Projects::ApplicationController
data = {
author: current_user,
is_award: true,
note: note_params[:note].gsub(":", '')
note: note_params[:note].delete(":")
}
note = noteable.notes.find_by(data)
......
......@@ -61,7 +61,7 @@ module ApplicationHelper
options[:class] ||= ''
options[:class] << ' identicon'
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
project.name[0, 1].upcase
......@@ -204,12 +204,16 @@ module ApplicationHelper
# Returns an HTML-safe String
def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false)
element = content_tag :time, time.to_s,
class: "#{html_class} js-timeago",
class: "#{html_class} js-timeago js-timeago-pending",
datetime: time.getutc.iso8601,
title: time.in_time_zone.stamp('Aug 21, 2011 9:23pm'),
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
end
......
......@@ -10,8 +10,8 @@ module ButtonHelper
# # => "<button class='...' data-clipboard-text='Foo'>...</button>"
#
# # Define the target element
# clipboard_button(clipboard_target: "#foo")
# # => "<button class='...' data-clipboard-target='#foo'>...</button>"
# clipboard_button(clipboard_target: "div#foo")
# # => "<button class='...' data-clipboard-target='div#foo'>...</button>"
#
# See http://clipboardjs.com/#usage
def clipboard_button(data = {})
......
......@@ -12,19 +12,6 @@ module CiStatusHelper
ci_label_for_status(ci_commit.status)
end
def ci_status_color(ci_commit)
case ci_commit.status
when 'success'
'green'
when 'failed'
'red'
when 'running', 'pending'
'yellow'
else
'gray'
end
end
def ci_status_with_icon(status)
content_tag :span, class: "ci-status ci-#{status}" do
ci_icon_for_status(status) + '&nbsp;'.html_safe + ci_label_for_status(status)
......@@ -56,12 +43,11 @@ module CiStatusHelper
end
def render_ci_status(ci_commit)
link_to ci_status_path(ci_commit),
class: "ci-status-link c#{ci_status_color(ci_commit)}",
link_to ci_status_icon(ci_commit),
ci_status_path(ci_commit),
class: "ci-status-link ci-status-icon-#{ci_commit.status.dasherize}",
title: "Build #{ci_status_label(ci_commit)}",
data: { toggle: 'tooltip', placement: 'left' } do
ci_status_icon(ci_commit)
end
data: { toggle: 'tooltip', placement: 'left' }
end
def no_runners_for_project?(project)
......
module ExternalWikiHelper
def get_project_wiki_path(project)
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?
external_wiki_service.properties['external_wiki_url']
else
......
......@@ -65,7 +65,8 @@ module GitlabMarkdownHelper
end
def asciidoc(text)
Gitlab::Asciidoc.render(text,
Gitlab::Asciidoc.render(
text,
project: @project,
current_user: (current_user if defined?(current_user)),
......
......@@ -57,15 +57,15 @@ module IssuesHelper
options_from_collection_for_select(milestones, 'id', 'title', object.milestone_id)
end
def issue_box_class(item)
def status_box_class(item)
if item.respond_to?(:expired?) && item.expired?
'issue-box-expired'
'status-box-expired'
elsif item.respond_to?(:merged?) && item.merged?
'issue-box-merged'
'status-box-merged'
elsif item.closed?
'issue-box-closed'
'status-box-closed'
else
'issue-box-open'
'status-box-open'
end
end
......
......@@ -332,8 +332,7 @@ module ProjectsHelper
namespace_project_blob_path(
project.namespace,
project,
tree_join(project.default_branch,
blob.name)
tree_join(project.default_branch, blob.name)
)
end
end
......
......@@ -79,7 +79,7 @@ module TreeHelper
part_path = File.join(part_path, part) unless 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))
end
end
......
......@@ -51,7 +51,7 @@ module Mentionable
else
self.class.mentionable_attrs.each do |attr, options|
text = send(attr)
options[:cache_key] = [self, attr] if options.delete(:cache)
options[:cache_key] = [self, attr] if options.delete(:cache) && self.persisted?
ext.analyze(text, options)
end
end
......
......@@ -13,7 +13,7 @@ module TokenAuthenticatable
@token_fields << token_field
define_singleton_method("find_by_#{token_field}") do |token|
where(token_field => token).first if token
find_by(token_field => token) if token
end
define_method("ensure_#{token_field}") do
......@@ -37,7 +37,7 @@ module TokenAuthenticatable
def generate_token_for(token_field)
loop do
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
......@@ -194,9 +194,7 @@ class MergeRequest < ActiveRecord::Base
similar_mrs = similar_mrs.where('id not in (?)', self.id) if self.id
if similar_mrs.any?
errors.add :validate_branches,
"Cannot Create: This merge request already exists: #{
similar_mrs.pluck(:title)
}"
"Cannot Create: This merge request already exists: #{similar_mrs.pluck(:title)}"
end
end
end
......
......@@ -45,7 +45,7 @@ class Namespace < ActiveRecord::Base
class << self
def by_path(path)
where('lower(path) = :value', value: path.downcase).first
find_by('lower(path) = :value', value: path.downcase)
end
# Case insensetive search for namespace by path or name
......@@ -148,6 +148,6 @@ class Namespace < ActiveRecord::Base
end
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
......@@ -265,7 +265,7 @@ class Project < ActiveRecord::Base
joins(:namespace).
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
end
......@@ -450,7 +450,7 @@ class Project < ActiveRecord::Base
end
def external_issue_tracker
@external_issues_tracker ||= external_issues_trackers.select(&:activated?).first
@external_issues_tracker ||= external_issues_trackers.find(&:activated?)
end
def can_have_issues_tracker_id?
......@@ -496,7 +496,7 @@ class Project < ActiveRecord::Base
end
def ci_service
@ci_service ||= ci_services.select(&:activated?).first
@ci_service ||= ci_services.find(&:activated?)
end
def avatar_type
......@@ -547,7 +547,7 @@ class Project < ActiveRecord::Base
end
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
end
......@@ -722,7 +722,7 @@ class Project < ActiveRecord::Base
end
def project_member(user)
project_members.where(user_id: user).first
project_members.find_by(user_id: user)
end
def default_branch
......@@ -850,4 +850,8 @@ class Project < ActiveRecord::Base
def build_timeout_in_minutes=(value)
self.build_timeout = value.to_i * 60
end
def open_issues_count
issues.opened.count
end
end
......@@ -27,12 +27,10 @@ class BambooService < CiService
validates :build_key, presence: true, if: :activated?
validates :username,
presence: true,
if: ->(service) { service.password? },
if: :activated?
if: ->(service) { service.activated? && service.password }
validates :password,
presence: true,
if: ->(service) { service.username? },
if: :activated?
if: ->(service) { service.activated? && service.username }
attr_accessor :response
......
......@@ -27,12 +27,10 @@ class TeamcityService < CiService
validates :build_type, presence: true, if: :activated?
validates :username,
presence: true,
if: ->(service) { service.password? },
if: :activated?
if: ->(service) { service.activated? && service.password }
validates :password,
presence: true,
if: ->(service) { service.username? },
if: :activated?
if: ->(service) { service.activated? && service.username }
attr_accessor :response
......
......@@ -220,9 +220,9 @@ class User < ActiveRecord::Base
def find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
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
where(conditions).first
find_by(conditions)
end
end
......@@ -285,7 +285,7 @@ class User < ActiveRecord::Base
end
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
def build_user(attrs = {})
......
- page_title @milestone.title, "Milestones"
- header_title "Milestones", dashboard_milestones_path
.issuable-details
.page-title
.issue-box{ class: "issue-box-#{@milestone.closed? ? 'closed' : 'open'}" }
.detail-page-header
.status-box{ class: "status-box-#{@milestone.closed? ? 'closed' : 'open'}" }
- if @milestone.closed?
Closed
- else
Open
%span.identifier
Milestone #{@milestone.title}
.gray-content-block.middle-block
%h2.issue-title
.detail-page-description.gray-content-block.second-block
%h2.title
= markdown escape_once(@milestone.title), pipeline: :single_line
- if @milestone.complete? && @milestone.active?
......
- page_title @milestone.title, "Milestones"
= render "header_title"
.issuable-details
.page-title
.issue-box{ class: "issue-box-#{@milestone.closed? ? 'closed' : 'open'}" }
.detail-page-header
.status-box{ class: "status-box-#{@milestone.closed? ? 'closed' : 'open'}" }
- if @milestone.closed?
Closed
- else
Open
%span.identifier
Milestone #{@milestone.title}
.pull-right
- if can?(current_user, :admin_milestones, @group)
......@@ -16,8 +16,8 @@
- else
= link_to 'Reopen Milestone', group_milestone_path(@group, @milestone.safe_title, title: @milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
.gray-content-block.middle-block
%h2.issue-title
.detail-page-description.gray-content-block.second-block
%h2.title
= markdown escape_once(@milestone.title), pipeline: :single_line
- if @milestone.complete? && @milestone.active?
......
%div
"#{link_to @note.author_name, user_url(@note.author)} wrote:"
%div
= markdown(@note.note, pipeline: :email)
......@@ -20,8 +20,8 @@
%p
%span.light Commit
= link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace", data: { clipboard_text: @commit.id }
= clipboard_button
= link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
= clipboard_button(clipboard_text: @commit.id)
.commit-info-row
%span.light Authored by
%strong
......
......@@ -19,11 +19,11 @@
- if defined?(commit_sha) && commit_sha
%td
= link_to commit_status.short_sha, namespace_project_commit_path(@project.namespace, @project, commit_status.sha), class: "monospace"
= link_to commit_status.short_sha, namespace_project_commit_path(commit_status.project.namespace, commit_status.project, commit_status.sha), class: "monospace"
%td
- if commit_status.ref
= link_to commit_status.ref, namespace_project_commits_path(@project.namespace, @project, commit_status.ref)
= link_to commit_status.ref, namespace_project_commits_path(commit_status.project.namespace, commit_status.project, commit_status.ref)
- else
.light none
......@@ -66,7 +66,7 @@
%td
.pull-right
- if current_user && can?(current_user, :download_build_artifacts, @project) && commit_status.download_url
- if current_user && can?(current_user, :download_build_artifacts, commit_status.project) && commit_status.download_url
= link_to commit_status.download_url, title: 'Download artifacts' do
%i.fa.fa-download
- if current_user && can?(current_user, :manage_builds, commit_status.project)
......
......@@ -2,14 +2,14 @@
= render "header_title"
.issue
.issue-details.issuable-details
.issuable-title
.issue-box{ class: issue_box_class(@issue) }
.detail-page-header
.status-box{ class: status_box_class(@issue) }
- if @issue.closed?
Closed
- else
Open
%span.issuable-id Issue ##{@issue.iid}
%span.identifier
Issue ##{@issue.iid}
%span.creator
&middot;
opened by #{link_to_member(@project, @issue.author, size: 24)}
......@@ -36,10 +36,11 @@
= icon('pencil-square-o')
Edit
.issue-details.issuable-details
.row
%section.col-md-9
.gray-content-block
%h2.issue-title
.detail-page-description.gray-content-block
%h2.title
= markdown escape_once(@issue.title), pipeline: :single_line
%div
- if @issue.description.present?
......
......@@ -5,8 +5,9 @@
- fluid_layout true
.merge-request{'data-url' => merge_request_path(@merge_request)}
.merge-request-details.issuable-details
= render "projects/merge_requests/show/mr_title"
.merge-request-details.issuable-details
.row
%section.col-md-9
= render "projects/merge_requests/show/mr_box"
......
......@@ -8,8 +8,8 @@
%p
%strong Step 1.
Fetch and check out the branch for this merge request
= clipboard_button
%pre.dark
= clipboard_button(clipboard_target: 'pre#merge-info-1')
%pre.dark#merge-info-1
- if @merge_request.for_fork?
:preserve
git fetch #{h @merge_request.source_project.http_url_to_repo} #{h @merge_request.source_branch}
......@@ -25,8 +25,8 @@
%p
%strong Step 3.
Merge the branch and fix any conflicts that come up
= clipboard_button
%pre.dark
= clipboard_button(clipboard_target: 'pre#merge-info-3')
%pre.dark#merge-info-3
- if @merge_request.for_fork?
:preserve
git checkout #{h @merge_request.target_branch}
......@@ -38,8 +38,8 @@
%p
%strong Step 4.
Push the result of the merge to GitLab
= clipboard_button
%pre.dark
= clipboard_button(clipboard_target: 'pre#merge-info-4')
%pre.dark#merge-info-4
:preserve
git push origin #{h @merge_request.target_branch}
- unless @merge_request.can_be_merged_by?(current_user)
......
.gray-content-block.middle-block
%h2.issue-title
.detail-page-description.gray-content-block.middle-block
%h2.title
= markdown escape_once(@merge_request.title), pipeline: :single_line
%div
......
.issuable-title
.issue-box{ class: issue_box_class(@merge_request) }
.detail-page-header
.status-box{ class: status_box_class(@merge_request) }
= @merge_request.state_human_name
%span.issuable-id Merge Request ##{@merge_request.iid}
%span.identifier
Merge Request ##{@merge_request.iid}
%span.creator
&middot;
opened by #{link_to_member(@project, @merge_request.author, size: 24)}
......
- page_title @milestone.title, "Milestones"
= render "header_title"
.issuable-details
.page-title
.issue-box{ class: issue_box_class(@milestone) }
.detail-page-header
.status-box{ class: status_box_class(@milestone) }
- if @milestone.closed?
Closed
- elsif @milestone.expired?
Expired
- else
Open
%span.identifier
Milestone ##{@milestone.iid}
- if @milestone.expires_at
%span.creator
......@@ -17,10 +17,6 @@
= @milestone.expires_at
.pull-right
- if can?(current_user, :admin_milestone, @project)
= link_to edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-grouped" do
%i.fa.fa-pencil-square-o
Edit
- if @milestone.active?
= link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-grouped"
- else
......@@ -30,8 +26,12 @@
%i.fa.fa-trash-o
Delete
.gray-content-block.middle-block
%h2.issue-title
= link_to edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-grouped" do
%i.fa.fa-pencil-square-o
Edit
.detail-page-description.gray-content-block.second-block
%h2.title
= markdown escape_once(@milestone.title), pipeline: :single_line
%div
- if @milestone.description.present?
......
......@@ -19,7 +19,7 @@
- else
Start the title with <code>[WIP]</code> or <code>WIP:</code> to prevent a
<strong>Work In Progress</strong> merge request from being merged before it's ready.
.form-group.issuable-description
.form-group.detail-page-description
= f.label :description, 'Description', class: 'control-label'
.col-sm-10
......
.issuable-sidebar.issuable-affix
= form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
.block
.title
Cross-project reference
.cross-project-reference
%span#cross-project-reference
= cross_project_reference(@project, issuable)
= clipboard_button(clipboard_target: 'span#cross-project-reference')
.block.assignee
.title
%label
......@@ -62,6 +54,14 @@
= f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
{ selected: issuable.label_ids }, multiple: true, class: 'select2 js-select2', data: { placeholder: "Select labels" }
.block
.title
Cross-project reference
.cross-project-reference
%span#cross-project-reference
= cross_project_reference(@project, issuable)
= clipboard_button(clipboard_target: 'span#cross-project-reference')
= render "shared/issuable/participants", participants: issuable.participants(current_user)
- if current_user
......
.issuable-details
.page-title
.detail-page-header
.snippet-box.has_tooltip{class: visibility_level_color(@snippet.visibility_level), title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: 'body' }}
= visibility_level_icon(@snippet.visibility_level, fw: false)
= visibility_level_label(@snippet.visibility_level)
%span.identifier
Snippet ##{@snippet.id}
%span.creator
&middot; created by #{link_to_member(@project, @snippet.author, size: 24)}
......@@ -20,6 +20,6 @@
- else
= render "snippets/actions"
.gray-content-block.middle-block
%h2.issue-title
.detail-page-description.gray-content-block.second-block
%h2.title
= markdown escape_once(@snippet.title), pipeline: :single_line
......@@ -73,7 +73,7 @@
.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
= link_to "#activity", 'data-toggle' => 'tab' do
Activity
......
......@@ -7,6 +7,7 @@
- [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).
- [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.
- [Profile Settings](profile/README.md)
- [Project Services](project_services/project_services.md) Integrate a project with external services, such as CI and chat.
......
......@@ -58,6 +58,7 @@ Parameters:
"path": "diaspora-client",
"path_with_namespace": "diaspora/diaspora-client",
"issues_enabled": true,
"open_issues_count": 1,
"merge_requests_enabled": true,
"builds_enabled": true,
"wiki_enabled": true,
......@@ -100,6 +101,7 @@ Parameters:
"path": "puppet",
"path_with_namespace": "brightbox/puppet",
"issues_enabled": true,
"open_issues_count": 1,
"merge_requests_enabled": true,
"builds_enabled": true,
"wiki_enabled": true,
......@@ -189,6 +191,7 @@ Parameters:
"path": "diaspora-project-site",
"path_with_namespace": "diaspora/diaspora-project-site",
"issues_enabled": true,
"open_issues_count": 1,
"merge_requests_enabled": true,
"builds_enabled": true,
"wiki_enabled": true,
......
......@@ -348,7 +348,7 @@ GitLab Shell is an SSH access and repository management software developed speci
cd /home/git
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
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
### Initialize Database and Activate Advanced Features
......
......@@ -78,7 +78,7 @@ which should already be on your system from GitLab 8.1.
```bash
cd /home/git/gitlab-workhorse
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
```
......@@ -115,6 +115,12 @@ git diff origin/8-2-stable:config/gitlab.yml.example origin/8-3-stable:config/gi
#### 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
current one:
......@@ -134,6 +140,18 @@ via [/etc/default/gitlab].
[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
#### 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+
Previous versions of GitLab allowed Redis versions >= 2.0 to be used, but
......
......@@ -19,3 +19,4 @@
- ["Work In Progress" Merge Requests](wip_merge_requests.md)
- [Merge When Build Succeeds](merge_when_build_succeeds.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
1. [Bitbucket](import_projects_from_bitbucket.md)
2. [GitHub](import_projects_from_github.md)
3. [GitLab.com](import_projects_from_gitlab_com.md)
4. [FogBugz](import_projects_from_fogbugz.md)
4. [SVN](migrating_from_svn.md)
1. [GitHub](import_projects_from_github.md)
1. [GitLab.com](import_projects_from_gitlab_com.md)
1. [FogBugz](import_projects_from_fogbugz.md)
1. [SVN](migrating_from_svn.md)
### Note
* 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.
In addition to the specific migration documentation above, you can import any
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
SVN stands for Subversion and is a version control system (VCS).
Git is a distributed version control system.
Subversion (SVN) is a central version control system (VCS) while
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
[git documentation pages](https://git-scm.com/book/en/Git-and-Other-Systems-Git-and-Subversion).
Install `svn2git`. On all systems you can install as a Ruby gem if you already
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
user created step by step guide for migrating from SVN to GitLab.
```bash
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
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
step 'I should see new group "Owned" avatar' do
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
step 'I should see the "Remove avatar" button' do
......
......@@ -34,7 +34,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
step 'I should see new avatar' do
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
step 'I should see the "Remove avatar" button' do
......
......@@ -273,7 +273,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see merged request' do
page.within '.issue-box' do
page.within '.status-box' do
expect(page).to have_content "Merged"
end
end
......@@ -283,7 +283,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see reopened merge request "Bug NS-04"' do
page.within '.issue-box' do
page.within '.status-box' do
expect(page).to have_content "Open"
end
end
......
......@@ -37,7 +37,7 @@ class Spinach::Features::Project < Spinach::FeatureSteps
step 'I should see new project avatar' do
expect(@project.avatar).to be_instance_of AvatarUploader
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
step 'I should see the "Remove avatar" button' do
......
......@@ -42,7 +42,7 @@ class Spinach::Features::ProjectSnippets < Spinach::FeatureSteps
end
step 'I click link "Edit"' do
page.within ".page-title" do
page.within ".detail-page-header" do
click_link "Edit"
end
end
......
......@@ -238,13 +238,13 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end
step 'I am redirected to the new file' do
expect(current_path).to eq(namespace_project_blob_path(
@project.namespace, @project, 'master/' + new_file_name))
expect(current_path).to eq(
namespace_project_blob_path(@project.namespace, @project, 'master/' + new_file_name))
end
step 'I am redirected to the new file with directory' do
expect(current_path).to eq(namespace_project_blob_path(
@project.namespace, @project, 'master/' + new_file_name_with_directory))
expect(current_path).to eq(
namespace_project_blob_path(@project.namespace, @project, 'master/' + new_file_name_with_directory))
end
step 'I am redirected to the new merge request page' do
......@@ -252,8 +252,8 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end
step 'I am redirected to the root directory' do
expect(current_path).to eq(namespace_project_tree_path(
@project.namespace, @project, 'master/'))
expect(current_path).to eq(
namespace_project_tree_path(@project.namespace, @project, 'master/'))
end
step "I don't see the permalink link" do
......
......@@ -212,8 +212,8 @@ module SharedPaths
end
step 'I visit a binary file in the repo' do
visit namespace_project_blob_path(@project.namespace, @project, File.join(
root_ref, 'files/images/logo-black.png'))
visit namespace_project_blob_path(@project.namespace, @project,
File.join(root_ref, 'files/images/logo-black.png'))
end
step "I visit my project's commits page" do
......@@ -316,8 +316,8 @@ module SharedPaths
end
step 'I am on the ".gitignore" edit file page' do
expect(current_path).to eq(namespace_project_edit_blob_path(
@project.namespace, @project, File.join(root_ref, '.gitignore')))
expect(current_path).to eq(
namespace_project_edit_blob_path(@project.namespace, @project, File.join(root_ref, '.gitignore')))
end
step 'I visit project source page for "6d39438"' do
......
......@@ -13,7 +13,7 @@ class Spinach::Features::Snippets < Spinach::FeatureSteps
end
step 'I click link "Edit"' do
page.within ".page-title" do
page.within ".detail-page-header" do
click_link "Edit"
end
end
......
......@@ -67,9 +67,10 @@ module API
expose :shared_runners_enabled
expose :creator_id
expose :namespace
expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ | project, options | project.forked? }
expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ |project, options| project.forked? }
expose :avatar_url
expose :star_count, :forks_count
expose :open_issues_count, if: lambda { | project, options | project.issues_enabled? && project.default_issues_tracker? }
end
class ProjectMember < UserBasic
......
......@@ -6,7 +6,7 @@ module Banzai
class MarkdownFilter < HTML::Pipeline::TextFilter
def initialize(text, context = nil, result = nil)
super text, context, result
@text = @text.gsub "\r", ''
@text = @text.delete "\r"
end
def call
......
......@@ -31,7 +31,7 @@ module Banzai
id = text.downcase
id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation
id.gsub!(' ', '-') # replace spaces with dash
id.tr!(' ', '-') # replace spaces with dash
id.squeeze!('-') # replace multiple dashes with one
uniq = (headers[id] > 0) ? "-#{headers[id]}" : ''
......
module Banzai
module Renderer
CACHE_ENABLED = false
# Convert a Markdown String into an HTML-safe String of HTML
#
# Note that while the returned HTML will have been sanitized of dangerous
......@@ -18,7 +20,7 @@ module Banzai
cache_key = context.delete(:cache_key)
cache_key = full_cache_key(cache_key, context[:pipeline])
if cache_key
if cache_key && CACHE_ENABLED
Rails.cache.fetch(cache_key) do
cacheless_render(text, context)
end
......
......@@ -2,7 +2,7 @@ module Gitlab
class Shell
class Error < StandardError; end
class KeyAdder < Struct.new(:io)
KeyAdder = Struct.new(:io) do
def add_key(id, key)
key.gsub!(/[[:space:]]+/, ' ').strip!
io.puts("#{id}\t#{key}")
......
......@@ -11,7 +11,8 @@ module Gitlab
end
def execute
project = ::Projects::CreateService.new(current_user,
project = ::Projects::CreateService.new(
current_user,
name: repo["name"],
path: repo["slug"],
description: repo["description"],
......
......@@ -46,11 +46,11 @@ module Gitlab
end
def added_lines
diff_lines.select(&:added?).size
diff_lines.count(&:added?)
end
def removed_lines
diff_lines.select(&:removed?).size
diff_lines.count(&:removed?)
end
end
end
......
......@@ -199,7 +199,7 @@ module Gitlab
s = s.gsub(/^#/, "\\#")
s = s.gsub(/^-/, "\\-")
s = s.gsub("`", "\\~")
s = s.gsub("\r", "")
s = s.delete("\r")
s = s.gsub("\n", " \n")
s
end
......
......@@ -12,7 +12,8 @@ module Gitlab
end
def execute
project = ::Projects::CreateService.new(current_user,
project = ::Projects::CreateService.new(
current_user,
name: repo.safe_name,
path: repo.path,
namespace: namespace,
......
......@@ -11,7 +11,8 @@ module Gitlab
end
def execute
project = ::Projects::CreateService.new(current_user,
project = ::Projects::CreateService.new(
current_user,
name: repo["name"],
path: repo["path"],
description: repo["description"],
......
......@@ -10,7 +10,8 @@ module Gitlab
end
def execute
::Projects::CreateService.new(current_user,
::Projects::CreateService.new(
current_user,
name: repo.name,
path: repo.path,
description: repo.description,
......
......@@ -171,8 +171,6 @@ module Gitlab
when /\AMilestone:/
"#fee3ff"
when *@closed_statuses.map { |s| nice_status_name(s) }
"#cfcfcf"
when "Status: New"
"#428bca"
when "Status: Accepted"
......@@ -199,6 +197,8 @@ module Gitlab
"#8e44ad"
when "Type: Other"
"#7f8c8d"
when *@closed_statuses.map { |s| nice_status_name(s) }
"#cfcfcf"
else
"#e2e2e2"
end
......@@ -227,7 +227,7 @@ module Gitlab
s = s.gsub("`", "\\`")
# Carriage returns make me sad
s = s.gsub("\r", "")
s = s.delete("\r")
# Markdown ignores single newlines, but we need them as <br />.
s = s.gsub("\n", " \n")
......
......@@ -11,7 +11,8 @@ module Gitlab
end
def execute
project = ::Projects::CreateService.new(current_user,
project = ::Projects::CreateService.new(
current_user,
name: repo.name,
path: repo.name,
description: repo.summary,
......
......@@ -33,12 +33,13 @@ app_user="git"
app_root="/home/$app_user/gitlab"
pid_path="$app_root/tmp/pids"
socket_path="$app_root/tmp/sockets"
rails_socket="$socket_path/gitlab.socket"
web_server_pid_path="$pid_path/unicorn.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid"
mail_room_enabled=false
mail_room_pid_path="$pid_path/mail_room.pid"
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"
shell_path="/bin/bash"
......
......@@ -36,7 +36,7 @@ gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
# '-listenNetwork tcp -listenAddr localhost:8181'.
# The -authBackend setting tells gitlab-workhorse where it can reach
# 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"
# mail_room_enabled specifies whether mail_room, which is used to process incoming email, is enabled.
......
......@@ -10,34 +10,12 @@
## If you change this file in a Merge Request, please also create
## a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
##
##################################
## CHUNKED TRANSFER ##
##################################
##
## It is a known issue that Git-over-HTTP requires chunked transfer encoding [0]
## which is not supported by Nginx < 1.3.9 [1]. As a result, pushing a large object
## with Git (i.e. a single large file) can lead to a 411 error. In theory you can get
## around this by tweaking this configuration file and either:
## - installing an old version of Nginx with the chunkin module [2] compiled in, or
## - using a newer version of Nginx.
##
## At the time of writing we do not know if either of these theoretical solutions works.
## As a workaround users can use Git over SSH to push large files.
##
## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
## [1] https://github.com/agentzh/chunkin-nginx-module#status
## [2] https://github.com/agentzh/chunkin-nginx-module
##
###################################
## configuration ##
###################################
##
## See installation.md#using-https for additional HTTPS configuration details.
upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
}
upstream gitlab-workhorse {
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
}
......@@ -54,10 +32,6 @@ server {
server_tokens off; ## Don't show the nginx version number, a security best practice
root /home/git/gitlab/public;
## Increase this if you want to upload large attachments
## Or if you want to accept large git objects over http
client_max_body_size 20m;
## See app/controllers/application_controller.rb for headers set
## Individual nginx logs for this GitLab vhost
......@@ -65,103 +39,8 @@ server {
error_log /var/log/nginx/gitlab_error.log;
location / {
## Serve static files from defined root folder.
## @gitlab is a named location for the upstream fallback, see below.
try_files $uri /index.html $uri.html @gitlab;
}
## We route uploads through GitLab to prevent XSS and enforce access control.
location /uploads/ {
## If you use HTTPS make sure you disable gzip compression
## to be safe against BREACH attack.
# gzip off;
## https://github.com/gitlabhq/gitlabhq/issues/694
## Some requests take more than 30 seconds.
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://gitlab;
}
## If a file, which is not found in the root folder is requested,
## then the proxy passes the request to the upsteam (gitlab unicorn).
location @gitlab {
## If you use HTTPS make sure you disable gzip compression
## to be safe against BREACH attack.
# gzip off;
## https://github.com/gitlabhq/gitlabhq/issues/694
## Some requests take more than 30 seconds.
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://gitlab;
}
location ~ ^/[\w\.-]+/[\w\.-]+/gitlab-lfs/objects {
client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-workhorse;
return 418;
}
location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ {
client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-workhorse;
return 418;
}
location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive {
client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-workhorse;
return 418;
}
location ~ ^/api/v3/projects/.*/repository/archive {
client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-workhorse;
return 418;
}
# Build artifacts should be submitted to this location
location ~ ^/[\w\.-]+/[\w\.-]+/builds/download {
client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-workhorse;
return 418;
}
# Build artifacts should be submitted to this location
location ~ /ci/api/v1/builds/[0-9]+/artifacts {
client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-workhorse;
return 418;
}
location @gitlab-workhorse {
client_max_body_size 0;
## If you use HTTPS make sure you disable gzip compression
## to be safe against BREACH attack.
# gzip off;
gzip off;
## https://github.com/gitlabhq/gitlabhq/issues/694
## Some requests take more than 30 seconds.
......@@ -169,14 +48,7 @@ server {
proxy_connect_timeout 300;
proxy_redirect off;
# Do not buffer Git HTTP responses
proxy_buffering off;
# The following settings only work with NGINX 1.7.11 or newer
#
# # Pass chunked request bodies to gitlab-workhorse as-is
# proxy_request_buffering off;
# proxy_http_version 1.1;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
......@@ -185,18 +57,4 @@ server {
proxy_pass http://gitlab-workhorse;
}
## Enable gzip compression as per rails guide:
## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
## WARNING: If you are using relative urls remove the block below
## See config/application.rb under "Relative url support" for the list of
## other files that need to be changed for relative url support
location ~ ^/(assets)/ {
root /home/git/gitlab/public;
gzip_static on; # to serve pre-gzipped version
expires max;
add_header Cache-Control public;
}
error_page 502 /502.html;
}
......@@ -14,34 +14,12 @@
## If you change this file in a Merge Request, please also create
## a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
##
##################################
## CHUNKED TRANSFER ##
##################################
##
## It is a known issue that Git-over-HTTP requires chunked transfer encoding [0]
## which is not supported by Nginx < 1.3.9 [1]. As a result, pushing a large object
## with Git (i.e. a single large file) can lead to a 411 error. In theory you can get
## around this by tweaking this configuration file and either:
## - installing an old version of Nginx with the chunkin module [2] compiled in, or
## - using a newer version of Nginx.
##
## At the time of writing we do not know if either of these theoretical solutions works.
## As a workaround users can use Git over SSH to push large files.
##
## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
## [1] https://github.com/agentzh/chunkin-nginx-module#status
## [2] https://github.com/agentzh/chunkin-nginx-module
##
###################################
## configuration ##
###################################
##
## See installation.md#using-https for additional HTTPS configuration details.
upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
}
upstream gitlab-workhorse {
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
}
......@@ -61,7 +39,6 @@ server {
error_log /var/log/nginx/gitlab_error.log;
}
## HTTPS host
server {
listen 0.0.0.0:443 ssl;
......@@ -70,10 +47,6 @@ server {
server_tokens off; ## Don't show the nginx version number, a security best practice
root /home/git/gitlab/public;
## Increase this if you want to upload large attachments
## Or if you want to accept large git objects over http
client_max_body_size 20m;
## Strong SSL Security
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
ssl on;
......@@ -110,104 +83,7 @@ server {
error_log /var/log/nginx/gitlab_error.log;
location / {
## Serve static files from defined root folder.
## @gitlab is a named location for the upstream fallback, see below.
try_files $uri /index.html $uri.html @gitlab;
}
## We route uploads through GitLab to prevent XSS and enforce access control.
location /uploads/ {
## If you use HTTPS make sure you disable gzip compression
## to be safe against BREACH attack.
gzip off;
## https://github.com/gitlabhq/gitlabhq/issues/694
## Some requests take more than 30 seconds.
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://gitlab;
}
## If a file, which is not found in the root folder is requested,
## then the proxy passes the request to the upsteam (gitlab unicorn).
location @gitlab {
## If you use HTTPS make sure you disable gzip compression
## to be safe against BREACH attack.
gzip off;
## https://github.com/gitlabhq/gitlabhq/issues/694
## Some requests take more than 30 seconds.
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://gitlab;
}
location ~ ^/[\w\.-]+/[\w\.-]+/gitlab-lfs/objects {
client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-workhorse;
return 418;
}
location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ {
client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-workhorse;
return 418;
}
location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive {
client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-workhorse;
return 418;
}
location ~ ^/api/v3/projects/.*/repository/archive {
client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-workhorse;
return 418;
}
# Build artifacts should be submitted to this location
location ~ ^/[\w\.-]+/[\w\.-]+/builds/download {
client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-workhorse;
return 418;
}
# Build artifacts should be submitted to this location
location ~ /ci/api/v1/builds/[0-9]+/artifacts {
client_max_body_size 0;
# 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-workhorse;
return 418;
}
location @gitlab-workhorse {
client_max_body_size 0;
## If you use HTTPS make sure you disable gzip compression
## to be safe against BREACH attack.
gzip off;
## https://github.com/gitlabhq/gitlabhq/issues/694
......@@ -216,14 +92,7 @@ server {
proxy_connect_timeout 300;
proxy_redirect off;
# Do not buffer Git HTTP responses
proxy_buffering off;
# The following settings only work with NGINX 1.7.11 or newer
#
# # Pass chunked request bodies to gitlab-workhorse as-is
# proxy_request_buffering off;
# proxy_http_version 1.1;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
......@@ -232,18 +101,4 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://gitlab-workhorse;
}
## Enable gzip compression as per rails guide:
## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
## WARNING: If you are using relative urls remove the block below
## See config/application.rb under "Relative url support" for the list of
## other files that need to be changed for relative url support
location ~ ^/(assets)/ {
root /home/git/gitlab/public;
gzip_static on; # to serve pre-gzipped version
expires max;
add_header Cache-Control public;
}
error_page 502 /502.html;
}
......@@ -43,7 +43,8 @@ FactoryGirl.define do
end
after(:create) do |user, evaluator|
user.identities << create(:identity,
user.identities << create(
:identity,
provider: evaluator.provider,
extern_uid: evaluator.extern_uid
)
......
......@@ -13,7 +13,7 @@ feature 'Issue filtering by Milestone', feature: true do
visit_issues(project)
filter_by_milestone(Milestone::None.title)
expect(page).to have_css('.issue-title', count: 1)
expect(page).to have_css('.title', count: 1)
end
scenario 'filters by a specific Milestone', js: true do
......@@ -23,7 +23,7 @@ feature 'Issue filtering by Milestone', feature: true do
visit_issues(project)
filter_by_milestone(milestone.title)
expect(page).to have_css('.issue-title', count: 1)
expect(page).to have_css('.title', count: 1)
end
def visit_issues(project)
......
......@@ -16,11 +16,11 @@ describe 'Group access', feature: true do
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}")
create(:user).tap do |user|
group.add_user(user, level)
grp.add_user(user, level)
end
end
......
......@@ -47,7 +47,7 @@ feature 'Task Lists', feature: true do
it 'contains the required selectors' do
visit_issue(project, issue)
container = '.issue-details .description.js-task-list-container'
container = '.detail-page-description .description.js-task-list-container'
expect(page).to have_selector(container)
expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox")
......@@ -123,7 +123,7 @@ feature 'Task Lists', feature: true do
it 'contains the required selectors' do
visit_merge_request(project, merge)
container = '.merge-request-details .description.js-task-list-container'
container = '.detail-page-description .description.js-task-list-container'
expect(page).to have_selector(container)
expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox")
......
......@@ -263,11 +263,12 @@ describe ApplicationHelper do
end
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
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
it 'accepts a custom tooltip placement' do
......@@ -278,7 +279,7 @@ describe ApplicationHelper do
el = element.next_element
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
it 'allows the script tag to be excluded' do
......
......@@ -6,13 +6,8 @@ describe CiStatusHelper do
let(:success_commit) { double("Ci::Commit", status: 'success') }
let(:failed_commit) { double("Ci::Commit", status: 'failed') }
describe 'ci_status_color' do
it { expect(ci_status_icon(success_commit)).to include('fa-check') }
it { expect(ci_status_icon(failed_commit)).to include('fa-close') }
end
describe 'ci_status_color' do
it { expect(ci_status_color(success_commit)).to eq('green') }
it { expect(ci_status_color(failed_commit)).to eq('red') }
describe 'ci_status_icon' do
it { expect(helper.ci_status_icon(success_commit)).to include('fa-check') }
it { expect(helper.ci_status_icon(failed_commit)).to include('fa-close') }
end
end
......@@ -9,7 +9,7 @@ describe GroupsHelper do
group.avatar = File.open(avatar_file_path)
group.save!
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
it 'should give default avatar_icon when no avatar is present' do
......
%a.btn-close
.issue-details
.detail-page-description
.description.js-task-list-container
.wiki
%ul.task-list
......
%a.btn-close
.merge-request-details
.detail-page-description
.description.js-task-list-container
.wiki
%ul.task-list
......
......@@ -37,14 +37,14 @@ describe Ci::Commit, models: true do
it 'returns ordered list of commits' do
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])
end
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
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
expect(project.ci_commits.ordered).to eq([commit2, commit4, commit3, commit1])
end
......
......@@ -81,7 +81,7 @@ describe Key, models: true do
it 'rejects the multiple line key' do
key = build(:key)
key.key.gsub!(' ', "\n")
key.key.tr!(' ', "\n")
expect(key).not_to be_valid
end
end
......
......@@ -57,23 +57,21 @@ describe HipchatService, models: true do
it 'should use v1 if version is provided' do
allow(hipchat).to receive(:api_version).and_return('v1')
expect(HipChat::Client).to receive(:new).
with(token,
expect(HipChat::Client).to receive(:new).with(
token,
api_version: 'v1',
server_url: server_url).
and_return(
double(:hipchat_service).as_null_object)
server_url: server_url
).and_return(double(:hipchat_service).as_null_object)
hipchat.execute(push_sample_data)
end
it 'should use v2 as the version when nothing is provided' do
allow(hipchat).to receive(:api_version).and_return('')
expect(HipChat::Client).to receive(:new).
with(token,
expect(HipChat::Client).to receive(:new).with(
token,
api_version: 'v2',
server_url: server_url).
and_return(
double(:hipchat_service).as_null_object)
server_url: server_url
).and_return(double(:hipchat_service).as_null_object)
hipchat.execute(push_sample_data)
end
......
......@@ -172,13 +172,17 @@ describe Project, models: true do
describe '#get_issue' do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let!(:issue) { create(:issue, project: project) }
context 'with default issues tracker' do
it 'returns an issue' do
expect(project.get_issue(issue.iid)).to eq issue
end
it 'returns count of open issues' do
expect(project.open_issues_count).to eq(1)
end
it 'returns nil when no issue found' do
expect(project.get_issue(999)).to be_nil
end
......
......@@ -462,8 +462,8 @@ describe User, models: true do
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.downcase).to_a).to eq([user2])
expect(User.search(user1.username.downcase).to_a.count).to eq(2)
expect(User.search(user2.username.downcase).to_a.count).to eq(1)
expect(User.search(user1.username.downcase).to_a.size).to eq(2)
expect(User.search(user2.username.downcase).to_a.size).to eq(1)
end
end
......
......@@ -6,7 +6,7 @@ describe API::API, api: true do
let(:user) { create(:user) }
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_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!(: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") }
......
......@@ -65,6 +65,22 @@ describe API::API, api: true do
expect(json_response.first.keys).to include('tag_list')
end
it 'should include open_issues_count' do
get api('/projects', user)
expect(response.status).to eq 200
expect(json_response).to be_an Array
expect(json_response.first.keys).to include('open_issues_count')
end
it 'should not include open_issues_count' do
project.update_attributes( { issues_enabled: false } )
get api('/projects', user)
expect(response.status).to eq 200
expect(json_response).to be_an Array
expect(json_response.first.keys).not_to include('open_issues_count')
end
context 'and using search' do
it 'should return searched project' do
get api('/projects', user), { search: project.name }
......
......@@ -29,7 +29,7 @@ describe API::API, api: true do
if required_attributes.empty?
expected_code = 200
else
attrs.delete(required_attributes.shuffle.first)
attrs.delete(required_attributes.sample)
expected_code = 400
end
......
......@@ -42,7 +42,7 @@ describe UpdateSnippetService, services: true do
CreateSnippetService.new(project, user, opts).execute
end
def update_snippet(project = nil, user, snippet, opts)
def update_snippet(project, user, snippet, opts)
UpdateSnippetService.new(project, user, snippet, opts).execute
end
end
......@@ -10,17 +10,19 @@ describe RepositoryForkWorker do
it "creates a new repository from a fork" do
expect_any_instance_of(Gitlab::Shell).to receive(:fork_repository).with(
project.path_with_namespace,
fork_project.namespace.path).
and_return(true)
fork_project.namespace.path
).and_return(true)
subject.perform(project.id,
subject.perform(
project.id,
project.path_with_namespace,
fork_project.namespace.path)
end
it "handles bad fork" do
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,
fork_project.namespace.path)
end
......
......@@ -15,7 +15,7 @@ describe StuckCiBuildsWorker do
end
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
is_expected.to eq('failed')
end
......@@ -35,7 +35,7 @@ describe StuckCiBuildsWorker do
end
it "is still #{status}" do
build.update!(updated_at: 2.day.ago)
build.update!(updated_at: 2.days.ago)
StuckCiBuildsWorker.new.perform
is_expected.to eq(status)
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