Merge branch 'master' into diff-line-comment-vuejs
# Conflicts: # db/schema.rb
|
@ -28,6 +28,7 @@ stages:
|
|||
- prepare
|
||||
- test
|
||||
- post-test
|
||||
- pages
|
||||
|
||||
# Prepare and merge knapsack tests
|
||||
.knapsack-state: &knapsack-state
|
||||
|
@ -40,6 +41,7 @@ stages:
|
|||
paths:
|
||||
- knapsack/
|
||||
artifacts:
|
||||
expire_in: 31d
|
||||
paths:
|
||||
- knapsack/
|
||||
|
||||
|
@ -81,8 +83,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
|
||||
|
@ -97,8 +101,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
|
||||
|
@ -186,14 +192,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
|
||||
|
@ -220,12 +226,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:
|
||||
|
@ -238,3 +260,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
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
# .simplecov
|
||||
SimpleCov.start 'rails' do
|
||||
merge_timeout 3600
|
||||
end
|
34
CHANGELOG
|
@ -1,27 +1,57 @@
|
|||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 8.11.0 (unreleased)
|
||||
- Fix the title of the toggle dropdown button. !5515 (herminiotorres)
|
||||
- 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
|
||||
- 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
|
||||
- Add a way to send an email and create an issue based on private personal token. Find the email address from issues page. !3363
|
||||
- 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
|
||||
- The overhead of instrumented method calls has been reduced
|
||||
- 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 the `sprockets-es6` gem
|
||||
- Multiple trigger variables show in separate lines (Katarzyna Kobierska Ula Budziszewska)
|
||||
- Profile requests when a header is passed
|
||||
- Add commit stats in commit api. !5517 (dixpac)
|
||||
- Make error pages responsive (Takuya Noguchi)
|
||||
- Change requests_profiles resource constraint to catch virtually any file
|
||||
- Reduce number of queries made for merge_requests/:id/diffs
|
||||
|
||||
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
|
||||
- Disable MySQL foreign key checks before dropping all tables. !5472
|
||||
- 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
|
||||
|
|
|
@ -1 +1 @@
|
|||
3.2.0
|
||||
3.2.1
|
||||
|
|
10
Gemfile
|
@ -225,7 +225,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'
|
||||
|
@ -253,7 +253,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'
|
||||
|
||||
|
@ -275,7 +275,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'
|
||||
|
@ -303,7 +303,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
|
||||
|
@ -334,6 +334,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'
|
||||
|
|
34
Gemfile.lock
|
@ -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)
|
||||
|
@ -303,7 +303,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
|
||||
|
@ -509,7 +509,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)
|
||||
|
@ -575,7 +575,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)
|
||||
|
@ -620,6 +620,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)
|
||||
|
@ -672,9 +673,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)
|
||||
|
@ -774,7 +775,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)
|
||||
version_sorter (2.0.0)
|
||||
|
@ -829,7 +830,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)
|
||||
|
@ -841,7 +842,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)
|
||||
|
@ -874,7 +875,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)
|
||||
hamlit (~> 2.5)
|
||||
|
@ -948,6 +949,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)
|
||||
|
@ -960,7 +962,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);
|
||||
|
|
|
@ -189,6 +189,7 @@
|
|||
_this.groupId = $(select).data('group-id');
|
||||
_this.showCurrentUser = $(select).data('current-user');
|
||||
_this.authorId = $(select).data('author-id');
|
||||
_this.skipUsers = $(select).data('skip-users');
|
||||
showNullUser = $(select).data('null-user');
|
||||
showAnyUser = $(select).data('any-user');
|
||||
showEmailUser = $(select).data('email-user');
|
||||
|
@ -320,7 +321,8 @@
|
|||
project_id: this.projectId,
|
||||
group_id: this.groupId,
|
||||
current_user: this.showCurrentUser,
|
||||
author_id: this.authorId
|
||||
author_id: this.authorId,
|
||||
skip_users: this.skipUsers
|
||||
},
|
||||
dataType: "json"
|
||||
}).done(function(users) {
|
||||
|
|
|
@ -99,3 +99,33 @@ form.edit-issue {
|
|||
.issue-form .select2-container {
|
||||
width: 250px !important;
|
||||
}
|
||||
|
||||
.issues-footer {
|
||||
padding-top: $gl-padding;
|
||||
padding-bottom: 37px;
|
||||
}
|
||||
|
||||
.issue-email-modal-btn {
|
||||
padding: 0;
|
||||
color: $gl-link-color;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.email-modal-input-group {
|
||||
margin-bottom: 10px;
|
||||
|
||||
.form-control {
|
||||
background-color: $white-light;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: $background-color;
|
||||
border: 1px solid $border-gray-light;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
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
|
|
@ -5,6 +5,7 @@ class AutocompleteController < ApplicationController
|
|||
def users
|
||||
@users ||= User.none
|
||||
@users = @users.search(params[:search]) if params[:search].present?
|
||||
@users = @users.where.not(id: params[:skip_users]) if params[:skip_users].present?
|
||||
@users = @users.active
|
||||
@users = @users.reorder(:name)
|
||||
@users = @users.page(params[:page])
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Explore::ApplicationController < ApplicationController
|
||||
skip_before_action :authenticate_user!, :reject_blocked
|
||||
skip_before_action :authenticate_user!, :reject_blocked!
|
||||
|
||||
layout 'explore'
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class HelpController < ApplicationController
|
||||
skip_before_action :authenticate_user!, :reject_blocked
|
||||
skip_before_action :authenticate_user!, :reject_blocked!
|
||||
|
||||
layout 'help'
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ class Projects::BranchesController < Projects::ApplicationController
|
|||
before_action :authorize_push_code!, only: [:new, :create, :destroy]
|
||||
|
||||
def index
|
||||
@sort = params[:sort].presence || 'name'
|
||||
@branches = BranchesFinder.new(@repository, params).execute
|
||||
@branches = Kaminari.paginate_array(@branches).page(params[:page])
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Projects::IssuesController < Projects::ApplicationController
|
||||
include NotesHelper
|
||||
include ToggleSubscriptionAction
|
||||
include IssuableActions
|
||||
include ToggleAwardEmoji
|
||||
|
@ -70,6 +71,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
|
||||
|
@ -79,7 +82,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
|
||||
|
@ -89,7 +92,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
|
||||
|
@ -382,6 +383,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
@project_wiki,
|
||||
@ref
|
||||
)
|
||||
|
||||
preload_max_access_for_authors(@notes, @project)
|
||||
end
|
||||
|
||||
def define_widget_vars
|
||||
|
@ -401,7 +404,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
}
|
||||
|
||||
@use_legacy_diff_notes = !@merge_request.support_new_diff_notes?
|
||||
@grouped_diff_discussions = @merge_request.notes.grouped_diff_discussions
|
||||
@grouped_diff_discussions = @merge_request.notes.inc_author_project_award_emoji.grouped_diff_discussions
|
||||
|
||||
Banzai::NoteRenderer.render(
|
||||
@grouped_diff_discussions.values.flat_map(&:notes),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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)
|
||||
|
@ -85,14 +85,13 @@ module NotesHelper
|
|||
data: data, title: 'Add a reply'
|
||||
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])
|
||||
end
|
||||
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)
|
||||
|
|
|
@ -5,21 +5,9 @@ module SelectsHelper
|
|||
css_class << "skip_ldap " if opts[:skip_ldap]
|
||||
css_class << (opts[:class] || '')
|
||||
value = opts[:selected] || ''
|
||||
|
||||
first_user = opts[:first_user] && current_user ? current_user.username : false
|
||||
|
||||
html = {
|
||||
class: css_class,
|
||||
data: {
|
||||
placeholder: opts[:placeholder] || 'Search for a user',
|
||||
null_user: opts[:null_user] || false,
|
||||
any_user: opts[:any_user] || false,
|
||||
email_user: opts[:email_user] || false,
|
||||
first_user: first_user,
|
||||
current_user: opts[:current_user] || false,
|
||||
"push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
|
||||
author_id: opts[:author_id] || ''
|
||||
}
|
||||
data: users_select_data_attributes(opts)
|
||||
}
|
||||
|
||||
unless opts[:scope] == :all
|
||||
|
@ -68,4 +56,20 @@ module SelectsHelper
|
|||
|
||||
hidden_field_tag(id, value, class: css_class)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def users_select_data_attributes(opts)
|
||||
{
|
||||
placeholder: opts[:placeholder] || 'Search for a user',
|
||||
null_user: opts[:null_user] || false,
|
||||
any_user: opts[:any_user] || false,
|
||||
email_user: opts[:email_user] || false,
|
||||
first_user: opts[:first_user] && current_user ? current_user.username : false,
|
||||
current_user: opts[:current_user] || false,
|
||||
"push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
|
||||
author_id: opts[:author_id] || '',
|
||||
skip_users: opts[:skip_users] ? opts[:skip_users].map(&:id) : nil,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -389,6 +389,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 = []
|
||||
|
||||
|
|
|
@ -331,7 +331,7 @@ module Ci
|
|||
end
|
||||
|
||||
def valid_token?(token)
|
||||
project.valid_runners_token? token
|
||||
project.valid_runners_token?(token)
|
||||
end
|
||||
|
||||
def has_tags?
|
||||
|
|
|
@ -17,7 +17,7 @@ module Issuable
|
|||
belongs_to :assignee, class_name: "User"
|
||||
belongs_to :updated_by, class_name: "User"
|
||||
belongs_to :milestone
|
||||
has_many :notes, as: :noteable, dependent: :destroy do
|
||||
has_many :notes, as: :noteable, inverse_of: :noteable, dependent: :destroy do
|
||||
def authors_loaded?
|
||||
# We check first if we're loaded to not load unnecessarily.
|
||||
loaded? && to_a.all? { |note| note.association(:author).loaded? }
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
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
|
||||
|
||||
DueDateStruct = Struct.new(:title, :name).freeze
|
||||
NoDueDate = DueDateStruct.new('No Due Date', '0').freeze
|
||||
|
|
|
@ -25,6 +25,14 @@ class LegacyDiffNote < Note
|
|||
@discussion_id ||= Digest::SHA1.hexdigest(self.class.build_discussion_id(noteable_type, noteable_id || commit_id, line_code))
|
||||
end
|
||||
|
||||
def project_repository
|
||||
if RequestStore.active?
|
||||
RequestStore.fetch("project:#{project_id}:repository") { self.project.repository }
|
||||
else
|
||||
self.project.repository
|
||||
end
|
||||
end
|
||||
|
||||
def diff_file_hash
|
||||
line_code.split('_')[0] if line_code
|
||||
end
|
||||
|
@ -34,7 +42,7 @@ class LegacyDiffNote < Note
|
|||
end
|
||||
|
||||
def diff_file
|
||||
@diff_file ||= Gitlab::Diff::File.new(diff, repository: self.project.repository) if diff
|
||||
@diff_file ||= Gitlab::Diff::File.new(diff, repository: project_repository) if diff
|
||||
end
|
||||
|
||||
def diff_line
|
||||
|
|
|
@ -53,6 +53,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)
|
||||
|
|
|
@ -451,7 +451,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
|
||||
|
@ -584,7 +586,11 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def to_param
|
||||
path
|
||||
if persisted? && errors.include?(:path)
|
||||
path_was
|
||||
else
|
||||
path
|
||||
end
|
||||
end
|
||||
|
||||
def to_reference(_from_project = nil)
|
||||
|
@ -599,6 +605,13 @@ class Project < ActiveRecord::Base
|
|||
web_url.split('://')[1]
|
||||
end
|
||||
|
||||
def new_issue_address(author)
|
||||
if Gitlab::IncomingEmail.enabled? && author
|
||||
Gitlab::IncomingEmail.reply_address(
|
||||
"#{path_with_namespace}+#{author.authentication_token}")
|
||||
end
|
||||
end
|
||||
|
||||
def build_commit_note(commit)
|
||||
notes.new(commit_id: commit.id, noteable_type: 'Commit')
|
||||
end
|
||||
|
@ -1151,7 +1164,10 @@ class Project < ActiveRecord::Base
|
|||
|
||||
def schedule_delete!(user_id, params)
|
||||
# Queue this task for after the commit, so once we mark pending_delete it will run
|
||||
run_after_commit { ProjectDestroyWorker.perform_async(id, user_id, params) }
|
||||
run_after_commit do
|
||||
job_id = ProjectDestroyWorker.perform_async(id, user_id, params)
|
||||
Rails.logger.info("User #{user_id} scheduled destruction of project #{path_with_namespace} with job ID #{job_id}")
|
||||
end
|
||||
|
||||
update_attribute(:pending_delete, true)
|
||||
end
|
||||
|
|
|
@ -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)
|
||||
|
@ -240,6 +240,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
|
||||
|
|
|
@ -132,39 +132,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.
|
||||
# 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 }
|
||||
|
||||
member_access = project.members.access_for_user_ids(user_ids)
|
||||
merge_max!(access, member_access)
|
||||
|
||||
if group
|
||||
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?
|
||||
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
|
||||
|
||||
def max_member_access(user_id)
|
||||
access = []
|
||||
|
||||
access += project.members.where(user_id: user_id).has_access.pluck(:access_level)
|
||||
|
||||
if group
|
||||
access += group.members.where(user_id: user_id).has_access.pluck(:access_level)
|
||||
end
|
||||
|
||||
if project.invited_groups.any? && project.allowed_to_share_with_group?
|
||||
access << max_invited_level(user_id)
|
||||
end
|
||||
|
||||
access.compact.max
|
||||
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|
|
||||
invited_group = group_link.group
|
||||
access = invited_group.group_members.find_by(user_id: user_id).try(:access_field)
|
||||
# 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
|
||||
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)
|
||||
|
@ -215,4 +239,8 @@ class ProjectTeam
|
|||
def group
|
||||
project.group
|
||||
end
|
||||
|
||||
def merge_max!(first_hash, second_hash)
|
||||
first_hash.merge!(second_hash) { |_key, old, new| old > new ? old : new }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -211,6 +211,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
|
||||
|
||||
|
@ -612,11 +615,11 @@ class Repository
|
|||
case value
|
||||
when 'name'
|
||||
branches.sort_by(&:name)
|
||||
when 'recently_updated'
|
||||
when 'updated_desc'
|
||||
branches.sort do |a, b|
|
||||
commit(b.target).committed_date <=> commit(a.target).committed_date
|
||||
end
|
||||
when 'last_updated'
|
||||
when 'updated_asc'
|
||||
branches.sort do |a, b|
|
||||
commit(a.target).committed_date <=> commit(b.target).committed_date
|
||||
end
|
||||
|
@ -985,6 +988,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
|
||||
|
|
|
@ -3,7 +3,7 @@ module Projects
|
|||
def execute
|
||||
# check that user is allowed to set specified visibility_level
|
||||
new_visibility = params[:visibility_level]
|
||||
|
||||
|
||||
if new_visibility && new_visibility.to_i != project.visibility_level
|
||||
unless can?(current_user, :change_visibility_level, project) &&
|
||||
Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility)
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
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
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
- @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,28 +7,28 @@
|
|||
.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
|
||||
- if params[:sort].present?
|
||||
= params[:sort].humanize
|
||||
- else
|
||||
Name
|
||||
%b.caret
|
||||
%ul.dropdown-menu.dropdown-menu-align-right
|
||||
%li
|
||||
= link_to filter_branches_path(sort: nil) do
|
||||
= sort_title_name
|
||||
= link_to filter_branches_path(sort: 'recently_updated') do
|
||||
= sort_title_recently_updated
|
||||
= link_to filter_branches_path(sort: 'last_updated') do
|
||||
= sort_title_oldest_updated
|
||||
.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
|
||||
= projects_sort_options_hash[@sort]
|
||||
%b.caret
|
||||
%ul.dropdown-menu.dropdown-menu-align-right
|
||||
%li
|
||||
= link_to filter_branches_path(sort: sort_value_name) do
|
||||
= sort_title_name
|
||||
= link_to filter_branches_path(sort: sort_value_recently_updated) do
|
||||
= sort_title_recently_updated
|
||||
= link_to filter_branches_path(sort: sort_value_oldest_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
|
||||
|
||||
- if @branches.any?
|
||||
%ul.content-list.all-branches
|
||||
- @branches.each do |branch|
|
||||
|
|
|
@ -88,8 +88,9 @@
|
|||
%p
|
||||
%span.build-light-text Variables:
|
||||
|
||||
%code
|
||||
- @build.trigger_request.variables.each do |key, value|
|
||||
|
||||
- @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
|
||||
|
@ -190,6 +191,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
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
.issues-footer.text-center
|
||||
%button.issue-email-modal-btn{ type: "button", data: { toggle: "modal", target: "#issue-email-modal" } }
|
||||
Email a new issue to this project
|
||||
|
||||
#issue-email-modal.modal.fade{ tabindex: "-1", role: "dialog" }
|
||||
.modal-dialog{ role: "document" }
|
||||
.modal-content
|
||||
.modal-header
|
||||
%button.close{ type: "button", data: { dismiss: "modal" }, aria: { label: "close" } }
|
||||
%span{ aria: { hidden: "true" } }= icon("times")
|
||||
%h4.modal-title
|
||||
Create new issue by email
|
||||
.modal-body
|
||||
%p
|
||||
Write an email to the below email address. (This is a private email address, so keep it secret.)
|
||||
.email-modal-input-group.input-group
|
||||
= text_field_tag :issue_email, email, class: "monospace js-select-on-focus form-control", readonly: true
|
||||
.input-group-btn
|
||||
= clipboard_button(clipboard_target: '#issue_email')
|
||||
%p
|
||||
Send an email to this address to create an issue.
|
||||
%p
|
||||
Use the subject line as the title of your issue.
|
||||
%p
|
||||
Use the message as the body of your issue (feel free to include some nice
|
||||
= succeed ")." do
|
||||
= link_to "Markdown", help_page_path('markdown', 'markdown')
|
|
@ -1,5 +1,6 @@
|
|||
- @no_container = true
|
||||
- page_title "Issues"
|
||||
- new_issue_email = @project.new_issue_address(current_user)
|
||||
= render "projects/issues/head"
|
||||
|
||||
= content_for :meta_tags do
|
||||
|
@ -23,7 +24,9 @@
|
|||
= render 'shared/issuable/filter', type: :issues
|
||||
|
||||
.issues-holder
|
||||
= render "issues"
|
||||
= render 'issues'
|
||||
- if new_issue_email
|
||||
= render 'issue_by_email', email: new_issue_email
|
||||
- else
|
||||
.blank-state.blank-state-welcome
|
||||
%h2.blank-state-title.blank-state-welcome-title
|
||||
|
@ -40,3 +43,5 @@
|
|||
- if can? current_user, :create_issue, @project
|
||||
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: "btn btn-new", title: "New Issue", id: "new_issue_link" do
|
||||
New Issue
|
||||
- if new_issue_email
|
||||
= render 'issue_by_email', email: new_issue_email
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<circle id="a" cx="7" cy="7" r="7"/>
|
||||
<mask id="b" width="14" height="14" x="0" y="0" fill="white">
|
||||
<use xlink:href="#a"/>
|
||||
</mask>
|
||||
</defs>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<use stroke="#5C5C5C" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
|
||||
<rect width="10" height="1" x="2" y="6.5" fill="#5C5C5C" transform="rotate(45 7 7)" rx=".3"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
|
||||
<g fill="#5C5C5C" fill-rule="evenodd">
|
||||
<path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
|
||||
<rect width="8" height="2" x="3" y="6" transform="rotate(45 7 7)" rx=".5"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 520 B After Width: | Height: | Size: 536 B |
|
@ -1,12 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<circle id="a" cx="7" cy="7" r="7"/>
|
||||
<mask id="b" width="14" height="14" x="0" y="0" fill="white">
|
||||
<use xlink:href="#a"/>
|
||||
</mask>
|
||||
</defs>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<use stroke="#D22852" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
|
||||
<path fill="#D22852" d="M7.5,6.5 L7.5,4.30578971 C7.5,4.12531853 7.36809219,4 7.20537567,4 L6.79462433,4 C6.63904572,4 6.5,4.13690672 6.5,4.30578971 L6.5,6.5 L4.30578971,6.5 C4.12531853,6.5 4,6.63190781 4,6.79462433 L4,7.20537567 C4,7.36095428 4.13690672,7.5 4.30578971,7.5 L6.5,7.5 L6.5,9.69421029 C6.5,9.87468147 6.63190781,10 6.79462433,10 L7.20537567,10 C7.36095428,10 7.5,9.86309328 7.5,9.69421029 L7.5,7.5 L9.69421029,7.5 C9.87468147,7.5 10,7.36809219 10,7.20537567 L10,6.79462433 C10,6.63904572 9.86309328,6.5 9.69421029,6.5 L7.5,6.5 Z" transform="rotate(45 7 7)"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
|
||||
<g fill="#D22852" fill-rule="evenodd">
|
||||
<path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
|
||||
<path d="M7.72916667,6.27083333 L7.72916667,4.28939247 C7.72916667,4.12531853 7.59703895,4 7.43405116,4 L6.56594884,4 C6.40541585,4 6.27083333,4.12956542 6.27083333,4.28939247 L6.27083333,6.27083333 L4.28939247,6.27083333 C4.12531853,6.27083333 4,6.40296105 4,6.56594884 L4,7.43405116 C4,7.59458415 4.12956542,7.72916667 4.28939247,7.72916667 L6.27083333,7.72916667 L6.27083333,9.71060753 C6.27083333,9.87468147 6.40296105,10 6.56594884,10 L7.43405116,10 C7.59458415,10 7.72916667,9.87043458 7.72916667,9.71060753 L7.72916667,7.72916667 L9.71060753,7.72916667 C9.87468147,7.72916667 10,7.59703895 10,7.43405116 L10,6.56594884 C10,6.40541585 9.87043458,6.27083333 9.71060753,6.27083333 L7.72916667,6.27083333 Z" transform="rotate(-45 7 7)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 999 B After Width: | Height: | Size: 1.2 KiB |
|
@ -1,13 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<circle id="a" cx="7" cy="7" r="7"/>
|
||||
<mask id="b" width="14" height="14" x="0" y="0" fill="white">
|
||||
<use xlink:href="#a"/>
|
||||
</mask>
|
||||
</defs>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<use stroke="#E75E40" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
|
||||
<rect width="1" height="4" x="5" y="5" fill="#E75E40" rx=".3"/>
|
||||
<rect width="1" height="4" x="8" y="5" fill="#E75E40" rx=".3"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
|
||||
<g fill="#E75E40" fill-rule="evenodd">
|
||||
<path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
|
||||
<path d="M4.69999981,5.30065012 C4.69999981,5.13460564 4.83842754,5 5.00354719,5 L5.89645243,5 C6.06409702,5 6.19999981,5.13308716 6.19999981,5.30065012 L6.19999981,8.69934988 C6.19999981,8.86539436 6.06157207,9 5.89645243,9 L5.00354719,9 C4.8359026,9 4.69999981,8.86691284 4.69999981,8.69934988 L4.69999981,5.30065012 Z M7.69999981,5.30065012 C7.69999981,5.13460564 7.83842754,5 8.00354719,5 L8.89645243,5 C9.06409702,5 9.19999981,5.13308716 9.19999981,5.30065012 L9.19999981,8.69934988 C9.19999981,8.86539436 9.06157207,9 8.89645243,9 L8.00354719,9 C7.8359026,9 7.69999981,8.86691284 7.69999981,8.69934988 L7.69999981,5.30065012 Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 558 B After Width: | Height: | Size: 1.1 KiB |
|
@ -1,12 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<circle id="a" cx="7" cy="7" r="7"/>
|
||||
<mask id="b" width="14" height="14" x="0" y="0" fill="white">
|
||||
<use xlink:href="#a"/>
|
||||
</mask>
|
||||
</defs>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<use stroke="#2D9FD8" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
|
||||
<path fill="#2D9FD8" d="M7,3.00800862 C9.09023405,3.13960661 10.7448145,4.87657932 10.7448145,7 C10.7448145,9.209139 8.95395346,11 6.74481446,11 C5.4560962,11 4.30972054,10.3905589 3.57817301,9.44416214 L7,7 L7,3.00800862 Z"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
|
||||
<g fill="#2D9FD8" fill-rule="evenodd">
|
||||
<path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
|
||||
<path d="M7,3 C9.209139,3 11,4.790861 11,7 C11,9.209139 9.209139,11 7,11 C5.65802855,11 4.47040669,10.3391508 3.74481446,9.32513253 L7,7 L7,3 L7,3 Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 653 B After Width: | Height: | Size: 612 B |
|
@ -1,15 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<circle id="a" cx="7" cy="7" r="7"/>
|
||||
<mask id="b" width="14" height="14" x="0" y="0" fill="white">
|
||||
<use xlink:href="#a"/>
|
||||
</mask>
|
||||
</defs>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<use stroke="#31AF64" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
|
||||
<g fill="#31AF64" transform="rotate(45 -.13 10.953)">
|
||||
<rect width="1" height="5" x="2" rx=".3"/>
|
||||
<rect width="3" height="1" y="4" rx=".3"/>
|
||||
</g>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
|
||||
<g fill="#31AF64" fill-rule="evenodd">
|
||||
<path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
|
||||
<path d="M7.29166667,7.875 L5.54840803,7.875 C5.38293028,7.875 5.25,8.00712771 5.25,8.17011551 L5.25,9.03821782 C5.25,9.19875081 5.38360183,9.33333333 5.54840803,9.33333333 L8.24853534,9.33333333 C8.52035522,9.33333333 8.75,9.11228506 8.75,8.83960819 L8.75,8.46475969 L8.75,4.07392947 C8.75,3.92144267 8.61787229,3.79166667 8.45488449,3.79166667 L7.58678218,3.79166667 C7.42624919,3.79166667 7.29166667,3.91804003 7.29166667,4.07392947 L7.29166667,7.875 Z" transform="rotate(45 7 6.563)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 587 B After Width: | Height: | Size: 950 B |
|
@ -1,15 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<circle id="a" cx="7" cy="7" r="7"/>
|
||||
<mask id="b" width="14" height="14" x="0" y="0" fill="white">
|
||||
<use xlink:href="#a"/>
|
||||
</mask>
|
||||
</defs>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<g fill="#FF8A24" transform="translate(6 3)">
|
||||
<rect width="2" height="5" rx=".5"/>
|
||||
<rect width="2" height="2" y="6" rx=".5"/>
|
||||
</g>
|
||||
<use stroke="#FF8A24" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
|
||||
<g fill="#FF8A24" fill-rule="evenodd">
|
||||
<path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
|
||||
<path d="M6,3.49769878 C6,3.22282734 6.21403503,3 6.50468445,3 L7.49531555,3 C7.77404508,3 8,3.21484375 8,3.49769878 L8,7.50230122 C8,7.77717266 7.78596497,8 7.49531555,8 L6.50468445,8 C6.22595492,8 6,7.78515625 6,7.50230122 L6,3.49769878 Z M6,9.50468445 C6,9.22595492 6.21403503,9 6.50468445,9 L7.49531555,9 C7.77404508,9 8,9.21403503 8,9.50468445 L8,10.4953156 C8,10.7740451 7.78596497,11 7.49531555,11 L6.50468445,11 C6.22595492,11 6,10.785965 6,10.4953156 L6,9.50468445 Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 573 B After Width: | Height: | Size: 939 B |
|
@ -21,31 +21,35 @@ class EmailReceiverWorker
|
|||
return unless raw.present?
|
||||
|
||||
can_retry = false
|
||||
reason = nil
|
||||
reason =
|
||||
case e
|
||||
when Gitlab::Email::UnknownIncomingEmail
|
||||
"We couldn't figure out what the email is for. Please create your issue or comment through the web interface."
|
||||
when Gitlab::Email::SentNotificationNotFoundError
|
||||
"We couldn't figure out what the email is in reply to. Please create your comment through the web interface."
|
||||
when Gitlab::Email::ProjectNotFound
|
||||
"We couldn't find the project. Please check if there's any typo."
|
||||
when Gitlab::Email::EmptyEmailError
|
||||
can_retry = true
|
||||
"It appears that the email is blank. Make sure your reply is at the top of the email, we can't process inline replies."
|
||||
when Gitlab::Email::AutoGeneratedEmailError
|
||||
"The email was marked as 'auto generated', which we can't accept. Please create your comment through the web interface."
|
||||
when Gitlab::Email::UserNotFoundError
|
||||
"We couldn't figure out what user corresponds to the email. Please create your comment through the web interface."
|
||||
when Gitlab::Email::UserBlockedError
|
||||
"Your account has been blocked. If you believe this is in error, contact a staff member."
|
||||
when Gitlab::Email::UserNotAuthorizedError
|
||||
"You are not allowed to perform this action. If you believe this is in error, contact a staff member."
|
||||
when Gitlab::Email::NoteableNotFoundError
|
||||
"The thread you are replying to no longer exists, perhaps it was deleted? If you believe this is in error, contact a staff member."
|
||||
when Gitlab::Email::InvalidNoteError,
|
||||
Gitlab::Email::InvalidIssueError
|
||||
can_retry = true
|
||||
e.message
|
||||
end
|
||||
|
||||
case e
|
||||
when Gitlab::Email::Receiver::SentNotificationNotFoundError
|
||||
reason = "We couldn't figure out what the email is in reply to. Please create your comment through the web interface."
|
||||
when Gitlab::Email::Receiver::EmptyEmailError
|
||||
can_retry = true
|
||||
reason = "It appears that the email is blank. Make sure your reply is at the top of the email, we can't process inline replies."
|
||||
when Gitlab::Email::Receiver::AutoGeneratedEmailError
|
||||
reason = "The email was marked as 'auto generated', which we can't accept. Please create your comment through the web interface."
|
||||
when Gitlab::Email::Receiver::UserNotFoundError
|
||||
reason = "We couldn't figure out what user corresponds to the email. Please create your comment through the web interface."
|
||||
when Gitlab::Email::Receiver::UserBlockedError
|
||||
reason = "Your account has been blocked. If you believe this is in error, contact a staff member."
|
||||
when Gitlab::Email::Receiver::UserNotAuthorizedError
|
||||
reason = "You are not allowed to respond to the thread you are replying to. If you believe this is in error, contact a staff member."
|
||||
when Gitlab::Email::Receiver::NoteableNotFoundError
|
||||
reason = "The thread you are replying to no longer exists, perhaps it was deleted? If you believe this is in error, contact a staff member."
|
||||
when Gitlab::Email::Receiver::InvalidNoteError
|
||||
can_retry = true
|
||||
reason = e.message
|
||||
else
|
||||
return
|
||||
if reason
|
||||
EmailRejectionMailer.rejection(reason, raw, can_retry).deliver_later
|
||||
end
|
||||
|
||||
EmailRejectionMailer.rejection(reason, raw, can_retry).deliver_later
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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.')
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
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
|
||||
|
|
|
@ -290,6 +290,9 @@ Settings.cron_jobs['repository_archive_cache_worker']['job_class'] = 'Repository
|
|||
Settings.cron_jobs['gitlab_remove_project_export_worker'] ||= Settingslogic.new({})
|
||||
Settings.cron_jobs['gitlab_remove_project_export_worker']['cron'] ||= '0 * * * *'
|
||||
Settings.cron_jobs['gitlab_remove_project_export_worker']['job_class'] = 'GitlabRemoveProjectExportWorker'
|
||||
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'
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Rails.application.configure do |config|
|
||||
config.middleware.use(Gitlab::RequestProfiler::Middleware)
|
||||
end
|
|
@ -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
|
||||
|
||||
|
@ -144,13 +143,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
|
||||
|
@ -243,7 +242,6 @@ Rails.application.routes.draw do
|
|||
get :projects
|
||||
get :keys
|
||||
get :groups
|
||||
put :team_update
|
||||
put :block
|
||||
put :unblock
|
||||
put :unlock
|
||||
|
@ -281,6 +279,7 @@ Rails.application.routes.draw do
|
|||
resource :health_check, controller: 'health_check', only: [:show]
|
||||
resource :background_jobs, controller: 'background_jobs', only: [:show]
|
||||
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
|
||||
|
@ -300,7 +299,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
|
||||
|
@ -309,7 +308,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
|
||||
|
@ -346,7 +345,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
|
||||
|
@ -358,7 +357,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]
|
||||
|
||||
|
@ -660,7 +659,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
|
||||
|
@ -789,7 +788,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
|
||||
|
@ -814,7 +813,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
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ Sidekiq::Testing.inline! do
|
|||
'https://github.com/airbnb/javascript.git',
|
||||
'https://github.com/tessalt/echo-chamber-js.git',
|
||||
'https://github.com/atom/atom.git',
|
||||
'https://github.com/ipselon/react-ui-builder.git',
|
||||
'https://github.com/mattermost/platform.git',
|
||||
'https://github.com/purifycss/purifycss.git',
|
||||
'https://github.com/facebook/nuclide.git',
|
||||
|
|
|
@ -81,6 +81,11 @@ Example response:
|
|||
"parent_ids": [
|
||||
"ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"
|
||||
],
|
||||
"stats": {
|
||||
"additions": 15,
|
||||
"deletions": 10,
|
||||
"total": 25
|
||||
},
|
||||
"status": "running"
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
# 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
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
# 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
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
if ENV['SIMPLECOV']
|
||||
require 'simplecov'
|
||||
end
|
||||
require './spec/simplecov_env'
|
||||
SimpleCovEnv.start!
|
||||
|
||||
ENV['RAILS_ENV'] = 'test'
|
||||
require './config/environment'
|
||||
|
|
|
@ -149,8 +149,13 @@ module API
|
|||
expose :safe_message, as: :message
|
||||
end
|
||||
|
||||
class RepoCommitStats < Grape::Entity
|
||||
expose :additions, :deletions, :total
|
||||
end
|
||||
|
||||
class RepoCommitDetail < RepoCommit
|
||||
expose :parent_ids, :committed_date, :authored_date
|
||||
expose :stats, using: Entities::RepoCommitStats
|
||||
expose :status
|
||||
end
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -60,16 +60,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
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
require 'gitlab/email/handler/create_note_handler'
|
||||
require 'gitlab/email/handler/create_issue_handler'
|
||||
|
||||
module Gitlab
|
||||
module Email
|
||||
module Handler
|
||||
HANDLERS = [CreateNoteHandler, CreateIssueHandler]
|
||||
|
||||
def self.for(mail, mail_key)
|
||||
HANDLERS.find do |klass|
|
||||
handler = klass.new(mail, mail_key)
|
||||
break handler if handler.can_handle?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,60 @@
|
|||
module Gitlab
|
||||
module Email
|
||||
module Handler
|
||||
class BaseHandler
|
||||
attr_reader :mail, :mail_key
|
||||
|
||||
def initialize(mail, mail_key)
|
||||
@mail = mail
|
||||
@mail_key = mail_key
|
||||
end
|
||||
|
||||
def message
|
||||
@message ||= process_message
|
||||
end
|
||||
|
||||
def author
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def project
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_permission!(permission)
|
||||
raise UserNotFoundError unless author
|
||||
raise UserBlockedError if author.blocked?
|
||||
raise ProjectNotFound unless author.can?(:read_project, project)
|
||||
raise UserNotAuthorizedError unless author.can?(permission, project)
|
||||
end
|
||||
|
||||
def process_message
|
||||
message = ReplyParser.new(mail).execute.strip
|
||||
add_attachments(message)
|
||||
end
|
||||
|
||||
def add_attachments(reply)
|
||||
attachments = Email::AttachmentUploader.new(mail).execute(project)
|
||||
|
||||
reply + attachments.map do |link|
|
||||
"\n\n#{link[:markdown]}"
|
||||
end.join
|
||||
end
|
||||
|
||||
def verify_record!(record:, invalid_exception:, record_name:)
|
||||
return if record.persisted?
|
||||
|
||||
error_title = "The #{record_name} could not be created for the following reasons:"
|
||||
|
||||
msg = error_title + record.errors.full_messages.map do |error|
|
||||
"\n\n- #{error}"
|
||||
end.join
|
||||
|
||||
raise invalid_exception, msg
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
require 'gitlab/email/handler/base_handler'
|
||||
|
||||
module Gitlab
|
||||
module Email
|
||||
module Handler
|
||||
class CreateIssueHandler < BaseHandler
|
||||
attr_reader :project_path, :authentication_token
|
||||
|
||||
def initialize(mail, mail_key)
|
||||
super(mail, mail_key)
|
||||
@project_path, @authentication_token =
|
||||
mail_key && mail_key.split('+', 2)
|
||||
end
|
||||
|
||||
def can_handle?
|
||||
!authentication_token.nil?
|
||||
end
|
||||
|
||||
def execute
|
||||
raise ProjectNotFound unless project
|
||||
|
||||
validate_permission!(:create_issue)
|
||||
|
||||
verify_record!(
|
||||
record: create_issue,
|
||||
invalid_exception: InvalidIssueError,
|
||||
record_name: 'issue')
|
||||
end
|
||||
|
||||
def author
|
||||
@author ||= User.find_by(authentication_token: authentication_token)
|
||||
end
|
||||
|
||||
def project
|
||||
@project ||= Project.find_with_namespace(project_path)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_issue
|
||||
Issues::CreateService.new(
|
||||
project,
|
||||
author,
|
||||
title: mail.subject,
|
||||
description: message
|
||||
).execute
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
require 'gitlab/email/handler/base_handler'
|
||||
|
||||
module Gitlab
|
||||
module Email
|
||||
module Handler
|
||||
class CreateNoteHandler < BaseHandler
|
||||
def can_handle?
|
||||
mail_key =~ /\A\w+\z/
|
||||
end
|
||||
|
||||
def execute
|
||||
raise SentNotificationNotFoundError unless sent_notification
|
||||
raise AutoGeneratedEmailError if mail.header.to_s =~ /auto-(generated|replied)/
|
||||
|
||||
validate_permission!(:create_note)
|
||||
|
||||
raise NoteableNotFoundError unless sent_notification.noteable
|
||||
raise EmptyEmailError if message.blank?
|
||||
|
||||
verify_record!(
|
||||
record: create_note,
|
||||
invalid_exception: InvalidNoteError,
|
||||
record_name: 'comment')
|
||||
end
|
||||
|
||||
def author
|
||||
sent_notification.recipient
|
||||
end
|
||||
|
||||
def project
|
||||
sent_notification.project
|
||||
end
|
||||
|
||||
def sent_notification
|
||||
@sent_notification ||= SentNotification.for(mail_key)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_note
|
||||
Notes::CreateService.new(
|
||||
project,
|
||||
author,
|
||||
note: message,
|
||||
noteable_type: sent_notification.noteable_type,
|
||||
noteable_id: sent_notification.noteable_id,
|
||||
commit_id: sent_notification.commit_id,
|
||||
line_code: sent_notification.line_code
|
||||
).execute
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,18 +1,24 @@
|
|||
|
||||
require 'gitlab/email/handler'
|
||||
|
||||
# Inspired in great part by Discourse's Email::Receiver
|
||||
module Gitlab
|
||||
module Email
|
||||
class Receiver
|
||||
class ProcessingError < StandardError; end
|
||||
class EmailUnparsableError < ProcessingError; end
|
||||
class SentNotificationNotFoundError < ProcessingError; end
|
||||
class EmptyEmailError < ProcessingError; end
|
||||
class AutoGeneratedEmailError < ProcessingError; end
|
||||
class UserNotFoundError < ProcessingError; end
|
||||
class UserBlockedError < ProcessingError; end
|
||||
class UserNotAuthorizedError < ProcessingError; end
|
||||
class NoteableNotFoundError < ProcessingError; end
|
||||
class InvalidNoteError < ProcessingError; end
|
||||
class ProcessingError < StandardError; end
|
||||
class EmailUnparsableError < ProcessingError; end
|
||||
class SentNotificationNotFoundError < ProcessingError; end
|
||||
class ProjectNotFound < ProcessingError; end
|
||||
class EmptyEmailError < ProcessingError; end
|
||||
class AutoGeneratedEmailError < ProcessingError; end
|
||||
class UserNotFoundError < ProcessingError; end
|
||||
class UserBlockedError < ProcessingError; end
|
||||
class UserNotAuthorizedError < ProcessingError; end
|
||||
class NoteableNotFoundError < ProcessingError; end
|
||||
class InvalidNoteError < ProcessingError; end
|
||||
class InvalidIssueError < ProcessingError; end
|
||||
class UnknownIncomingEmail < ProcessingError; end
|
||||
|
||||
class Receiver
|
||||
def initialize(raw)
|
||||
@raw = raw
|
||||
end
|
||||
|
@ -20,91 +26,38 @@ module Gitlab
|
|||
def execute
|
||||
raise EmptyEmailError if @raw.blank?
|
||||
|
||||
raise SentNotificationNotFoundError unless sent_notification
|
||||
mail = build_mail
|
||||
mail_key = extract_mail_key(mail)
|
||||
handler = Handler.for(mail, mail_key)
|
||||
|
||||
raise AutoGeneratedEmailError if message.header.to_s =~ /auto-(generated|replied)/
|
||||
raise UnknownIncomingEmail unless handler
|
||||
|
||||
author = sent_notification.recipient
|
||||
|
||||
raise UserNotFoundError unless author
|
||||
|
||||
raise UserBlockedError if author.blocked?
|
||||
|
||||
project = sent_notification.project
|
||||
|
||||
raise UserNotAuthorizedError unless project && author.can?(:create_note, project)
|
||||
|
||||
raise NoteableNotFoundError unless sent_notification.noteable
|
||||
|
||||
reply = ReplyParser.new(message).execute.strip
|
||||
|
||||
raise EmptyEmailError if reply.blank?
|
||||
|
||||
reply = add_attachments(reply)
|
||||
|
||||
note = create_note(reply)
|
||||
|
||||
unless note.persisted?
|
||||
msg = "The comment could not be created for the following reasons:"
|
||||
note.errors.full_messages.each do |error|
|
||||
msg << "\n\n- #{error}"
|
||||
end
|
||||
|
||||
raise InvalidNoteError, msg
|
||||
end
|
||||
handler.execute
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message
|
||||
@message ||= Mail::Message.new(@raw)
|
||||
rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError => e
|
||||
def build_mail
|
||||
Mail::Message.new(@raw)
|
||||
rescue Encoding::UndefinedConversionError,
|
||||
Encoding::InvalidByteSequenceError => e
|
||||
raise EmailUnparsableError, e
|
||||
end
|
||||
|
||||
def reply_key
|
||||
key_from_to_header || key_from_additional_headers
|
||||
def extract_mail_key(mail)
|
||||
key_from_to_header(mail) || key_from_additional_headers(mail)
|
||||
end
|
||||
|
||||
def key_from_to_header
|
||||
key = nil
|
||||
message.to.each do |address|
|
||||
def key_from_to_header(mail)
|
||||
mail.to.find do |address|
|
||||
key = Gitlab::IncomingEmail.key_from_address(address)
|
||||
break if key
|
||||
break key if key
|
||||
end
|
||||
|
||||
key
|
||||
end
|
||||
|
||||
def key_from_additional_headers
|
||||
reply_key = nil
|
||||
|
||||
Array(message.references).each do |message_id|
|
||||
reply_key = Gitlab::IncomingEmail.key_from_fallback_reply_message_id(message_id)
|
||||
break if reply_key
|
||||
def key_from_additional_headers(mail)
|
||||
Array(mail.references).find do |mail_id|
|
||||
key = Gitlab::IncomingEmail.key_from_fallback_message_id(mail_id)
|
||||
break key if key
|
||||
end
|
||||
|
||||
reply_key
|
||||
end
|
||||
|
||||
def sent_notification
|
||||
return nil unless reply_key
|
||||
|
||||
SentNotification.for(reply_key)
|
||||
end
|
||||
|
||||
def add_attachments(reply)
|
||||
attachments = Email::AttachmentUploader.new(message).execute(sent_notification.project)
|
||||
|
||||
attachments.each do |link|
|
||||
reply << "\n\n#{link[:markdown]}"
|
||||
end
|
||||
|
||||
reply
|
||||
end
|
||||
|
||||
def create_note(reply)
|
||||
sent_notification.create_note(reply)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module Gitlab
|
||||
module IncomingEmail
|
||||
class << self
|
||||
FALLBACK_REPLY_MESSAGE_ID_REGEX = /\Areply\-(.+)@#{Gitlab.config.gitlab.host}\Z/.freeze
|
||||
FALLBACK_MESSAGE_ID_REGEX = /\Areply\-(.+)@#{Gitlab.config.gitlab.host}\Z/.freeze
|
||||
|
||||
def enabled?
|
||||
config.enabled && config.address
|
||||
|
@ -21,8 +21,8 @@ module Gitlab
|
|||
match[1]
|
||||
end
|
||||
|
||||
def key_from_fallback_reply_message_id(message_id)
|
||||
match = message_id.match(FALLBACK_REPLY_MESSAGE_ID_REGEX)
|
||||
def key_from_fallback_message_id(mail_id)
|
||||
match = mail_id.match(FALLBACK_MESSAGE_ID_REGEX)
|
||||
return unless match
|
||||
|
||||
match[1]
|
||||
|
|
|
@ -124,6 +124,11 @@ module Gitlab
|
|||
trans.action = action if trans
|
||||
end
|
||||
|
||||
# Returns the prefix to use for the name of a series.
|
||||
def self.series_prefix
|
||||
@series_prefix ||= Sidekiq.server? ? 'sidekiq_' : 'rails_'
|
||||
end
|
||||
|
||||
# When enabled this should be set before being used as the usual pattern
|
||||
# "@foo ||= bar" is _not_ thread-safe.
|
||||
if enabled?
|
||||
|
|
|
@ -9,14 +9,17 @@ module Gitlab
|
|||
#
|
||||
# Gitlab::Metrics::Instrumentation.instrument_method(User, :by_login)
|
||||
module Instrumentation
|
||||
SERIES = 'method_calls'
|
||||
|
||||
PROXY_IVAR = :@__gitlab_instrumentation_proxy
|
||||
|
||||
def self.configure
|
||||
yield self
|
||||
end
|
||||
|
||||
# Returns the name of the series to use for storing method calls.
|
||||
def self.series
|
||||
@series ||= "#{Metrics.series_prefix}method_calls"
|
||||
end
|
||||
|
||||
# Instruments a class method.
|
||||
#
|
||||
# mod - The module to instrument as a Module/Class.
|
||||
|
@ -141,15 +144,15 @@ module Gitlab
|
|||
# generated method _only_ accepts regular arguments if the underlying
|
||||
# method also accepts them.
|
||||
if method.arity == 0
|
||||
args_signature = '&block'
|
||||
args_signature = ''
|
||||
else
|
||||
args_signature = '*args, &block'
|
||||
args_signature = '*args'
|
||||
end
|
||||
|
||||
proxy_module.class_eval <<-EOF, __FILE__, __LINE__ + 1
|
||||
def #{name}(#{args_signature})
|
||||
if trans = Gitlab::Metrics::Instrumentation.transaction
|
||||
trans.measure_method(#{label.inspect}) { super }
|
||||
trans.method_call_for(#{label.to_sym.inspect}).measure { super }
|
||||
else
|
||||
super
|
||||
end
|
||||
|
|
|
@ -11,8 +11,8 @@ module Gitlab
|
|||
def initialize(name, series)
|
||||
@name = name
|
||||
@series = series
|
||||
@real_time = 0.0
|
||||
@cpu_time = 0.0
|
||||
@real_time = 0
|
||||
@cpu_time = 0
|
||||
@call_count = 0
|
||||
end
|
||||
|
||||
|
|
|
@ -35,12 +35,12 @@ module Gitlab
|
|||
if Process.const_defined?(:CLOCK_THREAD_CPUTIME_ID)
|
||||
def self.cpu_time
|
||||
Process.
|
||||
clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :millisecond).to_f
|
||||
clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :millisecond)
|
||||
end
|
||||
else
|
||||
def self.cpu_time
|
||||
Process.
|
||||
clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID, :millisecond).to_f
|
||||
clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID, :millisecond)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -48,14 +48,14 @@ module Gitlab
|
|||
#
|
||||
# Returns the time as a Float.
|
||||
def self.real_time(precision = :millisecond)
|
||||
Process.clock_gettime(Process::CLOCK_REALTIME, precision).to_f
|
||||
Process.clock_gettime(Process::CLOCK_REALTIME, precision)
|
||||
end
|
||||
|
||||
# Returns the current monotonic clock time in a given precision.
|
||||
#
|
||||
# Returns the time as a Float.
|
||||
def self.monotonic_time(precision = :millisecond)
|
||||
Process.clock_gettime(Process::CLOCK_MONOTONIC, precision).to_f
|
||||
Process.clock_gettime(Process::CLOCK_MONOTONIC, precision)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -52,23 +52,16 @@ module Gitlab
|
|||
end
|
||||
|
||||
def add_metric(series, values, tags = {})
|
||||
@metrics << Metric.new("#{series_prefix}#{series}", values, tags)
|
||||
@metrics << Metric.new("#{Metrics.series_prefix}#{series}", values, tags)
|
||||
end
|
||||
|
||||
# Measures the time it takes to execute a method.
|
||||
#
|
||||
# Multiple calls to the same method add up to the total runtime of the
|
||||
# method.
|
||||
#
|
||||
# name - The full name of the method to measure (e.g. `User#sign_in`).
|
||||
def measure_method(name, &block)
|
||||
unless @methods[name]
|
||||
series = "#{series_prefix}#{Instrumentation::SERIES}"
|
||||
|
||||
@methods[name] = MethodCall.new(name, series)
|
||||
# Returns a MethodCall object for the given name.
|
||||
def method_call_for(name)
|
||||
unless method = @methods[name]
|
||||
@methods[name] = method = MethodCall.new(name, Instrumentation.series)
|
||||
end
|
||||
|
||||
@methods[name].measure(&block)
|
||||
method
|
||||
end
|
||||
|
||||
def increment(name, value)
|
||||
|
@ -115,14 +108,6 @@ module Gitlab
|
|||
|
||||
Metrics.submit_metrics(submit_hashes)
|
||||
end
|
||||
|
||||
def sidekiq?
|
||||
Sidekiq.server?
|
||||
end
|
||||
|
||||
def series_prefix
|
||||
sidekiq? ? 'sidekiq_' : 'rails_'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
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
|
|
@ -0,0 +1,47 @@
|
|||
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
|
|
@ -0,0 +1,43 @@
|
|||
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
|
|
@ -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
|
||||
|
|
|
@ -1,55 +1,65 @@
|
|||
<!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;
|
||||
}
|
||||
body {
|
||||
color: #666;
|
||||
text-align: center;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
margin: auto;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 56px;
|
||||
line-height: 100px;
|
||||
font-weight: normal;
|
||||
color: #456;
|
||||
}
|
||||
h1 {
|
||||
font-size: 56px;
|
||||
line-height: 100px;
|
||||
font-weight: normal;
|
||||
color: #456;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #456;
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 28px;
|
||||
}
|
||||
h3 {
|
||||
color: #456;
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 18px 0;
|
||||
border: 0;
|
||||
border-top: 1px solid #EEE;
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
hr {
|
||||
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>
|
||||
<h3>The page you're looking for could not be found.</h3>
|
||||
<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 class="container">
|
||||
<h3>The page you're looking for could not be found.</h3>
|
||||
<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>
|
||||
|
|
|
@ -1,55 +1,65 @@
|
|||
<!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;
|
||||
}
|
||||
text-align: center;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
margin: auto;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 56px;
|
||||
line-height: 100px;
|
||||
font-weight: normal;
|
||||
color: #456;
|
||||
}
|
||||
h1 {
|
||||
font-size: 56px;
|
||||
line-height: 100px;
|
||||
font-weight: normal;
|
||||
color: #456;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #456;
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 28px;
|
||||
}
|
||||
h3 {
|
||||
color: #456;
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 18px 0;
|
||||
border: 0;
|
||||
border-top: 1px solid #EEE;
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
</style>
|
||||
hr {
|
||||
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>
|
||||
<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 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>
|
||||
|
|
|
@ -1,54 +1,65 @@
|
|||
<!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;
|
||||
}
|
||||
body {
|
||||
color: #666;
|
||||
text-align: center;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
margin: auto;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 56px;
|
||||
line-height: 100px;
|
||||
font-weight: normal;
|
||||
color: #456;
|
||||
}
|
||||
h1 {
|
||||
font-size: 56px;
|
||||
line-height: 100px;
|
||||
font-weight: normal;
|
||||
color: #456;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #456;
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 28px;
|
||||
}
|
||||
h3 {
|
||||
color: #456;
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 18px 0;
|
||||
hr {
|
||||
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>
|
||||
<h3>Whoops, something went wrong on our end.</h3>
|
||||
<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 class="container">
|
||||
<h3>Whoops, something went wrong on our end.</h3>
|
||||
<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>
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
<!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>
|
||||
<h3>Whoops, GitLab is taking too much time to respond.</h3>
|
||||
<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 class="container">
|
||||
<h3>Whoops, GitLab is taking too much time to respond.</h3>
|
||||
<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>
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
<!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>
|
||||
<h3>Whoops, GitLab is currently unavailable.</h3>
|
||||
<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 class="container">
|
||||
<h3>Whoops, GitLab is currently unavailable.</h3>
|
||||
<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>
|
||||
|
|
|
@ -1,54 +1,64 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<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;
|
||||
}
|
||||
<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: auto;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 56px;
|
||||
line-height: 100px;
|
||||
font-weight: normal;
|
||||
color: #456;
|
||||
}
|
||||
h1 {
|
||||
font-size: 56px;
|
||||
line-height: 100px;
|
||||
font-weight: normal;
|
||||
color: #456;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #456;
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 28px;
|
||||
}
|
||||
h3 {
|
||||
color: #456;
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 18px 0;
|
||||
border: 0;
|
||||
border-top: 1px solid #EEE;
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
hr {
|
||||
max-width: 800px;
|
||||
margin: 18px auto;
|
||||
border: 0;
|
||||
border-top: 1px solid #EEE;
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
|
||||
<body>
|
||||
<h1>
|
||||
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" /><br />
|
||||
Deploy in progress
|
||||
</h1>
|
||||
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 />
|
||||
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>
|
||||
|
|