Commit 502aabdc authored by Alejandro Rodríguez's avatar Alejandro Rodríguez

Merge branch 'master' into 8-14-stable

parents b83e8a5a f4710ee8
......@@ -61,9 +61,10 @@ update-knapsack:
- scripts/merge-reports knapsack/spinach_report.json knapsack/spinach_node_*.json
- rm -f knapsack/*_node_*.json
only:
- master
# Execute all testing suites
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
.use-db: &use-db
services:
......@@ -143,7 +144,10 @@ spinach 9 10: *spinach-knapsack
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.1-git-2.7-phantomjs-2.1"
<<: *use-db
only:
- master
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
cache:
key: "ruby21"
paths:
......@@ -286,7 +290,10 @@ bundler:audit:
stage: test
<<: *ruby-static-analysis
only:
- master
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
script:
- "bundle exec bundle-audit check --update --ignore OSVDB-115941"
......@@ -297,6 +304,9 @@ migration paths:
SETUP_DB: "false"
only:
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
script:
- git checkout HEAD .
- git fetch --tags
......
......@@ -63,6 +63,7 @@ header {
&:focus,
&:active {
background-color: $background-color;
color: darken($gl-icon-color, 50%);
}
.fa-caret-down {
......@@ -152,7 +153,7 @@ header {
padding-right: 20px;
margin: 0;
font-size: 19px;
max-width: 400px;
max-width: 385px;
display: inline-block;
line-height: $header-height;
font-weight: normal;
......@@ -191,6 +192,10 @@ header {
font-size: 10px;
text-align: center;
cursor: pointer;
&:hover {
color: darken($color: $gl-text-color, $amount: 50%);
}
}
.project-item-select {
......@@ -218,6 +223,14 @@ header {
}
}
.page-sidebar-pinned.right-sidebar-expanded {
@media (max-width: $screen-lg-min) {
.header-content .title {
width: 300px;
}
}
}
@media (max-width: $screen-xs-max) {
header .container-fluid {
font-size: 18px;
......
......@@ -252,7 +252,7 @@ $award-emoji-new-btn-icon-color: #dcdcdc;
*/
$search-input-border-color: rgba(#4688f1, .8);
$search-input-focus-shadow-color: $dropdown-input-focus-shadow;
$search-input-width: 244px;
$search-input-width: 220px;
$location-badge-color: #aaa;
$location-badge-bg: $gray-normal;
$location-badge-active-bg: #4f91f8;
......
......@@ -84,7 +84,8 @@
font-weight: 600;
}
.commit {
.commit,
.generic_commit_status {
padding: 10px 0;
position: relative;
......@@ -102,7 +103,6 @@
vertical-align: baseline;
}
.avatar {
margin-left: -46px;
}
......
......@@ -141,6 +141,22 @@ ul.notes {
}
}
.page-sidebar-pinned.right-sidebar-expanded {
@media (max-width: $screen-lg-min) {
.note-header {
.note-headline-light {
display: block;
}
.note-actions {
position: absolute;
right: 0;
top: 0;
}
}
}
}
// Diff code in discussion view
.discussion-body .diff-file {
.file-title {
......
......@@ -109,10 +109,6 @@
float: none;
}
.api {
color: $code-color;
}
.branch-commit {
.branch-name {
......
......@@ -21,6 +21,11 @@
padding: 4px;
width: $search-input-width;
line-height: 24px;
&:hover {
border-color: lighten($dropdown-input-focus-border, 20%);
box-shadow: 0 0 4px lighten($search-input-focus-shadow-color, 20%);
}
}
.location-text {
......@@ -28,10 +33,9 @@
}
.search-input {
padding-right: 20px;
border: none;
font-size: 14px;
padding: 0;
padding: 0 20px 0 0;
margin-left: 5px;
line-height: 25px;
width: 98%;
......@@ -153,6 +157,7 @@
width: 68%;
}
}
}
.search-holder {
......@@ -229,4 +234,5 @@
&:focus {
color: $gl-link-color;
}
}
......@@ -7,8 +7,8 @@ class HelpController < ApplicationController
@help_index = File.read(Rails.root.join('doc', 'README.md'))
# Prefix Markdown links with `help/` unless they already have been
# See http://rubular.com/r/nwwhzH6Z8X
@help_index.gsub!(/(\]\()(?!help\/)([^\)\(]+)(\))/, '\1help/\2\3')
# See http://rubular.com/r/ie2MlpdUMq
@help_index.gsub!(/(\]\()(\/?help\/)?([^\)\(]+\))/, '\1/help/\3')
end
def show
......
......@@ -3,7 +3,7 @@ module AuthHelper
FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze
def ldap_enabled?
Gitlab.config.ldap.enabled
Gitlab::LDAP::Config.enabled?
end
def omniauth_enabled?
......
......@@ -82,6 +82,10 @@ module GitlabRoutingHelper
namespace_project_merge_request_path(entity.project.namespace, entity.project, entity, *args)
end
def pipeline_path(pipeline, *args)
namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id, *args)
end
def milestone_path(entity, *args)
namespace_project_milestone_path(entity.project.namespace, entity.project, entity, *args)
end
......
......@@ -203,6 +203,10 @@ class ApplicationSetting < ActiveRecord::Base
ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url)
end
def sidekiq_throttling_column_exists?
ActiveRecord::Base.connection.column_exists?(:application_settings, :sidekiq_throttling_enabled)
end
def domain_whitelist_raw
self.domain_whitelist.join("\n") unless self.domain_whitelist.nil?
end
......@@ -256,6 +260,12 @@ class ApplicationSetting < ActiveRecord::Base
ensure_health_check_access_token!
end
def sidekiq_throttling_enabled?
return false unless sidekiq_throttling_column_exists?
sidekiq_throttling_enabled
end
private
def check_repository_storages
......
......@@ -266,7 +266,7 @@ class Issue < ActiveRecord::Base
def as_json(options = {})
super(options).tap do |json|
json[:subscribed] = subscribed?(options[:user]) if options.has_key?(:user)
json[:subscribed] = subscribed?(options[:user]) if options.has_key?(:user) && options[:user]
if options.has_key?(:labels)
json[:labels] = labels.as_json(
......
......@@ -7,6 +7,7 @@ class Note < ActiveRecord::Base
include Importable
include FasterCacheKeys
include CacheMarkdownField
include AfterCommitQueue
cache_markdown_field :note, pipeline: :note
......
......@@ -49,20 +49,14 @@ class ProjectFeature < ActiveRecord::Base
end
def builds_enabled?
return true unless builds_access_level
builds_access_level > DISABLED
end
def wiki_enabled?
return true unless wiki_access_level
wiki_access_level > DISABLED
end
def merge_requests_enabled?
return true unless merge_requests_access_level
merge_requests_access_level > DISABLED
end
......
......@@ -26,9 +26,12 @@ module Notes
note.note = content
end
if !only_commands && note.save
note.run_after_commit do
# Finish the harder work in the background
NewNoteWorker.perform_in(2.seconds, note.id, params)
NewNoteWorker.perform_async(note.id)
end
if !only_commands && note.save
todo_service.new_note(note, current_user)
end
......
......@@ -84,7 +84,7 @@
= render "shared/empty_states/todos_all_done.svg"
- if todos_filter_empty?
%h4.text-center
Good job! Looks like you don't have any todos left.
= Gitlab.config.gitlab.no_todos_messages.sample
%p.text-center
Are you looking for things to do? Take a look at
= succeed "," do
......
%board-sidebar{ "inline-template" => true,
":current-user" => "#{current_user.to_json(only: [:username, :id, :name], methods: [:avatar_url]) if current_user}" }
":current-user" => "#{current_user ? current_user.to_json(only: [:username, :id, :name], methods: [:avatar_url]) : {}}" }
%aside.right-sidebar.right-sidebar-expanded.issue-boards-sidebar{ "v-show" => "showSidebar" }
.issuable-sidebar
.block.issuable-sidebar-header
......
.block.assignee
.title.hide-collapsed
Assignee
= icon("spinner spin", class: "block-loading")
- if can?(current_user, :admin_issue, @project)
= icon("spinner spin", class: "block-loading")
= link_to "Edit", "#", class: "edit-link pull-right"
.value.hide-collapsed
%span.assign-yourself.no-value{ "v-if" => "!issue.assignee" }
......
.block.due_date
.title
Due date
= icon("spinner spin", class: "block-loading")
- if can?(current_user, :admin_issue, @project)
= icon("spinner spin", class: "block-loading")
= link_to "Edit", "#", class: "edit-link pull-right"
.value
.value-content
......
.block.labels
.title
Labels
= icon("spinner spin", class: "block-loading")
- if can?(current_user, :admin_issue, @project)
= icon("spinner spin", class: "block-loading")
= link_to "Edit", "#", class: "edit-link pull-right"
.value.issuable-show-labels
%span.no-value{ "v-if" => "issue.labels && issue.labels.length === 0" }
......
.block.milestone
.title
Milestone
= icon("spinner spin", class: "block-loading")
- if can?(current_user, :admin_issue, @project)
= icon("spinner spin", class: "block-loading")
= link_to "Edit", "#", class: "edit-link pull-right"
.value
%span.no-value{ "v-if" => "!issue.milestone" }
......
......@@ -3,6 +3,9 @@
= ci_status_with_icon(@build.status)
Build
%strong ##{@build.id}
in pipeline
= link_to pipeline_path(@build.pipeline) do
%strong ##{@build.pipeline.id}
for commit
= link_to ci_status_path(@build.pipeline) do
%strong= @build.pipeline.short_sha
......
......@@ -10,6 +10,7 @@
%tr
%th Status
%th Build
%th Pipeline
- if admin
%th Project
%th Runner
......@@ -19,6 +20,6 @@
%th Coverage
%th
= render partial: "projects/ci/builds/build", collection: builds, as: :build, locals: { commit_sha: true, ref: true, stage: true, allow_retry: true, coverage: admin || project.build_coverage_enabled?, admin: admin }
= render partial: "projects/ci/builds/build", collection: builds, as: :build, locals: { commit_sha: true, ref: true, pipeline_link: true, stage: true, allow_retry: true, coverage: admin || project.build_coverage_enabled?, admin: admin }
= paginate builds, theme: 'gitlab'
- if !project.empty_repo? && can?(current_user, :download_code, project)
%span{class: 'hidden-xs hidden-sm download-button'}
%span{class: 'download-button'}
.dropdown.inline
%button.btn{ 'data-toggle' => 'dropdown' }
= icon('download')
......
......@@ -2,6 +2,7 @@
- ref = local_assigns.fetch(:ref, nil)
- commit_sha = local_assigns.fetch(:commit_sha, nil)
- retried = local_assigns.fetch(:retried, false)
- pipeline_link = local_assigns.fetch(:pipeline_link, false)
- stage = local_assigns.fetch(:stage, false)
- coverage = local_assigns.fetch(:coverage, false)
- allow_retry = local_assigns.fetch(:allow_retry, false)
......@@ -51,6 +52,16 @@
- if build.manual?
%span.label.label-info manual
- if pipeline_link
%td
= link_to pipeline_path(build.pipeline) do
%span.pipeline-id ##{build.pipeline.id}
%span by
- if build.pipeline.user
= user_avatar(user: build.pipeline.user, size: 20)
- else
%span.monospace API
- if admin
%td
- if build.project
......
......@@ -8,8 +8,8 @@
- if stage
&nbsp;
= stage.titleize
= render statuses.latest_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, allow_retry: true
= render statuses.retried_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, retried: true
%tr
= render statuses.latest_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, pipeline_link: false, allow_retry: true
= render statuses.retried_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, pipeline_link: false, retried: true
%tr
%td{colspan: 10}
&nbsp;
......@@ -15,6 +15,16 @@
- if defined?(retried) && retried
= icon('warning', class: 'text-warning has-tooltip', title: 'Status was retried.')
- if defined?(pipeline_link) && pipeline_link
%td
= link_to pipeline_path(generic_commit_status.pipeline) do
%span.pipeline-id ##{generic_commit_status.pipeline.id}
%span by
- if generic_commit_status.pipeline.user
= user_avatar(user: generic_commit_status.pipeline.user, size: 20)
- else
%span.monospace API
- if defined?(commit_sha) && commit_sha
%td
= link_to generic_commit_status.short_sha, namespace_project_commit_path(generic_commit_status.project.namespace, generic_commit_status.project, generic_commit_status.sha), class: "monospace"
......
......@@ -90,7 +90,8 @@
= f.label :visibility_level, class: 'label-light' do
Visibility Level
= link_to "(?)", help_page_path("public_access/public_access")
= render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: @project.visibility_level, form_model: @project)
= render 'shared/visibility_level', f: f, visibility_level: default_project_visibility, can_change_visibility_level: true, form_model: @project
= f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4
= link_to 'Cancel', dashboard_projects_path, class: 'btn btn-cancel'
......
......@@ -2,10 +2,12 @@ class NewNoteWorker
include Sidekiq::Worker
include DedicatedSidekiqQueue
def perform(note_id, note_params)
note = Note.find(note_id)
def perform(note_id)
if note = Note.find_by(id: note_id)
NotificationService.new.new_note(note)
Notes::PostProcessService.new(note).execute
else
Rails.logger.error("NewNoteWorker: couldn't find note with ID=#{note_id}, skipping job")
end
end
end
---
title: Add link to build pipeline within individual build pages
merge_request: 7082
author:
---
title: Project download buttons always show
merge_request: 7405
author: Philip Karpiak
---
title: Fix error links in help index page
merge_request: 7396
author: Fu Xu
---
title: Give search-input correct padding-right value
merge_request: 7407
author: Philip Karpiak
---
title: Show random messages when the To Do list is empty
merge_request: 6818
author: Josep Llaneras
---
title: Fix project Visibility Level selector not using default values
merge_request:
author:
---
title: Fix record not found error on NewNoteWorker processing
merge_request: 6863
author: Oswaldo Ferreira
---
title: Added ability to put emojis into repository name
merge_request: 7420
author: Vincent Composieux
---
title: Centralize LDAP config/filter logic
merge_request: 6606
author:
......@@ -3,8 +3,8 @@
#
production:
adapter: mysql2
encoding: utf8
collation: utf8_general_ci
encoding: utf8mb4
collation: utf8mb4_general_ci
reconnect: false
database: gitlabhq_production
pool: 10
......@@ -18,8 +18,8 @@ production:
#
development:
adapter: mysql2
encoding: utf8
collation: utf8_general_ci
encoding: utf8mb4
collation: utf8mb4_general_ci
reconnect: false
database: gitlabhq_development
pool: 5
......@@ -32,8 +32,8 @@ development:
# Do not set this db to the same as development or production.
test: &test
adapter: mysql2
encoding: utf8
collation: utf8_general_ci
encoding: utf8mb4
collation: utf8mb4_general_ci
reconnect: false
database: gitlabhq_test
pool: 5
......
......@@ -215,6 +215,7 @@ Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(
Settings.gitlab['domain_whitelist'] ||= []
Settings.gitlab['import_sources'] ||= %w[github bitbucket gitlab google_code fogbugz git gitlab_project]
Settings.gitlab['trusted_proxies'] ||= []
Settings.gitlab['no_todos_messages'] ||= YAML.load_file(Rails.root.join('config', 'no_todos_messages.yml'))
#
# CI
......
......@@ -213,22 +213,9 @@ Devise.setup do |config|
end
if Gitlab::LDAP::Config.enabled?
Gitlab.config.ldap.servers.values.each do |server|
if server['allow_username_or_email_login']
email_stripping_proc = ->(name) {name.gsub(/@.*\z/, '')}
else
email_stripping_proc = ->(name) {name}
end
config.omniauth server['provider_name'],
host: server['host'],
base: server['base'],
uid: server['uid'],
port: server['port'],
method: server['method'],
bind_dn: server['bind_dn'],
password: server['password'],
name_proc: email_stripping_proc
Gitlab::LDAP::Config.providers.each do |provider|
ldap_config = Gitlab::LDAP::Config.new(provider)
config.omniauth(provider, ldap_config.omniauth_options)
end
end
......
# When the Todos list on the user's dashboard becomes empty, one of the messages below shows up randomly.
#
# If you come up with a fun one, please feel free to contribute it to GitLab!
# https://about.gitlab.com/contributing/
---
- Good job! Looks like you don't have any todos left.
- Coffee really tastes better without any todos left.
- Isn't an empty To Do list beautiful?
- Time for a rewarding coffee break
- Give yourself a pat on the back!
- High five!
- Hence forth you shall be known as 'Todo Destroyer'
\ No newline at end of file
......@@ -44,7 +44,7 @@ listen "127.0.0.1:8080", :tcp_nopush => true
# nuke workers after 30 seconds instead of 60 seconds (the default)
#
# NOTICE: git push over http depends on this value.
# If you want be able to push huge amount of data to git repository over http
# If you want to be able to push huge amount of data to git repository over http
# you will have to increase this value too.
#
# Example of output if you try to push 1GB repo to GitLab over http.
......@@ -82,7 +82,7 @@ GC.respond_to?(:copy_on_write_friendly=) and
check_client_connection false
before_fork do |server, worker|
# the following is highly recomended for Rails + "preload_app true"
# the following is highly recommended for Rails + "preload_app true"
# as there's no need for the master process to hold a connection
defined?(ActiveRecord::Base) and
ActiveRecord::Base.connection.disconnect!
......
......@@ -76,7 +76,7 @@ configuration to move each data location to a subdirectory:
user['home'] = '/gitlab-data/home'
git_data_dir '/gitlab-data/git-data'
gitlab_rails['shared_path'] = '/gitlab-data/shared'
gitlab_rails['uploads_directory'] = "/gitlab-data/uploads"
gitlab_rails['uploads_directory'] = '/gitlab-data/uploads'
gitlab_ci['builds_directory'] = '/gitlab-data/builds'
```
......
......@@ -48,15 +48,15 @@ Redis.
redis['password'] = 'Redis Password'
```
1. Run `sudo gitlab-ctl reconfigure` to install and configure PostgreSQL.
1. Run `sudo touch /etc/gitlab/skip-auto-migrations` to prevent database migrations
from running on upgrade. Only the primary GitLab application server should
handle migrations.
1. Run `sudo gitlab-ctl reconfigure` to install and configure Redis.
> **Note**: This `reconfigure` step will result in some errors.
That's OK - don't be alarmed.
1. Run `touch /etc/gitlab/skip-auto-migrations` to prevent database migrations
from running on upgrade. Only the primary GitLab application server should
handle migrations.
## Experimental Redis Sentinel support
> [Introduced][ce-1877] in GitLab 8.11.
......
......@@ -14,7 +14,7 @@
contributing to documentation.
- [SQL Migration Style Guide](migration_style_guide.md) for creating safe SQL migrations
- [Testing standards and style guidelines](testing.md)
- [UX guide](ux_guide/README.md) for building GitLab with existing CSS styles and elements
- [UX guide](ux_guide/index.md) for building GitLab with existing CSS styles and elements
- [Frontend guidelines](frontend.md)
- [SQL guidelines](sql.md) for working with SQL queries
- [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers
......
......@@ -14,8 +14,8 @@ There are two ways to create a new project in GitLab.
1. Fill out the information:
1. "Project name" is the name of your project (you can't use spaces, but you
can use hyphens or underscores).
1. "Project name" is the name of your project (you can't use special characters,
but you can use spaces, hyphens, underscores or even emojis).
1. The "Project description" is optional and will be shown in your project's
dashboard so others can briefly understand what your project is about.
1. Select a [visibility level](../public_access/public_access.md).
......
......@@ -44,7 +44,7 @@ This [resource](http://kb.kerio.com/product/kerio-connect/server-configuration/s
has all the information you need to add a certificate to the main trusted chain.
This [answer](http://superuser.com/questions/437330/how-do-you-add-a-certificate-authority-ca-to-ubuntu)
at SuperUser also has relevant information.
at Super User also has relevant information.
**Omnibus Trusted Chain**
......
......@@ -590,7 +590,7 @@ Quote break.
You can also use raw HTML in your Markdown, and it'll mostly work pretty well.
See the documentation for HTML::Pipeline's [SanitizationFilter](http://www.rubydoc.info/gems/html-pipeline/HTML/Pipeline/SanitizationFilter#WHITELIST-constant) class for the list of allowed HTML tags and attributes. In addition to the default `SanitizationFilter` whitelist, GitLab allows `span` elements.
See the documentation for HTML::Pipeline's [SanitizationFilter](http://www.rubydoc.info/gems/html-pipeline/1.11.0/HTML/Pipeline/SanitizationFilter#WHITELIST-constant) class for the list of allowed HTML tags and attributes. In addition to the default `SanitizationFilter` whitelist, GitLab allows `span` elements.
```no-highlight
<dl>
......
......@@ -48,7 +48,7 @@ module API
put ':id/access_requests/:user_id/approve' do
source = find_source(source_type, params[:id])
member = ::Members::ApproveAccessRequestService.new(source, current_user, declared(params)).execute
member = ::Members::ApproveAccessRequestService.new(source, current_user, declared_params).execute
status :created
present member.user, with: Entities::Member, member: member
......
......@@ -36,8 +36,7 @@ module API
optional :font, type: String, desc: 'Foreground color'
end
post do
create_params = declared(params, include_missing: false).to_h
message = BroadcastMessage.create(create_params)
message = BroadcastMessage.create(declared_params(include_missing: false))
if message.persisted?
present message, with: Entities::BroadcastMessage
......@@ -73,9 +72,8 @@ module API
end
put ':id' do
message = find_message
update_params = declared(params, include_missing: false).to_h
if message.update(update_params)
if message.update(declared_params(include_missing: false))
present message, with: Entities::BroadcastMessage
else
render_validation_error!(message)
......
......@@ -53,7 +53,7 @@ module API
post ":id/repository/commits" do
authorize! :push_code, user_project
attrs = declared(params)
attrs = declared_params
attrs[:source_branch] = attrs[:branch_name]
attrs[:target_branch] = attrs[:branch_name]
attrs[:actions].map! do |action|
......
......@@ -82,7 +82,7 @@ module API
end
post ":id/#{path}/:key_id/enable" do
key = ::Projects::EnableDeployKeyService.new(user_project,
current_user, declared(params)).execute
current_user, declared_params).execute
if key
present key, with: Entities::SSHKey
......
......@@ -32,8 +32,7 @@ module API
post ':id/environments' do
authorize! :create_environment, user_project
create_params = declared(params, include_parent_namespaces: false).to_h
environment = user_project.environments.create(create_params)
environment = user_project.environments.create(declared_params)
if environment.persisted?
present environment, with: Entities::Environment
......@@ -56,7 +55,7 @@ module API
environment = user_project.environments.find(params[:environment_id])
update_params = declared(params, include_missing: false).extract!(:name, :external_url).to_h
update_params = declared_params(include_missing: false).extract!(:name, :external_url)
if environment.update(update_params)
present environment, with: Entities::Environment
else
......
......@@ -23,6 +23,11 @@ module API
warden.try(:authenticate) if %w[GET HEAD].include?(env['REQUEST_METHOD'])
end
def declared_params(options = {})
options = { include_parent_namespaces: false }.merge(options)
declared(params, options).to_h.symbolize_keys
end
def find_user_by_private_token
token = private_token
return nil unless token.present?
......
......@@ -30,10 +30,7 @@ module API
conflict!('Label already exists') if label
priority = params.delete(:priority)
label_params = declared(params,
include_parent_namespaces: false,
include_missing: false).to_h
label = user_project.labels.create(label_params)
label = user_project.labels.create(declared_params(include_missing: false))
if label.valid?
label.prioritize!(user_project, priority) if priority
......@@ -77,11 +74,9 @@ module API
update_priority = params.key?(:priority)
priority = params.delete(:priority)
label_params = declared(params,
include_parent_namespaces: false,
include_missing: false).to_h
label_params = declared_params(include_missing: false)
# Rename new name to the actual label attribute name
label_params[:name] = label_params.delete('new_name') if label_params.key?('new_name')
label_params[:name] = label_params.delete(:new_name) if label_params.key?(:new_name)
render_validation_error!(label) unless label.update(label_params)
......
......@@ -120,7 +120,7 @@ module API
if member.nil?
{ message: "Access revoked", id: params[:user_id].to_i }
else
::Members::DestroyService.new(source, current_user, declared(params)).execute
::Members::DestroyService.new(source, current_user, declared_params).execute
present member.user, with: Entities::Member, member: member
end
......
......@@ -62,9 +62,8 @@ module API
end
post ":id/milestones" do
authorize! :admin_milestone, user_project
milestone_params = declared(params, include_parent_namespaces: false)
milestone = ::Milestones::CreateService.new(user_project, current_user, milestone_params).execute
milestone = ::Milestones::CreateService.new(user_project, current_user, declared_params).execute
if milestone.valid?
present milestone, with: Entities::Milestone
......@@ -86,9 +85,9 @@ module API
end
put ":id/milestones/:milestone_id" do
authorize! :admin_milestone, user_project
milestone_params = declared(params, include_parent_namespaces: false, include_missing: false)
milestone = user_project.milestones.find(params.delete(:milestone_id))
milestone = user_project.milestones.find(milestone_params.delete(:milestone_id))
milestone_params = declared_params(include_missing: false)
milestone = ::Milestones::UpdateService.new(user_project, current_user, milestone_params).execute(milestone)
if milestone.valid?
......
......@@ -33,10 +33,9 @@ module API
begin
notification_setting.transaction do
new_notification_email = params.delete(:notification_email)
declared_params = declared(params, include_missing: false).to_h
current_user.update(notification_email: new_notification_email) if new_notification_email
notification_setting.update(declared_params)
notification_setting.update(declared_params(include_missing: false))
end
rescue ArgumentError => e # catch level enum error
render_api_error! e.to_s, 400
......@@ -81,9 +80,7 @@ module API
notification_setting = current_user.notification_settings_for(source)
begin
declared_params = declared(params, include_missing: false).to_h
notification_setting.update(declared_params)
notification_setting.update(declared_params(include_missing: false))
rescue ArgumentError => e # catch level enum error
render_api_error! e.to_s, 400
end
......
......@@ -51,8 +51,7 @@ module API
use :project_hook_properties
end
post ":id/hooks" do
new_hook_params = declared(params, include_missing: false, include_parent_namespaces: false).to_h
hook = user_project.hooks.new(new_hook_params)
hook = user_project.hooks.new(declared_params(include_missing: false))
if hook.save
present hook, with: Entities::ProjectHook
......@@ -71,12 +70,9 @@ module API
use :project_hook_properties
end
put ":id/hooks/:hook_id" do
hook = user_project.hooks.find(params[:hook_id])
new_params = declared(params, include_missing: false, include_parent_namespaces: false).to_h
new_params.delete('hook_id')
hook = user_project.hooks.find(params.delete(:hook_id))
if hook.update_attributes(new_params)
if hook.update_attributes(declared_params(include_missing: false))
present hook, with: Entities::ProjectHook
else
error!("Invalid url given", 422) if hook.errors[:url].present?
......
......@@ -57,9 +57,7 @@ module API
runner = get_runner(params.delete(:id))
authenticate_update_runner!(runner)
runner_params = declared(params, include_missing: false)
if runner.update(runner_params)
if runner.update(declared_params(include_missing: false))
present runner, with: Entities::RunnerDetails, current_user: current_user
else
render_validation_error!(runner)
......
......@@ -9,23 +9,20 @@ module API
'labels' => proc { |id| find_project_label(id) },
}
params do
requires :id, type: String, desc: 'The ID of a project'
requires :subscribable_id, type: String, desc: 'The ID of a resource'
end
resource :projects do
subscribable_types.each do |type, finder|
type_singularized = type.singularize
type_id_str = :"#{type_singularized}_id"
entity_class = Entities.const_get(type_singularized.camelcase)
# Subscribe to a resource
#
# Parameters:
# id (required) - The ID of a project
# subscribable_id (required) - The ID of a resource
# Example Request:
# POST /projects/:id/labels/:subscribable_id/subscription
# POST /projects/:id/issues/:subscribable_id/subscription
# POST /projects/:id/merge_requests/:subscribable_id/subscription
post ":id/#{type}/:#{type_id_str}/subscription" do
resource = instance_exec(params[type_id_str], &finder)
desc 'Subscribe to a resource' do
success entity_class
end
post ":id/#{type}/:subscribable_id/subscription" do
resource = instance_exec(params[:subscribable_id], &finder)
if resource.subscribed?(current_user)
not_modified!
......@@ -35,17 +32,11 @@ module API
end
end
# Unsubscribe from a resource
#
# Parameters:
# id (required) - The ID of a project
# subscribable_id (required) - The ID of a resource
# Example Request:
# DELETE /projects/:id/labels/:subscribable_id/subscription
# DELETE /projects/:id/issues/:subscribable_id/subscription
# DELETE /projects/:id/merge_requests/:subscribable_id/subscription
delete ":id/#{type}/:#{type_id_str}/subscription" do
resource = instance_exec(params[type_id_str], &finder)
desc 'Unsubscribe from a resource' do
success entity_class
end
delete ":id/#{type}/:subscribable_id/subscription" do
resource = instance_exec(params[:subscribable_id], &finder)
if !resource.subscribed?(current_user)
not_modified!
......
......@@ -27,7 +27,7 @@ module API
optional :enable_ssl_verification, type: Boolean, desc: "Do SSL verification when triggering the hook"
end
post do
hook = SystemHook.new declared(params, include_missing: false).to_h
hook = SystemHook.new(declared_params(include_missing: false))
if hook.save
present hook, with: Entities::Hook
......
......@@ -40,10 +40,9 @@ module API
end
post ':id/repository/tags' do
authorize_push_project
create_params = declared(params)
result = CreateTagService.new(user_project, current_user).
execute(create_params[:tag_name], create_params[:ref], create_params[:message], create_params[:release_description])
execute(params[:tag_name], params[:ref], params[:message], params[:release_description])
if result[:status] == :success
present result[:tag],
......
......@@ -335,7 +335,7 @@ module API
requires :id, type: String, desc: 'The user ID'
end
get ':id/events' do
user = User.find_by(id: declared(params).id)
user = User.find_by(id: params[:id])
not_found!('User') unless user
events = user.events.
......
......@@ -2,7 +2,7 @@ module Ci
class GitlabCiYamlProcessor
class ValidationError < StandardError; end
include Gitlab::Ci::Config::Node::LegacyValidationHelpers
include Gitlab::Ci::Config::Entry::LegacyValidationHelpers
attr_reader :path, :cache, :stages, :jobs
......
......@@ -13,7 +13,7 @@ module Gitlab
def initialize(config)
@config = Loader.new(config).load!
@global = Node::Global.new(@config)
@global = Entry::Global.new(@config)
@global.compose!
end
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a configuration of job artifacts.
#
class Artifacts < Entry
class Artifacts < Node
include Validatable
include Attributable
......
module Gitlab
module Ci
class Config
module Node
module Entry
module Attributable
extend ActiveSupport::Concern
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a boolean value.
#
class Boolean < Entry
class Boolean < Node
include Validatable
validations do
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a cache configuration
#
class Cache < Entry
class Cache < Node
include Configurable
ALLOWED_KEYS = %i[key untracked paths]
......@@ -14,13 +14,13 @@ module Gitlab
validates :config, allowed_keys: ALLOWED_KEYS
end
node :key, Node::Key,
entry :key, Entry::Key,
description: 'Cache key used to define a cache affinity.'
node :untracked, Node::Boolean,
entry :untracked, Entry::Boolean,
description: 'Cache all untracked files.'
node :paths, Node::Paths,
entry :paths, Entry::Paths,
description: 'Specify which paths should be cached across builds.'
end
end
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a job script.
#
class Commands < Entry
class Commands < Node
include Validatable
validations do
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# This mixin is responsible for adding DSL, which purpose is to
# simplifly process of adding child nodes.
......@@ -48,8 +48,8 @@ module Gitlab
private # rubocop:disable Lint/UselessAccessModifier
def node(key, node, metadata)
factory = Node::Factory.new(node)
def entry(key, entry, metadata)
factory = Entry::Factory.new(entry)
.with(description: metadata[:description])
(@nodes ||= {}).merge!(key.to_sym => factory)
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents an environment.
#
class Environment < Entry
class Environment < Node
include Validatable
ALLOWED_KEYS = %i[name url action on_stop]
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Factory class responsible for fabricating node entry objects.
# Factory class responsible for fabricating entry objects.
#
class Factory
class InvalidFactory < StandardError; end
def initialize(node)
@node = node
def initialize(entry)
@entry = entry
@metadata = {}
@attributes = {}
end
......@@ -37,11 +37,11 @@ module Gitlab
# See issue #18775.
#
if @value.nil?
Node::Unspecified.new(
Entry::Unspecified.new(
fabricate_unspecified
)
else
fabricate(@node, @value)
fabricate(@entry, @value)
end
end
......@@ -49,21 +49,21 @@ module Gitlab
def fabricate_unspecified
##
# If node has a default value we fabricate concrete node
# If entry has a default value we fabricate concrete node
# with default value.
#
if @node.default.nil?
fabricate(Node::Undefined)
if @entry.default.nil?
fabricate(Entry::Undefined)
else
fabricate(@node, @node.default)
fabricate(@entry, @entry.default)
end
end
def fabricate(node, value = nil)
node.new(value, @metadata).tap do |entry|
entry.key = @attributes[:key]
entry.parent = @attributes[:parent]
entry.description = @attributes[:description]
def fabricate(entry, value = nil)
entry.new(value, @metadata).tap do |node|
node.key = @attributes[:key]
node.parent = @attributes[:parent]
node.description = @attributes[:description]
end
end
end
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# This class represents a global entry - root node for entire
# This class represents a global entry - root Entry for entire
# GitLab CI Configuration file.
#
class Global < Entry
class Global < Node
include Configurable
node :before_script, Node::Script,
entry :before_script, Entry::Script,
description: 'Script that will be executed before each job.'
node :image, Node::Image,
entry :image, Entry::Image,
description: 'Docker image that will be used to execute jobs.'
node :services, Node::Services,
entry :services, Entry::Services,
description: 'Docker images that will be linked to the container.'
node :after_script, Node::Script,
entry :after_script, Entry::Script,
description: 'Script that will be executed after each job.'
node :variables, Node::Variables,
entry :variables, Entry::Variables,
description: 'Environment variables that will be used.'
node :stages, Node::Stages,
entry :stages, Entry::Stages,
description: 'Configuration of stages for this pipeline.'
node :types, Node::Stages,
entry :types, Entry::Stages,
description: 'Deprecated: stages for this pipeline.'
node :cache, Node::Cache,
entry :cache, Entry::Cache,
description: 'Configure caching between build jobs.'
helpers :before_script, :image, :services, :after_script,
......@@ -46,7 +46,7 @@ module Gitlab
private
def compose_jobs!
factory = Node::Factory.new(Node::Jobs)
factory = Entry::Factory.new(Entry::Jobs)
.value(@config.except(*self.class.nodes.keys))
.with(key: :jobs, parent: self,
description: 'Jobs definition for this pipeline')
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a hidden CI/CD job.
# Entry that represents a hidden CI/CD key.
#
class Hidden < Entry
class Hidden < Node
include Validatable
validations do
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a Docker image.
#
class Image < Entry
class Image < Node
include Validatable
validations do
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a concrete CI/CD job.
#
class Job < Entry
class Job < Node
include Configurable
include Attributable
......@@ -34,43 +34,43 @@ module Gitlab
end
end
node :before_script, Node::Script,
entry :before_script, Entry::Script,
description: 'Global before script overridden in this job.'
node :script, Node::Commands,
entry :script, Entry::Commands,
description: 'Commands that will be executed in this job.'
node :stage, Node::Stage,
entry :stage, Entry::Stage,
description: 'Pipeline stage this job will be executed into.'
node :type, Node::Stage,
entry :type, Entry::Stage,
description: 'Deprecated: stage this job will be executed into.'
node :after_script, Node::Script,
entry :after_script, Entry::Script,
description: 'Commands that will be executed when finishing job.'
node :cache, Node::Cache,
entry :cache, Entry::Cache,
description: 'Cache definition for this job.'
node :image, Node::Image,
entry :image, Entry::Image,
description: 'Image that will be used to execute this job.'
node :services, Node::Services,
entry :services, Entry::Services,
description: 'Services that will be used to execute this job.'
node :only, Node::Trigger,
entry :only, Entry::Trigger,
description: 'Refs policy this job will be executed for.'
node :except, Node::Trigger,
entry :except, Entry::Trigger,
description: 'Refs policy this job will be executed for.'
node :variables, Node::Variables,
entry :variables, Entry::Variables,
description: 'Environment variables available for this job.'
node :artifacts, Node::Artifacts,
entry :artifacts, Entry::Artifacts,
description: 'Artifacts configuration for this job.'
node :environment, Node::Environment,
entry :environment, Entry::Environment,
description: 'Environment configuration for this job.'
helpers :before_script, :script, :stage, :type, :after_script,
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a set of jobs.
#
class Jobs < Entry
class Jobs < Node
include Validatable
validations do
......@@ -29,9 +29,9 @@ module Gitlab
def compose!(deps = nil)
super do
@config.each do |name, config|
node = hidden?(name) ? Node::Hidden : Node::Job
node = hidden?(name) ? Entry::Hidden : Entry::Job
factory = Node::Factory.new(node)
factory = Entry::Factory.new(node)
.value(config || {})
.metadata(name: name)
.with(key: name, parent: self,
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a key.
#
class Key < Entry
class Key < Node
include Validatable
validations do
......
module Gitlab
module Ci
class Config
module Node
module Entry
module LegacyValidationHelpers
private
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Base abstract class for each configuration entry node.
#
class Entry
class Node
class InvalidError < StandardError; end
attr_reader :config, :metadata
......@@ -21,7 +21,7 @@ module Gitlab
end
def [](key)
@entries[key] || Node::Undefined.new
@entries[key] || Entry::Undefined.new
end
def compose!(deps = nil)
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents an array of paths.
#
class Paths < Entry
class Paths < Node
include Validatable
validations do
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a script.
#
class Script < Entry
class Script < Node
include Validatable
validations do
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a configuration of Docker services.
#
class Services < Entry
class Services < Node
include Validatable
validations do
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a stage for a job.
#
class Stage < Entry
class Stage < Node
include Validatable
validations do
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a configuration for pipeline stages.
#
class Stages < Entry
class Stages < Node
include Validatable
validations do
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents a trigger policy for the job.
#
class Trigger < Entry
class Trigger < Node
include Validatable
validations do
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# This class represents an undefined node.
# This class represents an undefined entry.
#
# Implements the Null Object pattern.
#
class Undefined < Entry
class Undefined < Node
def initialize(*)
super(nil)
end
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# This class represents an unspecified entry node.
# This class represents an unspecified entry.
#
# It decorates original entry adding method that indicates it is
# unspecified.
......
module Gitlab
module Ci
class Config
module Node
module Entry
module Validatable
extend ActiveSupport::Concern
class_methods do
def validator
@validator ||= Class.new(Node::Validator).tap do |validator|
@validator ||= Class.new(Entry::Validator).tap do |validator|
if defined?(@validations)
@validations.each { |rules| validator.class_eval(&rules) }
end
......
module Gitlab
module Ci
class Config
module Node
module Entry
class Validator < SimpleDelegator
include ActiveModel::Validations
include Node::Validators
include Entry::Validators
def initialize(node)
super(node)
@node = node
def initialize(entry)
super(entry)
@entry = entry
end
def messages
......@@ -30,7 +30,7 @@ module Gitlab
def key_name
if key.blank?
@node.class.name.demodulize.underscore.humanize
@entry.class.name.demodulize.underscore.humanize
else
key
end
......
module Gitlab
module Ci
class Config
module Node
module Entry
module Validators
class AllowedKeysValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
......
module Gitlab
module Ci
class Config
module Node
module Entry
##
# Entry that represents environment variables.
#
class Variables < Entry
class Variables < Node
include Validatable
validations do
......
......@@ -24,7 +24,7 @@ module Gitlab
end
def sidekiq_throttling_enabled?
current_application_settings.sidekiq_throttling_enabled
current_application_settings.sidekiq_throttling_enabled?
end
def fake_application_settings
......
......@@ -89,9 +89,7 @@ module Gitlab
end
def user_filter(filter = nil)
if config.user_filter.present?
user_filter = Net::LDAP::Filter.construct(config.user_filter)
end
user_filter = config.constructed_user_filter if config.user_filter.present?
if user_filter && filter
Net::LDAP::Filter.join(filter, user_filter)
......
......@@ -54,11 +54,9 @@ module Gitlab
# Apply LDAP user filter if present
if config.user_filter.present?
filter = Net::LDAP::Filter.join(
filter,
Net::LDAP::Filter.construct(config.user_filter)
)
filter = Net::LDAP::Filter.join(filter, config.constructed_user_filter)
end
filter
end
......
......@@ -13,7 +13,7 @@ module Gitlab
end
def self.providers
servers.map {|server| server['provider_name'] }
servers.map { |server| server['provider_name'] }
end
def self.valid_provider?(provider)
......@@ -38,13 +38,31 @@ module Gitlab
end
def adapter_options
{
host: options['host'],
port: options['port'],
encryption: encryption
}.tap do |options|
options.merge!(auth_options) if has_auth?
opts = base_options.merge(
encryption: encryption,
)
opts.merge!(auth_options) if has_auth?
opts
end
def omniauth_options
opts = base_options.merge(
base: base,
method: options['method'],
filter: omniauth_user_filter,
name_proc: name_proc
)
if has_auth?
opts.merge!(
bind_dn: options['bind_dn'],
password: options['password']
)
end
opts
end
def base
......@@ -68,6 +86,10 @@ module Gitlab
options['user_filter']
end
def constructed_user_filter
@constructed_user_filter ||= Net::LDAP::Filter.construct(user_filter)
end
def group_base
options['group_base']
end
......@@ -96,8 +118,27 @@ module Gitlab
options['password'] || options['bind_dn']
end
def allow_username_or_email_login
options['allow_username_or_email_login']
end
def name_proc
if allow_username_or_email_login
Proc.new { |name| name.gsub(/@.*\z/, '') }
else
Proc.new { |name| name }
end
end
protected
def base_options
{
host: options['host'],
port: options['port']
}
end
def base_config
Gitlab.config.ldap
end
......@@ -126,6 +167,16 @@ module Gitlab
}
}
end
def omniauth_user_filter
uid_filter = Net::LDAP::Filter.eq(uid, '%{username}')
if user_filter.present?
Net::LDAP::Filter.join(uid_filter, constructed_user_filter).to_s
else
uid_filter.to_s
end
end
end
end
end
......@@ -26,12 +26,12 @@ module Gitlab
end
def project_name_regex
@project_name_regex ||= /\A[\p{Alnum}_][\p{Alnum}\p{Pd}_\. ]*\z/.freeze
@project_name_regex ||= /\A[\p{Alnum}\u{00A9}-\u{1f9c0}_][\p{Alnum}\p{Pd}\u{00A9}-\u{1f9c0}_\. ]*\z/.freeze
end
def project_name_regex_message
"can contain only letters, digits, '_', '.', dash and space. " \
"It must start with letter, digit or '_'."
"can contain only letters, digits, emojis, '_', '.', dash, space. " \
"It must start with letter, digit, emoji or '_'."
end
def project_path_regex
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment