Commit 7d675971 authored by Valery Sizov's avatar Valery Sizov

Merge branch 'ce_upstream' into 'master'

CE upstream



See merge request !600
parents 5fc31b1d de8b05fb
......@@ -29,6 +29,7 @@ stages:
- prepare
- test
- post-test
- pages
# Prepare and merge knapsack tests
.knapsack-state: &knapsack-state
......@@ -41,6 +42,7 @@ stages:
paths:
- knapsack/
artifacts:
expire_in: 31d
paths:
- knapsack/
......@@ -83,8 +85,10 @@ update-knapsack:
- cp knapsack/rspec_report.json ${KNAPSACK_REPORT_PATH}
- knapsack rspec
artifacts:
expire_in: 31d
paths:
- knapsack/
- coverage/
.spinach-knapsack: &spinach-knapsack
stage: test
......@@ -99,8 +103,10 @@ update-knapsack:
- cp knapsack/spinach_report.json ${KNAPSACK_REPORT_PATH}
- knapsack spinach "-r rerun" || retry '[ ! -e tmp/spinach-rerun.txt ] || bundle exec spinach -r rerun $(cat tmp/spinach-rerun.txt)'
artifacts:
expire_in: 31d
paths:
- knapsack/
- coverage/
rspec 0 20: *rspec-knapsack
rspec 1 20: *rspec-knapsack
......@@ -188,14 +194,14 @@ spinach 9 10 ruby23: *spinach-knapsack-ruby23
# Other generic tests
.static-analyses-variables: &static-analyses-variables
.ruby-static-analysis: &ruby-static-analysis
variables:
SIMPLECOV: "false"
USE_DB: "false"
USE_BUNDLE_INSTALL: "true"
.exec: &exec
<<: *static-analyses-variables
<<: *ruby-static-analysis
stage: test
script:
- bundle exec $CI_BUILD_NAME
......@@ -222,12 +228,28 @@ teaspoon:
bundler:audit:
stage: test
<<: *static-analyses-variables
<<: *ruby-static-analysis
only:
- master
script:
- "bundle exec bundle-audit check --update --ignore OSVDB-115941"
coverage:
stage: post-test
services: []
variables:
USE_DB: "false"
USE_BUNDLE_INSTALL: "true"
script:
- bundle exec scripts/merge-simplecov
artifacts:
name: coverage
expire_in: 31d
paths:
- coverage/index.html
- coverage/assets/
# Notify slack in the end
notify:slack:
......@@ -240,3 +262,18 @@ notify:slack:
- tags@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- tags@gitlab-org/gitlab-ee
pages:
before_script: []
stage: pages
dependencies:
- coverage
script:
- mv public/ .public/
- mkdir public/
- mv coverage public/coverage-ruby
artifacts:
paths:
- public
only:
- master
# .simplecov
SimpleCov.start 'rails' do
merge_timeout 3600
end
Please view this file on the master branch, on stable branches it's out of date.
v 8.11.0 (unreleased)
- Remove magic comments (`# encoding: UTF-8`) from Ruby files !5456 (winniehell)
- Remove magic comments (`# encoding: UTF-8`) from Ruby files. !5456 (winniehell)
- Fix CI status icon link underline (ClemMakesApps)
- Fix of 'Commits being passed to custom hooks are already reachable when using the UI'
- Add support for using RequestStore within Sidekiq tasks via SIDEKIQ_REQUEST_STORE env variable
- Optimize maximum user access level lookup in loading of notes
- Limit git rev-list output count to one in forced push check
- Add green outline to New Branch button !5447 (winniehell)
- Clean up unused routes (Josef Strzibny)
- Add green outline to New Branch button. !5447 (winniehell)
- Retrieve rendered HTML from cache in one request
- Fix renaming repository when name contains invalid chararacters under project settings
- Nokogiri's various parsing methods are now instrumented
- Make fork counter always clickable !5463 (winniehell)
- Load project invited groups and members eagerly in ProjectTeam#fetch_members
- Add build event color in HipChat messages (David Eisner)
- Make fork counter always clickable. !5463 (winniehell)
- All created issues, API or WebUI, can be submitted to Akismet for spam check !5333
- Remove `search_id` of labels dropdown filter to fix 'Missleading URI for labels in Merge Requests and Issues view'. !5368 (Scott Le)
- Load project invited groups and members eagerly in `ProjectTeam#fetch_members`
- Make branches sortable without push permission !5462 (winniehell)
- Add GitLab Workhorse version to admin dashboard (Katarzyna Kobierska Ula Budziszewska)
- Add ES6 gem
- Add the `sprockets-es6` gem
- Multiple trigger variables show in separate lines (Katarzyna Kobierska Ula Budziszewska)
- Profile requests when a header is passed
- Make error pages responsive (Takuya Noguchi)
- Change requests_profiles resource constraint to catch virtually any file
v 8.10.2 (unreleased)
v 8.10.3 (unreleased)
v 8.10.2
- User can now search branches by name. !5144
- Page is now properly rendered after committing the first file and creating the first branch. !5399
- Add branch or tag icon to ref in builds page. !5434
- Fix backup restore. !5459
- Use project ID in repository cache to prevent stale data from persisting across projects. !5460
- Fix issue with autocomplete search not working with enter key. !5466
- Add iid to MR API response. !5468
- Disable MySQL foreign key checks before dropping all tables. !5472
- Ensure relative paths for video are rewritten as we do for images. !5474
- Ensure current user can retry a build before showing the 'Retry' button. !5476
- Add ENV variable to skip repository storages validations. !5478
- Added `*.js.es6 gitlab-language=javascript` to `.gitattributes`. !5486
- Don't show comment button in gutter of diffs on MR discussion tab. !5493
- Rescue Rugged::OSError (lock exists) when creating references. !5497
- Fix expand all diffs button in compare view. !5500
- Show release notes in tags list. !5503
- Fix a bug where forking a project from a repository storage to another would fail. !5509
- Fix missing schema update for `20160722221922`. !5512
- Update `gitlab-shell` version to 3.2.1 in the 8.9->8.10 update guide. !5516
v 8.10.1
- Refactor repository storages documentation. !5428
......@@ -26,10 +56,6 @@ v 8.10.1
- Fix bug where replies to commit notes displayed in the MR discussion tab wouldn't show up on the commit page. !5446
- Ignore invalid trusted proxies in X-Forwarded-For header. !5454
- Add links to the real markdown.md file for all GFM examples. !5458
- Remove `search_id` of labels dropdown filter to fix 'Missleading URI for labels in Merge Requests and Issues view' !5368 (Scott Le)
v 8.10.1 (unreleased)
- Fix bug where replies to commit notes displayed in the MR discussion tab wouldn't show up on the commit page
v 8.10.0
- Fix profile activity heatmap to show correct day name (eanplatter)
......
......@@ -235,7 +235,7 @@ gem 'addressable', '~> 2.3.8'
gem 'bootstrap-sass', '~> 3.3.0'
gem 'font-awesome-rails', '~> 4.6.1'
gem 'gemojione', '~> 3.0'
gem 'gon', '~> 6.0.1'
gem 'gon', '~> 6.1.0'
gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 4.1.0'
gem 'jquery-ui-rails', '~> 5.0.0'
......@@ -264,7 +264,7 @@ group :development do
gem 'letter_opener_web', '~> 1.3.0'
gem 'rerun', '~> 0.11.0'
gem 'bullet', '~> 5.0.0', require: false
gem 'bullet', '~> 5.2.0', require: false
gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false
gem 'web-console', '~> 2.0'
......@@ -286,7 +286,7 @@ group :development, :test do
gem 'awesome_print', '~> 1.2.0', require: false
gem 'fuubar', '~> 2.0.0'
gem 'database_cleaner', '~> 1.4.0'
gem 'database_cleaner', '~> 1.5.0'
gem 'factory_girl_rails', '~> 4.6.0'
gem 'rspec-rails', '~> 3.5.0'
gem 'rspec-retry', '~> 0.4.5'
......@@ -314,7 +314,7 @@ group :development, :test do
gem 'rubocop', '~> 0.41.2', require: false
gem 'rubocop-rspec', '~> 1.5.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false
gem 'simplecov', '~> 0.11.0', require: false
gem 'simplecov', '0.12.0', require: false
gem 'flog', '~> 4.3.2', require: false
gem 'flay', '~> 2.6.1', require: false
gem 'bundler-audit', '~> 0.5.0', require: false
......@@ -345,6 +345,8 @@ gem 'mail_room', '~> 0.8'
gem 'email_reply_parser', '~> 0.5.8'
gem 'ruby-prof', '~> 0.15.9'
## CI
gem 'activerecord-session_store', '~> 1.0.0'
gem 'nested_form', '~> 0.3.2'
......
......@@ -59,7 +59,7 @@ GEM
oauth2 (~> 1.0)
asciidoctor (1.5.3)
ast (2.3.0)
attr_encrypted (3.0.1)
attr_encrypted (3.0.3)
encryptor (~> 3.0.0)
attr_required (1.0.0)
autoprefixer-rails (6.2.3)
......@@ -104,9 +104,9 @@ GEM
brakeman (3.3.2)
browser (2.2.0)
builder (3.2.2)
bullet (5.0.0)
bullet (5.2.0)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.9.0)
uniform_notifier (~> 1.10.0)
bundler-audit (0.5.0)
bundler (~> 1.2)
thor (~> 0.18)
......@@ -153,11 +153,11 @@ GEM
d3_rails (3.5.11)
railties (>= 3.1.0)
daemons (1.2.3)
database_cleaner (1.4.1)
database_cleaner (1.5.3)
debug_inspector (0.0.2)
debugger-ruby_core_source (1.3.8)
default_value_for (3.0.1)
activerecord (>= 3.2.0, < 5.0)
default_value_for (3.0.2)
activerecord (>= 3.2.0, < 5.1)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devise (4.1.1)
......@@ -325,7 +325,7 @@ GEM
gollum-rugged_adapter (0.4.2)
mime-types (>= 1.15)
rugged (~> 0.24.0, >= 0.21.3)
gon (6.0.1)
gon (6.1.0)
actionpack (>= 3.0)
json
multi_json
......@@ -533,7 +533,7 @@ GEM
rack-cors (0.4.0)
rack-mount (0.8.3)
rack (>= 1.0.0)
rack-oauth2 (1.2.1)
rack-oauth2 (1.2.3)
activesupport (>= 2.3)
attr_required (>= 0.0.5)
httpclient (>= 2.4)
......@@ -599,7 +599,7 @@ GEM
redis-store (~> 1.1.0)
redis-store (1.1.7)
redis (>= 2.2)
request_store (1.3.0)
request_store (1.3.1)
rerun (0.11.0)
listen (~> 3.0)
responders (2.1.1)
......@@ -644,6 +644,7 @@ GEM
rubocop (>= 0.40.0)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-prof (0.15.9)
ruby-progressbar (1.8.1)
ruby-saml (1.3.0)
nokogiri (>= 1.5.10)
......@@ -696,9 +697,9 @@ GEM
rufus-scheduler (>= 2.0.24)
sidekiq (>= 4.0.0)
simple_oauth (0.1.9)
simplecov (0.11.2)
simplecov (0.12.0)
docile (~> 1.1.0)
json (~> 1.8)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
sinatra (1.4.7)
......@@ -798,7 +799,7 @@ GEM
unicorn-worker-killer (0.4.4)
get_process_mem (~> 0)
unicorn (>= 4, < 6)
uniform_notifier (1.9.0)
uniform_notifier (1.10.0)
uuid (2.3.8)
macaddr (~> 1.0)
validates_hostname (1.0.5)
......@@ -856,7 +857,7 @@ DEPENDENCIES
bootstrap-sass (~> 3.3.0)
brakeman (~> 3.3.0)
browser (~> 2.2)
bullet (~> 5.0.0)
bullet (~> 5.2.0)
bundler-audit (~> 0.5.0)
byebug (~> 8.2.1)
capybara (~> 2.6.2)
......@@ -868,7 +869,7 @@ DEPENDENCIES
connection_pool (~> 2.0)
creole (~> 0.5.0)
d3_rails (~> 3.5.0)
database_cleaner (~> 1.4.0)
database_cleaner (~> 1.5.0)
default_value_for (~> 3.0.0)
devise (~> 4.0)
devise-two-factor (~> 3.0.0)
......@@ -905,7 +906,7 @@ DEPENDENCIES
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.2)
gollum-rugged_adapter (~> 0.4.2)
gon (~> 6.0.1)
gon (~> 6.1.0)
grape (~> 0.13.0)
grape-entity (~> 0.4.2)
gssapi
......@@ -981,6 +982,7 @@ DEPENDENCIES
rubocop (~> 0.41.2)
rubocop-rspec (~> 1.5.0)
ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.15.9)
sanitize (~> 2.0)
sass-rails (~> 5.0.0)
scss_lint (~> 0.47.0)
......@@ -993,7 +995,7 @@ DEPENDENCIES
shoulda-matchers (~> 2.8.0)
sidekiq (~> 4.0)
sidekiq-cron (~> 0.4.0)
simplecov (~> 0.11.0)
simplecov (= 0.12.0)
sinatra (~> 1.4.4)
six (~> 0.2.0)
slack-notifier (~> 1.2.0)
......
......@@ -66,4 +66,12 @@
})();
$(function() {
if ($('.js-importer-status').length) {
var jobsImportPath = $('.js-importer-status').data('jobs-import-path');
var importPath = $('.js-importer-status').data('import-path');
new ImporterStatus(jobsImportPath, importPath);
}
});
}).call(this);
class Admin::RequestsProfilesController < Admin::ApplicationController
def index
@profile_token = Gitlab::RequestProfiler.profile_token
@profiles = Gitlab::RequestProfiler::Profile.all.group_by(&:request_path)
end
def show
clean_name = Rack::Utils.clean_path_info(params[:name])
profile = Gitlab::RequestProfiler::Profile.find(clean_name)
if profile
render text: profile.content
else
redirect_to admin_requests_profiles_path, alert: 'Profile not found'
end
end
end
class Explore::ApplicationController < ApplicationController
skip_before_action :authenticate_user!, :reject_blocked
skip_before_action :authenticate_user!, :reject_blocked!
layout 'explore'
end
class HelpController < ApplicationController
skip_before_action :authenticate_user!, :reject_blocked
skip_before_action :authenticate_user!, :reject_blocked!
layout 'help'
......
class Projects::IssuesController < Projects::ApplicationController
include NotesHelper
include ToggleSubscriptionAction
include IssuableActions
include ToggleAwardEmoji
......@@ -76,6 +77,8 @@ class Projects::IssuesController < Projects::ApplicationController
@note = @project.notes.new(noteable: @issue)
@noteable = @issue
preload_max_access_for_authors(@notes, @project)
respond_to do |format|
format.html
format.json do
......@@ -85,7 +88,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def create
@issue = Issues::CreateService.new(project, current_user, issue_params).execute
@issue = Issues::CreateService.new(project, current_user, issue_params.merge(request: request)).execute
respond_to do |format|
format.html do
......@@ -95,7 +98,7 @@ class Projects::IssuesController < Projects::ApplicationController
render :new
end
end
format.js do |format|
format.js do
@link = @issue.attachment.url.to_js
end
end
......
......@@ -3,6 +3,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
include DiffForPath
include DiffHelper
include IssuableActions
include NotesHelper
include ToggleAwardEmoji
before_action :module_enabled
......@@ -425,6 +426,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@project_wiki,
@ref
)
preload_max_access_for_authors(@notes, @project)
end
def define_widget_vars
......
......@@ -10,11 +10,12 @@ class Projects::TagsController < Projects::ApplicationController
@tags = @repository.tags_sorted_by(@sort)
@tags = Kaminari.paginate_array(@tags).page(params[:page])
@releases = project.releases.where(tag: @tags)
@releases = project.releases.where(tag: @tags.map(&:name))
end
def show
@tag = @repository.find_tag(params[:id])
@release = @project.releases.find_or_initialize_by(tag: @tag.name)
@commit = @repository.commit(@tag.target)
end
......
class SearchController < ApplicationController
skip_before_action :authenticate_user!, :reject_blocked
skip_before_action :authenticate_user!, :reject_blocked!
include SearchHelper
......
......@@ -7,7 +7,7 @@ module NotesHelper
end
def note_editable?(note)
note.editable? && can?(current_user, :admin_note, note)
Ability.can_edit_note?(current_user, note)
end
def noteable_json(noteable)
......@@ -87,14 +87,13 @@ module NotesHelper
end
end
def note_max_access_for_user(note)
@max_access_by_user_id ||= Hash.new do |hash, key|
project = key[:project]
hash[key] = project.team.human_max_access(key[:user_id])
def preload_max_access_for_authors(notes, project)
user_ids = notes.map(&:author_id)
project.team.max_member_access_for_user_ids(user_ids)
end
full_key = { project: note.project, user_id: note.author_id }
@max_access_by_user_id[full_key]
def note_max_access_for_user(note)
note.project.team.human_max_access(note.author_id)
end
def discussion_diff_path(discussion)
......
......@@ -411,6 +411,18 @@ class Ability
GroupProjectsFinder.new(group).execute(user).any?
end
def can_edit_note?(user, note)
return false if !note.editable? || !user.present?
return true if note.author == user || user.admin?
if note.project
max_access_level = note.project.team.max_member_access(user.id)
max_access_level >= Gitlab::Access::MASTER
else
false
end
end
def namespace_abilities(user, namespace)
rules = []
......
......@@ -31,6 +31,10 @@ class Blob < SimpleDelegator
text? && language && language.name == 'SVG'
end
def video?
UploaderHelper::VIDEO_EXT.include?(extname.downcase.delete('.'))
end
def to_partial_path
if lfs_pointer?
'download'
......
......@@ -295,8 +295,8 @@ class Commit
def uri_type(path)
entry = @raw.tree.path(path)
if entry[:type] == :blob
blob = Gitlab::Git::Blob.new(name: entry[:name])
blob.image? ? :raw : :blob
blob = ::Blob.decorate(Gitlab::Git::Blob.new(name: entry[:name]))
blob.image? || blob.video? ? :raw : :blob
else
entry[:type]
end
......
module Spammable
extend ActiveSupport::Concern
included do
attr_accessor :spam
after_validation :check_for_spam, on: :create
end
def spam?
@spam
end
def check_for_spam
self.errors.add(:base, "Your #{self.class.name.underscore} has been recognized as spam and has been discarded.") if spam?
end
end
......@@ -6,6 +6,7 @@ class Issue < ActiveRecord::Base
include Referable
include Sortable
include Taskable
include Spammable
include Elastic::IssuesSearch
WEIGHT_RANGE = 1..9
......
......@@ -54,6 +54,10 @@ class Member < ActiveRecord::Base
default_value_for :notification_level, NotificationSetting.levels[:global]
class << self
def access_for_user_ids(user_ids)
where(user_id: user_ids).has_access.pluck(:user_id, :access_level).to_h
end
def find_by_invite_token(invite_token)
invite_token = Devise.token_generator.digest(self, :invite_token, invite_token)
find_by(invite_token: invite_token)
......
......@@ -481,7 +481,9 @@ class Project < ActiveRecord::Base
def add_import_job
if forked?
job_id = RepositoryForkWorker.perform_async(self.id, forked_from_project.path_with_namespace, self.namespace.path)
job_id = RepositoryForkWorker.perform_async(id, forked_from_project.repository_storage_path,
forked_from_project.path_with_namespace,
self.namespace.path)
else
job_id = RepositoryImportWorker.perform_async(self.id)
end
......@@ -676,8 +678,12 @@ class Project < ActiveRecord::Base
end
def to_param
if persisted? && errors.include?(:path)
path_was
else
path
end
end
def to_reference(_from_project = nil)
path_with_namespace
......
......@@ -46,7 +46,7 @@ class HipchatService < Service
return unless supported_events.include?(data[:object_kind])
message = create_message(data)
return unless message.present?
gate[room].send('GitLab', message, message_options)
gate[room].send('GitLab', message, message_options(data))
end
def test(data)
......@@ -67,8 +67,8 @@ class HipchatService < Service
@gate ||= HipChat::Client.new(token, options)
end
def message_options
{ notify: notify.present? && notify == '1', color: color || 'yellow' }
def message_options(data = nil)
{ notify: notify.present? && notify == '1', color: message_color(data) }
end
def create_message(data)
......@@ -243,6 +243,21 @@ class HipchatService < Service
"#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)"
end
def message_color(data)
build_status_color(data) || color || 'yellow'
end
def build_status_color(data)
return unless data && data[:object_kind] == 'build'
case data[:commit][:status]
when 'success'
'green'
else
'red'
end
end
def project_name
project.name_with_namespace.gsub(/\s/, '')
end
......
......@@ -134,39 +134,63 @@ class ProjectTeam
Gitlab::Access.options_with_owner.key(max_member_access(user_id))
end
# This method assumes project and group members are eager loaded for optimal
# performance.
def max_member_access(user_id)
access = []
# Determine the maximum access level for a group of users in bulk.
#
# Returns a Hash mapping user ID -> maximum access level.
def max_member_access_for_user_ids(user_ids)
user_ids = user_ids.uniq
key = "max_member_access:#{project.id}"
RequestStore.store[key] ||= {}
access = RequestStore.store[key]
# Lookup only the IDs we need
user_ids = user_ids - access.keys
if user_ids.present?
user_ids.each { |id| access[id] = Gitlab::Access::NO_ACCESS }
access += project.members.where(user_id: user_id).has_access.pluck(:access_level)
member_access = project.members.access_for_user_ids(user_ids)
merge_max!(access, member_access)
if group
access += group.members.where(user_id: user_id).has_access.pluck(:access_level)
group_access = group.members.access_for_user_ids(user_ids)
merge_max!(access, group_access)
end
# Each group produces a list of maximum access level per user. We take the
# max of the values produced by each group.
if project.invited_groups.any? && project.allowed_to_share_with_group?
access << max_invited_level(user_id)
project.project_group_links.each do |group_link|
invited_access = max_invited_level_for_users(group_link, user_ids)
merge_max!(access, invited_access)
end
end
end
access
end
access.compact.max
def max_member_access(user_id)
max_member_access_for_user_ids([user_id])[user_id]
end
private
def max_invited_level(user_id)
project.project_group_links.map do |group_link|
# For a given group, return the maximum access level for the user. This is the min of
# the invited access level of the group and the access level of the user within the group.
# For example, if the group has been given DEVELOPER access but the member has MASTER access,
# the user should receive only DEVELOPER access.
def max_invited_level_for_users(group_link, user_ids)
invited_group = group_link.group
access = invited_group.group_members.find_by(user_id: user_id).try(:access_field)
capped_access_level = group_link.group_access
access = invited_group.group_members.access_for_user_ids(user_ids)
# If group member has higher access level we should restrict it
# to max allowed access level
if access && access > group_link.group_access
access = group_link.group_access
end
# If the user is not in the list, assume he/she does not have access
missing_users = user_ids - access.keys
missing_users.each { |id| access[id] = Gitlab::Access::NO_ACCESS }
access
end.compact.max
# Cap the maximum access by the invited level access
access.each { |key, value| access[key] = [value, capped_access_level].min }
end
def fetch_members(level = nil)
......@@ -221,4 +245,8 @@ class ProjectTeam
def group_member_lock
group && group.membership_lock
end
def merge_max!(first_hash, second_hash)
first_hash.merge!(second_hash) { |_key, old, new| old > new ? old : new }
end
end
......@@ -274,6 +274,9 @@ class Repository
rugged.references.create(keep_around_ref_name(sha), sha, force: true)
rescue Rugged::ReferenceError => ex
Rails.logger.error "Unable to create keep-around reference for repository #{path}: #{ex}"
rescue Rugged::OSError => ex
raise unless ex.message =~ /Failed to create locked file/ && ex.message =~ /File exists/
Rails.logger.error "Unable to create keep-around reference for repository #{path}: #{ex}"
end
end
......@@ -1175,6 +1178,10 @@ class Repository
if was_empty || !target_branch
# Create branch
rugged.references.create(ref, newrev)
# If repo was empty expire cache
after_create if was_empty
after_create_branch
else
# Update head
current_head = find_branch(branch).target
......
......@@ -2,10 +2,14 @@ module Issues
class CreateService < Issues::BaseService
def execute
filter_params
label_params = params[:label_ids]
issue = project.issues.new(params.except(:label_ids))
label_params = params.delete(:label_ids)
request = params.delete(:request)
api = params.delete(:api)
issue = project.issues.new(params)
issue.author = params[:author] || current_user
issue.spam = spam_check_service.execute(request, api)
if issue.save
issue.update_attributes(label_ids: label_params)
notification_service.new_issue(issue, current_user)
......@@ -17,5 +21,11 @@ module Issues
issue
end
private
def spam_check_service
SpamCheckService.new(project, current_user, params)
end
end
end
class SpamCheckService < BaseService
include Gitlab::AkismetHelper
attr_accessor :request, :api
def execute(request, api)
@request, @api = request, api
return false unless request || check_for_spam?(project)
return false unless is_spam?(request.env, current_user, text)
create_spam_log
true
end
private
def text
[params[:title], params[:description]].reject(&:blank?).join("\n")
end
def spam_log_attrs
{
user_id: current_user.id,
project_id: project.id,
title: params[:title],
description: params[:description],
source_ip: client_ip(request.env),
user_agent: user_agent(request.env),
noteable_type: 'Issue',
via_api: api
}
end
def create_spam_log
CreateSpamLogService.new(project, current_user, spam_log_attrs).execute
end
end
......@@ -16,3 +16,7 @@
= link_to admin_health_check_path, title: 'Health Check' do
%span
Health Check
= nav_link(controller: :requests_profiles) do
= link_to admin_requests_profiles_path, title: 'Requests Profiles' do
%span
Requests Profiles
- @no_container = true
- page_title 'Requests Profiles'
= render 'admin/background_jobs/head'
%div{ class: container_class }
%h3.page-title
= page_title
.bs-callout.clearfix
Pass the header
%code X-Profile-Token: #{@profile_token}
to profile the request
- if @profiles.present?
.prepend-top-default
- @profiles.each do |path, profiles|
.panel.panel-default.panel-small
.panel-heading
%code= path
%ul.content-list
- profiles.each do |profile|
%li
= link_to profile.time.to_s(:long), admin_requests_profile_path(profile), data: {no_turbolink: true}
- else
%p
No profiles found
......@@ -74,6 +74,4 @@
= link_to "import flow", status_import_bitbucket_path, "data-no-turbolink" => "true"
again.
:javascript
new ImporterStatus("#{jobs_import_bitbucket_path}", "#{import_bitbucket_path}");
.js-importer-status{ data: { jobs_import_path: "#{jobs_import_bitbucket_path}", import_path: "#{import_bitbucket_path}" } }
......@@ -56,5 +56,4 @@
Import
= icon("spinner spin", class: "loading-icon")
:javascript
new ImporterStatus("#{jobs_import_fogbugz_path}", "#{import_fogbugz_path}");
.js-importer-status{ data: { jobs_import_path: "#{jobs_import_fogbugz_path}", import_path: "#{import_fogbugz_path}" } }
......@@ -55,5 +55,4 @@
Import
= icon("spinner spin", class: "loading-icon")
:javascript
new ImporterStatus("#{jobs_import_github_path}", "#{import_github_path}");
.js-importer-status{ data: { jobs_import_path: "#{jobs_import_github_path}", import_path: "#{import_github_path}" } }
......@@ -51,5 +51,4 @@
Import
= icon("spinner spin", class: "loading-icon")
:javascript
new ImporterStatus("#{jobs_import_gitlab_path}", "#{import_gitlab_path}");
.js-importer-status{ data: { jobs_import_path: "#{jobs_import_gitlab_path}", import_path: "#{import_gitlab_path}" } }
......@@ -51,5 +51,4 @@
Import
= icon("spinner spin", class: "loading-icon")
:javascript
new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}");
.js-importer-status{ data: { jobs_import_path: "#{jobs_import_gitorious_path}", import_path: "#{import_gitorious_path}" } }
......@@ -77,5 +77,4 @@
= link_to "import flow", new_import_google_code_path
again.
:javascript
new ImporterStatus("#{jobs_import_google_code_path}", "#{import_google_code_path}");
.js-importer-status{ data: { jobs_import_path: "#{jobs_import_google_code_path}", import_path: "#{import_google_code_path}" } }
......@@ -9,7 +9,7 @@
= link_to admin_root_path, title: 'Overview', class: 'shortcuts-tree' do
%span
Overview
= nav_link(controller: %w(system_info background_jobs logs health_check)) do
= nav_link(controller: %w(system_info background_jobs logs health_check requests_profiles)) do
= link_to admin_system_info_path, title: 'Monitoring' do
%span
Monitoring
......
......@@ -7,10 +7,10 @@
.nav-text
Protected branches can be managed in project settings
- if can? current_user, :push_code, @project
.nav-controls
= form_tag(filter_branches_path, method: :get) do
= search_field_tag :search, params[:search], { placeholder: 'Filter by branch name', id: 'branch-search', class: 'form-control search-text-input input-short', spellcheck: false }
.dropdown.inline
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light
......@@ -27,6 +27,8 @@
= sort_title_recently_updated
= link_to filter_branches_path(sort: 'last_updated') do
= sort_title_oldest_updated
- if can? current_user, :push_code, @project
= link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do
New branch
= render 'projects/commits/mirror_status'
......
......@@ -40,7 +40,7 @@
.block{ class: ("block-first" if !@build.coverage && !(can?(current_user, :read_build, @project) && (@build.artifacts? || @build.artifacts_expired?))) }
.title
Build details
- if @build.retryable?
- if can?(current_user, :update_build, @build) && @build.retryable?
= link_to "Retry", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'pull-right', method: :post
- if @build.merge_request
%p.build-detail-row
......@@ -88,8 +88,9 @@
%p
%span.build-light-text Variables:
%code
- @build.trigger_request.variables.each do |key, value|
%code
#{key}=#{value}
.block
......
......@@ -22,6 +22,8 @@
- if defined?(ref) && ref
- if build.ref
.icon-container
= build.tag? ? icon('tag') : icon('code-fork')
= link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref), class: "monospace branch-name"
- else
.light none
......
......@@ -7,7 +7,7 @@
.content-block.oneline-block.files-changed
.inline-parallel-buttons
- if !expand_all_diffs? && diff_files.any? { |diff_file| diff_file.collapsed? }
= link_to 'Expand all', url_for(params.merge(expand_all_diffs: 1, format: 'html')), class: 'btn btn-default'
= link_to 'Expand all', url_for(params.merge(expand_all_diffs: 1, format: nil)), class: 'btn btn-default'
- if show_whitespace_toggle
- if current_controller?(:commit)
= commit_diff_whitespace_link(@project, @commit, class: 'hidden-xs')
......
......@@ -4,6 +4,7 @@
%h4.prepend-top-0
Project settings
.col-lg-9
.project-edit-errors
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit-project" }, authenticity_token: true do |f|
%fieldset.append-bottom-0
.form-group
......@@ -191,6 +192,7 @@
%h4.prepend-top-0.warning-title
Rename repository
.col-lg-9
= render 'projects/errors'
= form_for([@project.namespace.becomes(Namespace), @project]) do |f|
.form-group.project_name_holder
= f.label :name, class: 'label-light' do
......
......@@ -19,4 +19,9 @@
]
}
var ctx = $("#build_timesChart").get(0).getContext("2d");
new Chart(ctx).Bar(data,{"scaleOverlay": true, responsive: true, maintainAspectRatio: false});
var options = { scaleOverlay: true, responsive: true, maintainAspectRatio: false };
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8
}
new Chart(ctx).Bar(data, options);
......@@ -48,4 +48,9 @@
]
}
var ctx = $("##{scope}Chart").get(0).getContext("2d");
new Chart(ctx).Line(data,{"scaleOverlay": true, responsive: true, maintainAspectRatio: false});
var options = { scaleOverlay: true, responsive: true, maintainAspectRatio: false };
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8
}
new Chart(ctx).Line(data, options);
......@@ -59,6 +59,10 @@
var container = $(selector).parent();
var generateChart = function() {
selector.attr('width', $(container).width());
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8
}
return new Chart(ctx).Bar(data, options);
};
// enabling auto-resizing
......
......@@ -6,4 +6,4 @@
$(".project-edit-errors").html("#{escape_javascript(render('errors'))}");
$('.save-project-loader').hide();
$('.project-edit-container').show();
$('.project-edit-content .btn-save').enable();
$('.edit-project .btn-save').enable();
......@@ -4,7 +4,7 @@ class RepositoryForkWorker
sidekiq_options queue: :gitlab_shell
def perform(project_id, source_path, target_path)
def perform(project_id, forked_from_repository_storage_path, source_path, target_path)
project = Project.find_by_id(project_id)
unless project.present?
......@@ -12,7 +12,8 @@ class RepositoryForkWorker
return
end
result = gitlab_shell.fork_repository(project.repository_storage_path, source_path, target_path)
result = gitlab_shell.fork_repository(forked_from_repository_storage_path, source_path,
project.repository_storage_path, target_path)
unless result
logger.error("Unable to fork project #{project_id} for repository #{source_path} -> #{target_path}")
project.mark_import_as_failed('The project could not be forked.')
......
class RequestsProfilesWorker
include Sidekiq::Worker
sidekiq_options queue: :default
def perform
Gitlab::RequestProfiler.remove_all_profiles
end
end
......@@ -68,6 +68,25 @@
:why: https://opensource.org/licenses/BSD-2-Clause
:versions: []
:when: 2016-05-02 05:55:09.796363000 Z
- - :whitelist
- LGPLv2+
- :who: Stan Hu
:why: Equivalent to LGPLv2
:versions: []
:when: 2016-06-07 17:14:10.907682000 Z
- - :whitelist
- Artistic 2.0
- :who: Josh Frye
:why: Disk/mount information display on Admin pages
:versions: []
:when: 2016-06-29 16:32:45.432113000 Z
- - :whitelist
- Simplified BSD
- :who: Douwe Maan
:why: https://opensource.org/licenses/BSD-2-Clause
:versions: []
:when: 2016-07-26 21:24:07.248480000 Z
# LICENSE BLACKLIST
- - :blacklist
......@@ -175,15 +194,3 @@
:why: https://github.com/jmcnevin/rubypants/blob/master/LICENSE.rdoc
:versions: []
:when: 2016-05-02 05:56:50.696858000 Z
- - :whitelist
- LGPLv2+
- :who: Stan Hu
:why: Equivalent to LGPLv2
:versions: []
:when: 2016-06-07 17:14:10.907682000 Z
- - :whitelist
- Artistic 2.0
- :who: Josh Frye
:why: Disk/mount information display on Admin pages
:versions: []
:when: 2016-06-29 16:32:45.432113000 Z
......@@ -380,6 +380,9 @@ Settings.cron_jobs['gitlab_remove_project_export_worker']['job_class'] = 'Gitlab
Settings.cron_jobs['gitlab_usage_ping_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['gitlab_usage_ping_worker']['cron'] ||= Settings.send(:cron_random_weekly_time)
Settings.cron_jobs['gitlab_usage_ping_worker']['job_class'] = 'GitlabUsagePingWorker'
Settings.cron_jobs['requests_profiles_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['requests_profiles_worker']['cron'] ||= '0 0 * * *'
Settings.cron_jobs['requests_profiles_worker']['job_class'] = 'RequestsProfilesWorker'
#
# GitLab Shell
......
......@@ -26,4 +26,4 @@ def validate_storages
end
end
validate_storages unless Rails.env.test?
validate_storages unless Rails.env.test? || ENV['SKIP_STORAGE_VALIDATION'] == 'true'
Rails.application.configure do |config|
config.middleware.use(Gitlab::RequestProfiler::Middleware)
end
......@@ -7,6 +7,7 @@ Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.add Gitlab::SidekiqMiddleware::ArgumentsLogger if ENV['SIDEKIQ_LOG_ARGUMENTS']
chain.add Gitlab::SidekiqMiddleware::MemoryKiller if ENV['SIDEKIQ_MEMORY_KILLER_MAX_RSS']
chain.add Gitlab::SidekiqMiddleware::RequestStoreMiddleware unless ENV['SIDEKIQ_REQUEST_STORE'] == '0'
end
# Sidekiq-cron: load recurring jobs from gitlab.yml
......
......@@ -42,10 +42,9 @@ Rails.application.routes.draw do
resource :lint, only: [:show, :create]
resources :projects do
resources :projects, only: [:index, :show] do
member do
get :status, to: 'projects#badge'
get :integration
end
end
......@@ -152,13 +151,13 @@ Rails.application.routes.draw do
get :jobs
end
resource :gitlab, only: [:create, :new], controller: :gitlab do
resource :gitlab, only: [:create], controller: :gitlab do
get :status
get :callback
get :jobs
end
resource :bitbucket, only: [:create, :new], controller: :bitbucket do
resource :bitbucket, only: [:create], controller: :bitbucket do
get :status
get :callback
get :jobs
......@@ -251,7 +250,6 @@ Rails.application.routes.draw do
get :projects
get :keys
get :groups
put :team_update
put :block
put :unblock
put :unlock
......@@ -292,6 +290,7 @@ Rails.application.routes.draw do
resource :background_jobs, controller: 'background_jobs', only: [:show]
resource :email, only: [:show, :create]
resource :system_info, controller: 'system_info', only: [:show]
resources :requests_profiles, only: [:index, :show], param: :name, constraints: { name: /.+\.html/ }
resources :namespaces, path: '/projects', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: [] do
root to: 'projects#index', as: :projects
......@@ -311,7 +310,7 @@ Rails.application.routes.draw do
end
end
resource :appearances, path: 'appearance' do
resource :appearances, only: [:show, :create, :update], path: 'appearance' do
member do
get :preview
delete :logo
......@@ -320,7 +319,7 @@ Rails.application.routes.draw do
end
resource :application_settings, only: [:show, :update] do
resources :services
resources :services, only: [:index, :edit, :update]
put :reset_runners_token
put :reset_health_check_token
put :clear_repository_check_states
......@@ -367,7 +366,7 @@ Rails.application.routes.draw do
end
scope module: :profiles do
resource :account, only: [:show, :update] do
resource :account, only: [:show] do
member do
delete :unlink
end
......@@ -379,7 +378,7 @@ Rails.application.routes.draw do
end
end
resource :preferences, only: [:show, :update]
resources :keys
resources :keys, only: [:index, :show, :new, :create, :destroy]
resources :emails, only: [:index, :create, :destroy]
resource :avatar, only: [:destroy]
......@@ -708,7 +707,7 @@ Rails.application.routes.draw do
post '/wikis/*id/markdown_preview', to: 'wikis#markdown_preview', constraints: WIKI_SLUG_ID, as: 'wiki_markdown_preview'
end
resource :repository, only: [:show, :create] do
resource :repository, only: [:create] do
member do
get 'archive', constraints: { format: Gitlab::Regex.archive_formats_regex }
end
......@@ -844,7 +843,7 @@ Rails.application.routes.draw do
end
end
resources :labels, constraints: { id: /\d+/ } do
resources :labels, except: [:show], constraints: { id: /\d+/ } do
collection do
post :generate
post :set_priorities
......@@ -869,7 +868,7 @@ Rails.application.routes.draw do
end
end
resources :project_members, except: [:new, :edit], constraints: { id: /[a-zA-Z.\/0-9_\-#%+]+/ }, concerns: :access_requestable do
resources :project_members, except: [:show, :new, :edit], constraints: { id: /[a-zA-Z.\/0-9_\-#%+]+/ }, concerns: :access_requestable do
collection do
delete :leave
......
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160721081015) do
ActiveRecord::Schema.define(version: 20160722221922) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......
......@@ -38,7 +38,7 @@ GitLab Runner then executes build scripts as the `gitlab-runner` user.
$ sudo gitlab-ci-multi-runner register -n \
--url https://gitlab.com/ci \
--registration-token REGISTRATION_TOKEN \
--executor shell
--executor shell \
--description "My Runner"
```
......
# Akismet
> *Note:* Before 8.11 only issues submitted via the API and for non-project
members were submitted to Akismet.
GitLab leverages [Akismet](http://akismet.com) to protect against spam. Currently
GitLab uses Akismet to prevent users who are not members of a project from
creating spam via the GitLab API. Detected spam will be rejected, and
an entry in the "Spam Log" section in the Admin page will be created.
GitLab uses Akismet to prevent the creation of spam issues on public projects. Issues
created via the WebUI or the API can be submitted to Akismet for review.
Detected spam will be rejected, and an entry in the "Spam Log" section in the
Admin page will be created.
Privacy note: GitLab submits the user's IP and user agent to Akismet. Note that
adding a user to a project will disable the Akismet check and prevent this
......
# From 8.10 to 8.11
Make sure you view this update guide from the tag (version) of GitLab you would
like to install. In most cases this should be the highest numbered production
tag (without rc in it). You can select the tag in the version dropdown at the
top left corner of GitLab (below the menu bar).
If the highest number stable branch is unclear please check the
[GitLab Blog](https://about.gitlab.com/blog/archives.html) for installation
guide links by version.
### 1. Stop server
sudo service gitlab stop
### 2. Backup
```bash
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
```
### 3. Get latest code
```bash
sudo -u git -H git fetch --all
sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
```
For GitLab Community Edition:
```bash
sudo -u git -H git checkout 8-11-stable
```
OR
For GitLab Enterprise Edition:
```bash
sudo -u git -H git checkout 8-11-stable-ee
```
### 4. Update gitlab-shell
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch --all --tags
sudo -u git -H git checkout v3.2.1
```
### 5. Update gitlab-workhorse
Install and compile gitlab-workhorse. This requires
[Go 1.5](https://golang.org/dl) 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 v0.7.8
sudo -u git -H make
```
### 6. Update MySQL permissions
If you are using MySQL you need to grant the GitLab user the necessary
permissions on the database:
```bash
# Login to MySQL
mysql -u root -p
# Grant the GitLab user the REFERENCES permission on the database
GRANT REFERENCES ON `gitlabhq_production`.* TO 'git'@'localhost';
# Quit the database session
mysql> \q
```
### 7. Install libs, migrations, etc.
```bash
cd /home/git/gitlab
# MySQL installations (note: the line below states '--without postgres')
sudo -u git -H bundle install --without postgres development test --deployment
# PostgreSQL installations (note: the line below states '--without mysql')
sudo -u git -H bundle install --without mysql development test --deployment
# Optional: clean up old gems
sudo -u git -H bundle clean
# Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
# Clean up assets and cache
sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
```
### 8. Update configuration files
#### New configuration options for `gitlab.yml`
There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them manually to your current `gitlab.yml`:
```sh
git diff origin/8-10-stable:config/gitlab.yml.example origin/8-11-stable:config/gitlab.yml.example
```
#### Git configuration
Disable `git gc --auto` because GitLab runs `git gc` for us already.
```sh
sudo -u git -H git config --global gc.auto 0
```
#### Nginx configuration
Ensure you're still up-to-date with the latest NGINX configuration changes:
```sh
# For HTTPS configurations
git diff origin/8-10-stable:lib/support/nginx/gitlab-ssl origin/8-11-stable:lib/support/nginx/gitlab-ssl
# For HTTP configurations
git diff origin/8-10-stable:lib/support/nginx/gitlab origin/8-11-stable:lib/support/nginx/gitlab
```
If you are using Apache instead of NGINX please see the updated [Apache templates].
Also note that because Apache does not support upstreams behind Unix sockets you
will need to let gitlab-workhorse listen on a TCP port. You can do this
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-11-stable/lib/support/init.d/gitlab.default.example#L38
#### SMTP configuration
If you're installing from source and use SMTP to deliver mail, you will need to add the following line
to config/initializers/smtp_settings.rb:
```ruby
ActionMailer::Base.delivery_method = :smtp
```
See [smtp_settings.rb.sample] as an example.
[smtp_settings.rb.sample]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-11-stable/config/initializers/smtp_settings.rb.sample#L13?
#### Init script
Ensure you're still up-to-date with the latest init script changes:
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
### 9. Start application
sudo service gitlab start
sudo service nginx restart
### 10. Check application status
Check if GitLab and its environment are configured correctly:
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
To make sure you didn't miss anything run a more thorough check:
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
If all items are green, then congratulations, the upgrade is complete!
## Things went south? Revert to previous version (8.10)
### 1. Revert the code to the previous version
Follow the [upgrade guide from 8.9 to 8.10](8.9-to-8.10.md), except for the
database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup
```bash
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
```
If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above.
......@@ -46,7 +46,7 @@ sudo -u git -H git checkout 8-10-stable-ee
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch --all --tags
sudo -u git -H git checkout v3.2.0
sudo -u git -H git checkout v3.2.1
```
### 5. Update gitlab-workhorse
......
if ENV['SIMPLECOV']
require 'simplecov'
end
require './spec/simplecov_env'
SimpleCovEnv.start!
ENV['RAILS_ENV'] = 'test'
require './config/environment'
......
......@@ -21,17 +21,6 @@ module API
def filter_issues_milestone(issues, milestone)
issues.includes(:milestone).where('milestones.title' => milestone)
end
def create_spam_log(project, current_user, attrs)
params = attrs.merge({
source_ip: client_ip(env),
user_agent: user_agent(env),
noteable_type: 'Issue',
via_api: true
})
::CreateSpamLogService.new(project, current_user, params).execute
end
end
resource :issues do
......@@ -168,15 +157,13 @@ module API
end
project = user_project
text = [attrs[:title], attrs[:description]].reject(&:blank?).join("\n")
if check_for_spam?(project, current_user) && is_spam?(env, current_user, text)
create_spam_log(project, current_user, attrs)
issue = ::Issues::CreateService.new(project, current_user, attrs.merge(request: request, api: true)).execute
if issue.spam?
render_api_error!({ error: 'Spam detected' }, 400)
end
issue = ::Issues::CreateService.new(project, current_user, attrs).execute
if issue.valid?
# Find or create labels and attach to issue. Labels are valid because
# we already checked its name, so there can't be an error here
......
......@@ -20,7 +20,7 @@ module Banzai
process_link_attr el.attribute('href')
end
doc.search('img').each do |el|
doc.css('img, video').each do |el|
process_link_attr el.attribute('src')
end
......
......@@ -7,6 +7,7 @@ module Gitlab
module Access
class AccessDeniedError < StandardError; end
NO_ACCESS = 0
GUEST = 10
REPORTER = 20
DEVELOPER = 30
......
......@@ -17,8 +17,8 @@ module Gitlab
env['HTTP_USER_AGENT']
end
def check_for_spam?(project, user)
akismet_enabled? && !project.team.member?(user)
def check_for_spam?(project)
akismet_enabled? && project.public?
end
def is_spam?(environment, user, text)
......
......@@ -107,16 +107,18 @@ module Gitlab
end
# Fork repository to new namespace
# storage - project's storage path
# forked_from_storage - forked-from project's storage path
# path - project path with namespace
# forked_to_storage - forked-to project's storage path
# fork_namespace - namespace for forked project
#
# Ex.
# fork_repository("/path/to/storage", "gitlab/gitlab-ci", "randx")
# fork_repository("/path/to/forked_from/storage", "gitlab/gitlab-ci", "/path/to/forked_to/storage", "randx")
#
def fork_repository(storage, path, fork_namespace)
def fork_repository(forked_from_storage, path, forked_to_storage, fork_namespace)
Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'fork-project',
storage, "#{path}.git", fork_namespace])
forked_from_storage, "#{path}.git", forked_to_storage,
fork_namespace])
end
# Remove repository from file system
......
require 'fileutils'
module Gitlab
module RequestProfiler
PROFILES_DIR = "#{Gitlab.config.shared.path}/tmp/requests_profiles"
def profile_token
Rails.cache.fetch('profile-token') do
Devise.friendly_token
end
end
module_function :profile_token
def remove_all_profiles
FileUtils.rm_rf(PROFILES_DIR)
end
module_function :remove_all_profiles
end
end
require 'ruby-prof'
module Gitlab
module RequestProfiler
class Middleware
def initialize(app)
@app = app
end
def call(env)
if profile?(env)
call_with_profiling(env)
else
@app.call(env)
end
end
def profile?(env)
header_token = env['HTTP_X_PROFILE_TOKEN']
return unless header_token.present?
profile_token = RequestProfiler.profile_token
return unless profile_token.present?
header_token == profile_token
end
def call_with_profiling(env)
ret = nil
result = RubyProf::Profile.profile do
ret = @app.call(env)
end
printer = RubyProf::CallStackPrinter.new(result)
file_name = "#{env['PATH_INFO'].tr('/', '|')}_#{Time.current.to_i}.html"
file_path = "#{PROFILES_DIR}/#{file_name}"
FileUtils.mkdir_p(PROFILES_DIR)
File.open(file_path, 'wb') do |file|
printer.print(file)
end
ret
end
end
end
end
module Gitlab
module RequestProfiler
class Profile
attr_reader :name, :time, :request_path
alias_method :to_param, :name
def self.all
Dir["#{PROFILES_DIR}/*.html"].map do |path|
new(File.basename(path))
end
end
def self.find(name)
name_dup = name.dup
name_dup << '.html' unless name.end_with?('.html')
file_path = "#{PROFILES_DIR}/#{name_dup}"
return unless File.exist?(file_path)
new(name_dup)
end
def initialize(name)
@name = name
set_attributes
end
def content
File.read("#{PROFILES_DIR}/#{name}")
end
private
def set_attributes
_, path, timestamp = name.split(/(.*)_(\d+)\.html$/)
@request_path = path.tr('|', '/')
@time = Time.at(timestamp.to_i).utc
end
end
end
end
module Gitlab
module SidekiqMiddleware
class RequestStoreMiddleware
def call(worker, job, queue)
RequestStore.begin!
yield
ensure
RequestStore.end!
RequestStore.clear!
end
end
end
end
......@@ -25,6 +25,10 @@ namespace :gitlab do
desc 'Drop all tables'
task :drop_tables => :environment do
connection = ActiveRecord::Base.connection
# If MySQL, turn off foreign key checks
connection.execute('SET FOREIGN_KEY_CHECKS=0') if Gitlab::Database.mysql?
tables = connection.tables
tables.delete 'schema_migrations'
# Truncate schema_migrations to ensure migrations re-run
......@@ -35,6 +39,9 @@ namespace :gitlab do
# MySQL: http://dev.mysql.com/doc/refman/5.7/en/drop-table.html
# Add `IF EXISTS` because cascade could have already deleted a table.
tables.each { |t| connection.execute("DROP TABLE IF EXISTS #{connection.quote_table_name(t)} CASCADE") }
# If MySQL, re-enable foreign key checks
connection.execute('SET FOREIGN_KEY_CHECKS=1') if Gitlab::Database.mysql?
end
desc 'Configures the database by running migrate, or by loading the schema and seeding if needed'
......
......@@ -7,5 +7,5 @@ end
unless Rails.env.production?
desc "GitLab | Run all tests on CI with simplecov"
task test_ci: [:rubocop, :brakeman, 'teaspoon', :spinach, :spec]
task test_ci: [:rubocop, :brakeman, :teaspoon, :spinach, :spec]
end
<!DOCTYPE html>
<html>
<head>
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<title>The page you're looking for could not be found (404)</title>
<style>
body {
color: #666;
text-align: center;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 0;
width: 800px;
margin: auto;
font-size: 14px;
}
......@@ -34,22 +33,33 @@
}
hr {
margin: 18px 0;
max-width: 800px;
margin: 18px auto;
border: 0;
border-top: 1px solid #EEE;
border-bottom: 1px solid white;
}
img {
max-width: 40vw;
}
.container {
margin: auto 20px;
}
</style>
</head>
<body>
<h1>
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" /><br />
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" alt="GitLab Logo" /><br />
404
</h1>
<div class="container">
<h3>The page you're looking for could not be found.</h3>
<hr/>
<hr />
<p>Make sure the address is correct and that the page hasn't moved.</p>
<p>Please contact your GitLab administrator if you think this is a mistake.</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<title>The change you requested was rejected (422)</title>
<style>
body {
color: #666;
text-align: center;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 0;
width: 800px;
margin: auto;
font-size: 14px;
}
......@@ -34,22 +33,33 @@
}
hr {
margin: 18px 0;
max-width: 800px;
margin: 18px auto;
border: 0;
border-top: 1px solid #EEE;
border-bottom: 1px solid white;
}
img {
max-width: 40vw;
}
.container {
margin: auto 20px;
}
</style>
</head>
<body>
<h1>
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" /><br />
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" alt="GitLab Logo" /><br />
422
</h1>
<div class="container">
<h3>The change you requested was rejected.</h3>
<hr />
<p>Make sure you have access to the thing you tried to change.</p>
<p>Please contact your GitLab administrator if you think this is a mistake.</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<title>Something went wrong (500)</title>
<style>
body {
color: #666;
text-align: center;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 0;
width: 800px;
margin: auto;
font-size: 14px;
}
......@@ -34,21 +33,33 @@
}
hr {
margin: 18px 0;
max-width: 800px;
margin: 18px auto;
border: 0;
border-top: 1px solid #EEE;
border-bottom: 1px solid white;
}
img {
max-width: 40vw;
}
.container {
margin: auto 20px;
}
</style>
</head>
<body>
<h1>
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" /><br />
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" alt="GitLab Logo" /><br />
500
</h1>
<div class="container">
<h3>Whoops, something went wrong on our end.</h3>
<hr/>
<hr />
<p>Try refreshing the page, or going back and attempting the action again.</p>
<p><a href="/help" >Please contact your GitLab administrator</a> if this problem persists.</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<title>GitLab is not responding (502)</title>
<style>
body {
color: #666;
text-align: center;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 0;
width: 800px;
margin: auto;
font-size: 14px;
}
......@@ -34,21 +33,33 @@
}
hr {
margin: 18px 0;
max-width: 800px;
margin: 18px auto;
border: 0;
border-top: 1px solid #EEE;
border-bottom: 1px solid white;
}
img {
max-width: 40vw;
}
.container {
margin: auto 20px;
}
</style>
</head>
<body>
<h1>
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" /><br />
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" alt="GitLab Logo" /><br />
502
</h1>
<div class="container">
<h3>Whoops, GitLab is taking too much time to respond.</h3>
<hr/>
<hr />
<p>Try refreshing the page, or going back and attempting the action again.</p>
<p><a href="/help" >Please contact your GitLab administrator</a> if this problem persists.</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<title>GitLab is not responding (503)</title>
<style>
body {
color: #666;
text-align: center;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 0;
width: 800px;
margin: auto;
font-size: 14px;
}
......@@ -34,21 +33,33 @@
}
hr {
margin: 18px 0;
max-width: 800px;
margin: 18px auto;
border: 0;
border-top: 1px solid #EEE;
border-bottom: 1px solid white;
}
img {
max-width: 40vw;
}
.container {
margin: auto 20px;
}
</style>
</head>
<body>
<h1>
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" alt="GitLab Logo"/><br />
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" alt="GitLab Logo" /><br />
503
</h1>
<div class="container">
<h3>Whoops, GitLab is currently unavailable.</h3>
<hr/>
<hr />
<p>Try refreshing the page, or going back and attempting the action again.</p>
<p>Please contact your GitLab administrator if this problem persists.</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<head>
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<title>Deploy in progress</title>
<style>
body {
color: #666;
text-align: center;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 0;
width: 800px;
margin: auto;
font-size: 14px;
}
......@@ -34,21 +33,32 @@
}
hr {
margin: 18px 0;
max-width: 800px;
margin: 18px auto;
border: 0;
border-top: 1px solid #EEE;
border-bottom: 1px solid white;
}
img {
max-width: 40vw;
}
.container {
margin: auto 20px;
}
</style>
</head>
</head>
<body>
<body>
<h1>
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" /><br />
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" alt="GitLab Logo" /><br />
Deploy in progress
</h1>
<div class="container">
<h3>Please try again in a few minutes.</h3>
<hr/>
<hr />
<p>Please contact your GitLab administrator if this problem persists.</p>
</body>
</div>
</body>
</html>
#!/usr/bin/env ruby
require_relative '../spec/simplecov_env'
SimpleCovEnv.configure_profile
module SimpleCov
module ResultMerger
class << self
def resultset_files
Dir.glob(File.join(SimpleCov.coverage_path, '*', '.resultset.json'))
end
def resultset_hashes
resultset_files.map do |path|
begin
JSON.parse(File.read(path))
rescue
{}
end
end
end
def resultset
resultset_hashes.reduce({}, :merge)
end
end
end
end
SimpleCov::ResultMerger.merged_result.format!
......@@ -180,14 +180,13 @@ describe AutocompleteController do
context 'skip_users parameter included' do
before { sign_in(user) }
let(:response_user_ids) { JSON.parse(response.body).map { |user| user['id'] } }
it 'skips the user IDs passed' do
get(:users, skip_users: [user, user2].map(&:id))
expect(response_user_ids).not_to include(user.id)
expect(response_user_ids).not_to include(user2.id)
expect(response_user_ids).not_to be_empty
other_user_ids = [non_member, project.owner, project.creator].map(&:id)
response_user_ids = JSON.parse(response.body).map { |user| user['id'] }
expect(response_user_ids).to contain_exactly(*other_user_ids)
end
end
end
......@@ -243,6 +243,37 @@ describe Projects::IssuesController do
end
end
describe 'POST #create' do
context 'Akismet is enabled' do
before do
allow_any_instance_of(Gitlab::AkismetHelper).to receive(:check_for_spam?).and_return(true)
allow_any_instance_of(Gitlab::AkismetHelper).to receive(:is_spam?).and_return(true)
end
def post_spam_issue
sign_in(user)
spam_project = create(:empty_project, :public)
post :create, {
namespace_id: spam_project.namespace.to_param,
project_id: spam_project.to_param,
issue: { title: 'Spam Title', description: 'Spam lives here' }
}
end
it 'rejects an issue recognized as spam' do
expect{ post_spam_issue }.not_to change(Issue, :count)
expect(response).to render_template(:new)
end
it 'creates a spam log' do
post_spam_issue
spam_logs = SpamLog.all
expect(spam_logs.count).to eq(1)
expect(spam_logs[0].title).to eq('Spam Title')
end
end
end
describe "DELETE #destroy" do
context "when the user is a developer" do
before { sign_in(user) }
......
require 'spec_helper'
describe Projects::TagsController do
let(:project) { create(:project, :public) }
let!(:release) { create(:release, project: project) }
let!(:invalid_release) { create(:release, project: project, tag: 'does-not-exist') }
describe 'GET index' do
before { get :index, namespace_id: project.namespace.to_param, project_id: project.to_param }
it 'returns the tags for the page' do
expect(assigns(:tags).map(&:name)).to eq(['v1.1.0', 'v1.0.0'])
end
it 'returns releases matching those tags' do
expect(assigns(:releases)).to include(release)
expect(assigns(:releases)).not_to include(invalid_release)
end
end
end
......@@ -5,7 +5,8 @@ FactoryGirl.define do
variables do
{
TRIGGER_KEY: 'TRIGGER_VALUE'
TRIGGER_KEY_1: 'TRIGGER_VALUE_1',
TRIGGER_KEY_2: 'TRIGGER_VALUE_2'
}
end
end
......
......@@ -199,9 +199,13 @@ describe "Builds" do
click_link 'Retry'
end
it { expect(page.status_code).to eq(200) }
it { expect(page).to have_content 'pending' }
it { expect(page).to have_content 'Cancel' }
it 'shows the right status and buttons' do
expect(page).to have_http_status(200)
expect(page).to have_content 'pending'
page.within('aside.right-sidebar') do
expect(page).to have_content 'Cancel'
end
end
end
context "Build from other project" do
......@@ -212,7 +216,25 @@ describe "Builds" do
page.driver.post(retry_namespace_project_build_path(@project.namespace, @project, @build2))
end
it { expect(page.status_code).to eq(404) }
it { expect(page).to have_http_status(404) }
end
context "Build that current user is not allowed to retry" do
before do
@build.run!
@build.cancel!
@project.update(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
logout_direct
login_with(create(:user))
visit namespace_project_build_path(@project.namespace, @project, @build)
end
it 'does not show the Retry button' do
page.within('aside.right-sidebar') do
expect(page).not_to have_content 'Retry'
end
end
end
end
......
require 'spec_helper'
describe 'Branches', feature: true do
let(:project) { create(:project) }
let(:repository) { project.repository }
before do
login_as :user
project.team << [@user, :developer]
end
describe 'Initial branches page' do
it 'shows all the branches' do
visit namespace_project_branches_path(project.namespace, project)
repository.branches { |branch| expect(page).to have_content("#{branch.name}") }
expect(page).to have_content("Protected branches can be managed in project settings")
end
end
describe 'Find branches' do
it 'shows filtered branches', js: true do
visit namespace_project_branches_path(project.namespace, project, project.id)
fill_in 'branch-search', with: 'fix'
find('#branch-search').native.send_keys(:enter)
expect(page).to have_content('fix')
expect(find('.all-branches')).to have_selector('li', count: 1)
end
end
end
require 'spec_helper'
describe 'Edit Project Settings', feature: true do
let(:user) { create(:user) }
let(:project) { create(:empty_project, path: 'gitlab', name: 'sample') }
before do
login_as(user)
project.team << [user, :master]
end
describe 'Project settings', js: true do
it 'shows errors for invalid project name' do
visit edit_namespace_project_path(project.namespace, project)
fill_in 'project_name_edit', with: 'foo&bar'
click_button 'Save changes'
expect(page).to have_field 'project_name_edit', with: 'foo&bar'
expect(page).to have_content "Name can contain only letters, digits, '_', '.', dash and space. It must start with letter, digit or '_'."
expect(page).to have_button 'Save changes'
end
end
describe 'Rename repository' do
it 'shows errors for invalid project path/name' do
visit edit_namespace_project_path(project.namespace, project)
fill_in 'Project name', with: 'foo&bar'
fill_in 'Path', with: 'foo&bar'
click_button 'Rename project'
expect(page).to have_field 'Project name', with: 'foo&bar'
expect(page).to have_field 'Path', with: 'foo&bar'
expect(page).to have_content "Name can contain only letters, digits, '_', '.', dash and space. It must start with letter, digit or '_'."
expect(page).to have_content "Path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-', end in '.git' or end in '.atom'"
end
end
end
......@@ -20,7 +20,7 @@ describe BranchesFinder do
result = branches_finder.execute
expect(result.first.name).to eq('expand-collapse-lines')
expect(result.first.name).to eq('video')
end
it 'sorts by last_updated' do
......
require "spec_helper"
describe NotesHelper do
describe "#notes_max_access_for_users" do
let(:owner) { create(:owner) }
let(:group) { create(:group) }
let(:project) { create(:empty_project, namespace: group) }
......@@ -21,17 +20,11 @@ describe NotesHelper do
project.team << [guest, :guest]
end
describe "#notes_max_access_for_users" do
it 'return human access levels' do
original_method = project.team.method(:human_max_access)
expect_any_instance_of(ProjectTeam).to receive(:human_max_access).exactly(3).times do |*args|
original_method.call(args[1])
end
expect(helper.note_max_access_for_user(owner_note)).to eq('Owner')
expect(helper.note_max_access_for_user(master_note)).to eq('Master')
expect(helper.note_max_access_for_user(reporter_note)).to eq('Reporter')
# Call it again to ensure value is cached
expect(helper.note_max_access_for_user(owner_note)).to eq('Owner')
end
it 'handles access in different projects' do
......@@ -43,4 +36,16 @@ describe NotesHelper do
expect(helper.note_max_access_for_user(other_note)).to eq('Reporter')
end
end
describe '#preload_max_access_for_authors' do
it 'loads multiple users' do
expected_access = {
owner.id => Gitlab::Access::OWNER,
master.id => Gitlab::Access::MASTER,
reporter.id => Gitlab::Access::REPORTER
}
expect(helper.preload_max_access_for_authors(notes, project)).to eq(expected_access)
end
end
end
......@@ -17,6 +17,10 @@ describe Banzai::Filter::RelativeLinkFilter, lib: true do
%(<img src="#{path}" />)
end
def video(path)
%(<video src="#{path}"></video>)
end
def link(path)
%(<a href="#{path}">#{path}</a>)
end
......@@ -37,6 +41,12 @@ describe Banzai::Filter::RelativeLinkFilter, lib: true do
doc = filter(image('files/images/logo-black.png'))
expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png'
end
it 'does not modify any relative URL in video' do
doc = filter(video('files/videos/intro.mp4'), commit: project.commit('video'), ref: 'video')
expect(doc.at_css('video')['src']).to eq 'files/videos/intro.mp4'
end
end
shared_examples :relative_to_requested do
......@@ -111,11 +121,26 @@ describe Banzai::Filter::RelativeLinkFilter, lib: true do
end
it 'rebuilds relative URL for an image in the repo' do
doc = filter(image('files/images/logo-black.png'))
expect(doc.at_css('img')['src']).
to eq "/#{project_path}/raw/#{ref}/files/images/logo-black.png"
end
it 'rebuilds relative URL for link to an image in the repo' do
doc = filter(link('files/images/logo-black.png'))
expect(doc.at_css('a')['href']).
to eq "/#{project_path}/raw/#{ref}/files/images/logo-black.png"
end
it 'rebuilds relative URL for a video in the repo' do
doc = filter(video('files/videos/intro.mp4'), commit: project.commit('video'), ref: 'video')
expect(doc.at_css('video')['src']).
to eq "/#{project_path}/raw/video/files/videos/intro.mp4"
end
it 'does not modify relative URL with an anchor only' do
doc = filter(link('#section-1'))
expect(doc.at_css('a')['href']).to eq '#section-1'
......
require 'spec_helper'
describe Gitlab::AkismetHelper, type: :helper do
let(:project) { create(:project) }
let(:project) { create(:project, :public) }
let(:user) { create(:user) }
before do
......@@ -11,13 +11,13 @@ describe Gitlab::AkismetHelper, type: :helper do
end
describe '#check_for_spam?' do
it 'returns true for non-member' do
expect(helper.check_for_spam?(project, user)).to eq(true)
it 'returns true for public project' do
expect(helper.check_for_spam?(project)).to eq(true)
end
it 'returns false for member' do
project.team << [user, :guest]
expect(helper.check_for_spam?(project, user)).to eq(false)
it 'returns false for private project' do
project.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PRIVATE)
expect(helper.check_for_spam?(project)).to eq(false)
end
end
......
require 'spec_helper'
describe Ability, lib: true do
describe '.can_edit_note?' do
let(:project) { create(:empty_project) }
let!(:note) { create(:note_on_issue, project: project) }
context 'using an anonymous user' do
it 'returns false' do
expect(described_class.can_edit_note?(nil, note)).to be_falsy
end
end
context 'using a system note' do
it 'returns false' do
system_note = create(:note, system: true)
user = create(:user)
expect(described_class.can_edit_note?(user, system_note)).to be_falsy
end
end
context 'using users with different access levels' do
let(:user) { create(:user) }
it 'returns true for the author' do
expect(described_class.can_edit_note?(note.author, note)).to be_truthy
end
it 'returns false for a guest user' do
project.team << [user, :guest]
expect(described_class.can_edit_note?(user, note)).to be_falsy
end
it 'returns false for a developer' do
project.team << [user, :developer]
expect(described_class.can_edit_note?(user, note)).to be_falsy
end
it 'returns true for a master' do
project.team << [user, :master]
expect(described_class.can_edit_note?(user, note)).to be_truthy
end
it 'returns true for a group owner' do
group = create(:group)
project.project_group_links.create(
group: group,
group_access: Gitlab::Access::MASTER)
group.add_owner(user)
expect(described_class.can_edit_note?(user, note)).to be_truthy
end
end
end
describe '.users_that_can_read_project' do
context 'using a public project' do
it 'returns all the users' do
......
......@@ -33,6 +33,22 @@ describe Blob do
end
end
describe '#video?' do
it 'is falsey with image extension' do
git_blob = Gitlab::Git::Blob.new(name: 'image.png')
expect(described_class.decorate(git_blob)).not_to be_video
end
UploaderHelper::VIDEO_EXT.each do |ext|
it "is truthy when extension is .#{ext}" do
git_blob = Gitlab::Git::Blob.new(name: "video.#{ext}")
expect(described_class.decorate(git_blob)).to be_video
end
end
end
describe '#to_partial_path' do
def stubbed_blob(overrides = {})
overrides.reverse_merge!(
......
......@@ -259,7 +259,7 @@ describe Ci::Build, models: true do
let(:trigger) { create(:ci_trigger, project: project) }
let(:trigger_request) { create(:ci_trigger_request_with_variables, pipeline: pipeline, trigger: trigger) }
let(:user_trigger_variable) do
{ key: :TRIGGER_KEY, value: 'TRIGGER_VALUE', public: false }
{ key: :TRIGGER_KEY_1, value: 'TRIGGER_VALUE_1', public: false }
end
let(:predefined_trigger_variable) do
{ key: 'CI_BUILD_TRIGGERED', value: 'true', public: true }
......
......@@ -212,6 +212,7 @@ eos
it 'returns the URI type at the given path' do
expect(commit.uri_type('files/html')).to be(:tree)
expect(commit.uri_type('files/images/logo-black.png')).to be(:raw)
expect(project.commit('video').uri_type('files/videos/intro.mp4')).to be(:raw)
expect(commit.uri_type('files/js/application.js')).to be(:blob)
end
......
......@@ -79,6 +79,18 @@ describe Member, models: true do
@accepted_request_member = project.requesters.find_by(user_id: accepted_request_user.id).tap { |m| m.accept_request }
end
describe '.access_for_user_ids' do
it 'returns the right access levels' do
users = [@owner_user.id, @master_user.id]
expected = {
@owner_user.id => Gitlab::Access::OWNER,
@master_user.id => Gitlab::Access::MASTER
}
expect(described_class.access_for_user_ids(users)).to eq(expected)
end
end
describe '.invite' do
it { expect(described_class.invite).not_to include @master }
it { expect(described_class.invite).to include @invited_member }
......
......@@ -353,18 +353,36 @@ describe HipchatService, models: true do
end
context "#message_options" do
it "should be set to the defaults" do
expect(hipchat.send(:message_options)).to eq({ notify: false, color: 'yellow' })
it "is set to the defaults" do
expect(hipchat.__send__(:message_options)).to eq({ notify: false, color: 'yellow' })
end
it "should set notfiy to true" do
it "sets notify to true" do
allow(hipchat).to receive(:notify).and_return('1')
expect(hipchat.send(:message_options)).to eq({ notify: true, color: 'yellow' })
expect(hipchat.__send__(:message_options)).to eq({ notify: true, color: 'yellow' })
end
it "should set the color" do
it "sets the color" do
allow(hipchat).to receive(:color).and_return('red')
expect(hipchat.send(:message_options)).to eq({ notify: false, color: 'red' })
expect(hipchat.__send__(:message_options)).to eq({ notify: false, color: 'red' })
end
context 'with a successful build' do
it 'uses the green color' do
build_data = { object_kind: 'build', commit: { status: 'success' } }
expect(hipchat.__send__(:message_options, build_data)).to eq({ notify: false, color: 'green' })
end
end
context 'with a failed build' do
it 'uses the red color' do
build_data = { object_kind: 'build', commit: { status: 'failed' } }
expect(hipchat.__send__(:message_options, build_data)).to eq({ notify: false, color: 'red' })
end
end
end
end
......
......@@ -382,6 +382,24 @@ describe Project, models: true do
it { expect(@project.to_param).to eq('gitlabhq') }
end
context 'with invalid path' do
it 'returns previous path to keep project suitable for use in URLs when persisted' do
project = create(:empty_project, path: 'gitlab')
project.path = 'foo&bar'
expect(project).not_to be_valid
expect(project.to_param).to eq 'gitlab'
end
it 'returns current path when new record' do
project = build(:empty_project, path: 'gitlab')
project.path = 'foo&bar'
expect(project).not_to be_valid
expect(project.to_param).to eq 'foo&bar'
end
end
end
describe '#repository' do
......@@ -1383,6 +1401,32 @@ describe Project, models: true do
end
end
describe '#add_import_job' do
context 'forked' do
let(:forked_project_link) { create(:forked_project_link) }
let(:forked_from_project) { forked_project_link.forked_from_project }
let(:project) { forked_project_link.forked_to_project }
it 'schedules a RepositoryForkWorker job' do
expect(RepositoryForkWorker).to receive(:perform_async).
with(project.id, forked_from_project.repository_storage_path,
forked_from_project.path_with_namespace, project.namespace.path)
project.add_import_job
end
end
context 'not forked' do
let(:project) { create(:project) }
it 'schedules a RepositoryImportWorker job' do
expect(RepositoryImportWorker).to receive(:perform_async).with(project.id)
project.add_import_job
end
end
end
describe '.where_paths_in' do
context 'without any paths' do
it 'returns an empty relation' do
......
......@@ -151,8 +151,8 @@ describe ProjectTeam, models: true do
it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::MASTER) }
it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::REPORTER) }
it { expect(project.team.max_member_access(guest.id)).to eq(Gitlab::Access::GUEST) }
it { expect(project.team.max_member_access(nonmember.id)).to be_nil }
it { expect(project.team.max_member_access(requester.id)).to be_nil }
it { expect(project.team.max_member_access(nonmember.id)).to eq(Gitlab::Access::NO_ACCESS) }
it { expect(project.team.max_member_access(requester.id)).to eq(Gitlab::Access::NO_ACCESS) }
end
context 'when project is shared with group' do
......@@ -168,14 +168,14 @@ describe ProjectTeam, models: true do
it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::DEVELOPER) }
it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::REPORTER) }
it { expect(project.team.max_member_access(nonmember.id)).to be_nil }
it { expect(project.team.max_member_access(requester.id)).to be_nil }
it { expect(project.team.max_member_access(nonmember.id)).to eq(Gitlab::Access::NO_ACCESS) }
it { expect(project.team.max_member_access(requester.id)).to eq(Gitlab::Access::NO_ACCESS) }
context 'but share_with_group_lock is true' do
before { project.namespace.update(share_with_group_lock: true) }
it { expect(project.team.max_member_access(master.id)).to be_nil }
it { expect(project.team.max_member_access(reporter.id)).to be_nil }
it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::NO_ACCESS) }
it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::NO_ACCESS) }
end
end
end
......@@ -194,8 +194,53 @@ describe ProjectTeam, models: true do
it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::MASTER) }
it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::REPORTER) }
it { expect(project.team.max_member_access(guest.id)).to eq(Gitlab::Access::GUEST) }
it { expect(project.team.max_member_access(nonmember.id)).to be_nil }
it { expect(project.team.max_member_access(requester.id)).to be_nil }
it { expect(project.team.max_member_access(nonmember.id)).to eq(Gitlab::Access::NO_ACCESS) }
it { expect(project.team.max_member_access(requester.id)).to eq(Gitlab::Access::NO_ACCESS) }
end
end
describe "#max_member_access_for_users" do
it 'returns correct roles for different users' do
master = create(:user)
reporter = create(:user)
promoted_guest = create(:user)
guest = create(:user)
project = create(:project)
project.team << [master, :master]
project.team << [reporter, :reporter]
project.team << [promoted_guest, :guest]
project.team << [guest, :guest]
group = create(:group)
group_developer = create(:user)
second_developer = create(:user)
project.project_group_links.create(
group: group,
group_access: Gitlab::Access::DEVELOPER)
group.add_master(promoted_guest)
group.add_developer(group_developer)
group.add_developer(second_developer)
second_group = create(:group)
project.project_group_links.create(
group: second_group,
group_access: Gitlab::Access::MASTER)
second_group.add_master(second_developer)
users = [master, reporter, promoted_guest, guest, group_developer, second_developer].map(&:id)
expected = {
master.id => Gitlab::Access::MASTER,
reporter.id => Gitlab::Access::REPORTER,
promoted_guest.id => Gitlab::Access::DEVELOPER,
guest.id => Gitlab::Access::GUEST,
group_developer.id => Gitlab::Access::DEVELOPER,
second_developer.id => Gitlab::Access::MASTER
}
expect(project.team.max_member_access_for_user_ids(users)).to eq(expected)
end
end
end
......@@ -446,6 +446,43 @@ describe Repository, models: true do
end.to raise_error(GitHooksService::PreReceiveError)
end
end
context 'when target branch is different from source branch' do
before do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, ''])
end
it 'expires branch cache' do
expect(repository).not_to receive(:expire_exists_cache)
expect(repository).not_to receive(:expire_root_ref_cache)
expect(repository).not_to receive(:expire_emptiness_caches)
expect(repository).to receive(:expire_branches_cache)
expect(repository).to receive(:expire_has_visible_content_cache)
expect(repository).to receive(:expire_branch_count_cache)
repository.commit_with_hooks(user, 'new-feature') { sample_commit.id }
end
end
context 'when repository is empty' do
before do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, ''])
end
it 'expires creation and branch cache' do
empty_repository = create(:empty_project, :empty_repo).repository
expect(empty_repository).to receive(:expire_exists_cache)
expect(empty_repository).to receive(:expire_root_ref_cache)
expect(empty_repository).to receive(:expire_emptiness_caches)
expect(empty_repository).to receive(:expire_branches_cache)
expect(empty_repository).to receive(:expire_has_visible_content_cache)
expect(empty_repository).to receive(:expire_branch_count_cache)
empty_repository.commit_file(user, 'CHANGELOG', 'Changelog!',
'Updates file content', 'master', false)
end
end
end
describe '#exists?' do
......
......@@ -531,10 +531,8 @@ describe API::API, api: true do
describe 'POST /projects/:id/issues with spam filtering' do
before do
Grape::Endpoint.before_each do |endpoint|
allow(endpoint).to receive(:check_for_spam?).and_return(true)
allow(endpoint).to receive(:is_spam?).and_return(true)
end
allow_any_instance_of(Gitlab::AkismetHelper).to receive(:check_for_spam?).and_return(true)
allow_any_instance_of(Gitlab::AkismetHelper).to receive(:is_spam?).and_return(true)
end
let(:params) do
......
......@@ -98,7 +98,7 @@ describe Ci::API::API do
{ "key" => "CI_BUILD_TRIGGERED", "value" => "true", "public" => true },
{ "key" => "DB_NAME", "value" => "postgres", "public" => true },
{ "key" => "SECRET_KEY", "value" => "secret_value", "public" => false },
{ "key" => "TRIGGER_KEY", "value" => "TRIGGER_VALUE", "public" => false }
{ "key" => "TRIGGER_KEY_1", "value" => "TRIGGER_VALUE_1", "public" => false }
)
end
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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