Skip to content
Snippets Groups Projects
Commit deed6022 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent f7a13c56
No related branches found
No related tags found
No related merge requests found
Showing
with 151 additions and 289 deletions
Loading
Loading
@@ -16,7 +16,7 @@ class UsersController < ApplicationController
 
skip_before_action :authenticate_user!
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
before_action :user, except: [:exists]
before_action :user, except: [:exists, :suggests]
before_action :authorize_read_user_profile!,
only: [:calendar, :calendar_activities, :groups, :projects, :contributed_projects, :starred_projects, :snippets]
 
Loading
Loading
@@ -114,6 +114,14 @@ class UsersController < ApplicationController
render json: { exists: !!Namespace.find_by_path_or_name(params[:username]) }
end
 
def suggests
namespace_path = params[:username]
exists = !!Namespace.find_by_path_or_name(namespace_path)
suggestions = exists ? [Namespace.clean_path(namespace_path)] : []
render json: { exists: exists, suggests: suggestions }
end
private
 
def user
Loading
Loading
Loading
Loading
@@ -55,6 +55,7 @@ scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) d
get :starred, as: :starred_projects
get :snippets
get :exists
get :suggests
get :activity
get '/', to: redirect('%{username}'), as: nil
end
Loading
Loading
Loading
Loading
@@ -50,10 +50,9 @@ In their own machine, configure the Gitaly server as described in the
 
#### Praefect
 
Next, Praefect has to be enabled on its own node. Disable all other services,
and add each Gitaly node that will be connected to Praefect. In the example below,
the Gitaly nodes are named `praefect-git-X`. Note that one node is designated as
primary, by setting the primary to `true`:
Next, Praefect has to be enabled on its own node.
##### Disable other services
 
```ruby
# /etc/gitlab/gitlab.rb
Loading
Loading
@@ -67,27 +66,36 @@ unicorn['enable'] = false
sidekiq['enable'] = false
gitlab_workhorse['enable'] = false
gitaly['enable'] = false
```
##### Set up Praefect and its Gitaly nodes
In the example below, the Gitaly nodes are named `praefect-git-X`. Note that one node is designated as
primary, by setting the primary to `true`:
```ruby
# /etc/gitlab/gitlab.rb
 
# virtual_storage_name must match the same storage name given to praefect in git_data_dirs
praefect['virtual_storage_name'] = 'praefect'
praefect['auth_token'] = 'super_secret_abc'
praefect['auth_token'] = 'abc123secret'
praefect['enable'] = true
praefect['storage_nodes'] = [
{
'storage' => 'praefect-git-1',
'address' => 'tcp://praefect-git-1.internal',
'token' => 'token1',
'token' => 'xyz123secret',
'primary' => true
},
{
'storage' => 'praefect-git-2',
'address' => 'tcp://praefect-git-2.internal',
'token' => 'token2'
'token' => 'xyz456secret',
},
{
'storage' => 'praefect-git-3',
'address' => 'tcp://praefect-git-3.internal',
'token' => 'token3'
'token' => 'xyz789secret',
}
]
```
Loading
Loading
@@ -97,7 +105,28 @@ Save the file and [reconfigure Praefect](../restart_gitlab.md#omnibus-gitlab-rec
#### GitLab
 
When Praefect is running, it should be exposed as a storage to GitLab. This
is done through setting the `git_data_dirs`. Assuming the default storage
is done through setting the `git_data_dirs`.
##### On a fresh GitLab installation
On a fresh Gitlab installation, set up the `default` storage to point to praefect:
```ruby
git_data_dirs({
"default" => {
"gitaly_address" => "tcp://praefect.internal:2305"
},
})
```
##### On an existing GitLab instance
On an existing GitLab instance, the `default` storage is already being served by a
Gitaly node, so an additional storage can be added. `praefect` is chosen in the example
below, but it can be any name as long as it matches the `virtual_storage_name` in the
praefect attributes above.
Assuming the default storage
configuration is used, there would be two storages available to GitLab:
 
```ruby
Loading
Loading
Loading
Loading
@@ -96,7 +96,7 @@ To enable the redirection, add the following line in `/etc/gitlab/gitlab.rb`:
nginx['custom_gitlab_server_config'] = "location /-/plantuml/ { \n proxy_cache off; \n proxy_pass http://plantuml:8080/; \n}\n"
 
# Built from source
nginx['custom_gitlab_server_config'] = "location /-/plantuml/ { \n proxy_cache off; \n proxy_pass http://127.0.0.1:8080/plantuml/; \n}\n"
nginx['custom_gitlab_server_config'] = "location /-/plantuml { \n rewrite ^/-/(plantuml.*) /$1 break;\n proxy_cache off; \n proxy_pass http://localhost:8080/plantuml; \n}\n"
```
 
To activate the changes, run the following command:
Loading
Loading
Loading
Loading
@@ -50,6 +50,7 @@ module Gitlab
validates :timeout, duration: { limit: ChronicDuration.output(Project::MAX_BUILD_TIMEOUT) }
 
validates :dependencies, array_of_strings: true
validates :needs, array_of_strings: true
validates :extends, array_of_strings_or_string: true
validates :rules, array_of_hashes: true
end
Loading
Loading
@@ -113,11 +114,6 @@ module Gitlab
description: 'List of evaluable Rules to determine job inclusion.',
inherit: false
 
entry :needs, Entry::Needs,
description: 'Needs configuration for this job.',
metadata: { allowed_needs: %i[job] },
inherit: false
entry :variables, Entry::Variables,
description: 'Environment variables available for this job.',
inherit: false
Loading
Loading
# frozen_string_literal: true
module Gitlab
module Ci
class Config
module Entry
class Need < ::Gitlab::Config::Entry::Simplifiable
strategy :Job, if: -> (config) { config.is_a?(String) }
class Job < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
validations do
validates :config, presence: true
validates :config, type: String
end
def type
:job
end
def value
{ name: @config }
end
end
class UnknownStrategy < ::Gitlab::Config::Entry::Node
def type
end
def value
end
def errors
["#{location} has an unsupported type"]
end
end
end
end
end
end
end
::Gitlab::Ci::Config::Entry::Need.prepend_if_ee('::EE::Gitlab::Ci::Config::Entry::Need')
# frozen_string_literal: true
module Gitlab
module Ci
class Config
module Entry
##
# Entry that represents a set of needs dependencies.
#
class Needs < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
validations do
validates :config, presence: true
validate do
unless config.is_a?(Hash) || config.is_a?(Array)
errors.add(:config, 'can only be a Hash or an Array')
end
end
validate on: :composed do
extra_keys = value.keys - opt(:allowed_needs)
if extra_keys.any?
errors.add(:config, "uses invalid types: #{extra_keys.join(', ')}")
end
end
end
def compose!(deps = nil)
super(deps) do
[@config].flatten.each_with_index do |need, index|
@entries[index] = ::Gitlab::Config::Entry::Factory.new(Entry::Need)
.value(need)
.with(key: "need", parent: self, description: "need definition.") # rubocop:disable CodeReuse/ActiveRecord
.create!
end
@entries.each_value do |entry|
entry.compose!(deps)
end
end
end
def value
values = @entries.values.select(&:type)
values.group_by(&:type).transform_values do |values|
values.map(&:value)
end
end
end
end
end
end
end
Loading
Loading
@@ -40,7 +40,7 @@ module Gitlab
environment: job[:environment_name],
coverage_regex: job[:coverage],
yaml_variables: yaml_variables(name),
needs_attributes: job.dig(:needs, :job),
needs_attributes: job[:needs]&.map { |need| { name: need } },
interruptible: job[:interruptible],
rules: job[:rules],
options: {
Loading
Loading
@@ -59,7 +59,7 @@ module Gitlab
instance: job[:instance],
start_in: job[:start_in],
trigger: job[:trigger],
bridge_needs: job.dig(:needs, :bridge)&.first
bridge_needs: job[:needs]
}.compact }.compact
end
 
Loading
Loading
@@ -159,19 +159,17 @@ module Gitlab
end
 
def validate_job_needs!(name, job)
return unless job.dig(:needs, :job)
return unless job[:needs]
 
stage_index = @stages.index(job[:stage])
 
job.dig(:needs, :job).each do |need|
need_job_name = need[:name]
job[:needs].each do |need|
raise ValidationError, "#{name} job: undefined need: #{need}" unless @jobs[need.to_sym]
 
raise ValidationError, "#{name} job: undefined need: #{need_job_name}" unless @jobs[need_job_name.to_sym]
needs_stage_index = @stages.index(@jobs[need_job_name.to_sym][:stage])
needs_stage_index = @stages.index(@jobs[need.to_sym][:stage])
 
unless needs_stage_index.present? && needs_stage_index < stage_index
raise ValidationError, "#{name} job: need #{need_job_name} is not defined in prior stages"
raise ValidationError, "#{name} job: need #{need} is not defined in prior stages"
end
end
end
Loading
Loading
Loading
Loading
@@ -29,24 +29,22 @@ module Gitlab
def compose!(deps = nil)
return unless valid?
 
super do
self.class.nodes.each do |key, factory|
# If we override the config type validation
# we can end with different config types like String
next unless config.is_a?(Hash)
self.class.nodes.each do |key, factory|
# If we override the config type validation
# we can end with different config types like String
next unless config.is_a?(Hash)
 
factory
.value(config[key])
.with(key: key, parent: self)
factory
.value(config[key])
.with(key: key, parent: self)
 
entries[key] = factory.create!
end
entries[key] = factory.create!
end
 
yield if block_given?
yield if block_given?
 
entries.each_value do |entry|
entry.compose!(deps)
end
entries.each_value do |entry|
entry.compose!(deps)
end
end
# rubocop: enable CodeReuse/ActiveRecord
Loading
Loading
@@ -69,13 +67,12 @@ module Gitlab
private
 
# rubocop: disable CodeReuse/ActiveRecord
def entry(key, entry, description: nil, default: nil, inherit: nil, reserved: nil, metadata: {})
def entry(key, entry, description: nil, default: nil, inherit: nil, reserved: nil)
factory = ::Gitlab::Config::Entry::Factory.new(entry)
.with(description: description)
.with(default: default)
.with(inherit: inherit)
.with(reserved: reserved)
.metadata(metadata)
 
(@nodes ||= {}).merge!(key.to_sym => factory)
end
Loading
Loading
Loading
Loading
@@ -112,10 +112,6 @@ module Gitlab
@aspects ||= []
end
 
def self.with_aspect(blk)
self.aspects.append(blk)
end
private
 
attr_reader :entries
Loading
Loading
Loading
Loading
@@ -4,11 +4,11 @@ module Gitlab
module Config
module Entry
class Simplifiable < SimpleDelegator
EntryStrategy = Struct.new(:name, :klass, :condition)
EntryStrategy = Struct.new(:name, :condition)
 
attr_reader :subject
 
def initialize(config, **metadata, &blk)
def initialize(config, **metadata)
unless self.class.const_defined?(:UnknownStrategy)
raise ArgumentError, 'UndefinedStrategy not available!'
end
Loading
Loading
@@ -19,13 +19,14 @@ module Gitlab
 
entry = self.class.entry_class(strategy)
 
@subject = entry.new(config, metadata, &blk)
@subject = entry.new(config, metadata)
 
yield(@subject) if block_given?
super(@subject)
end
 
def self.strategy(name, **opts)
EntryStrategy.new(name, opts.dig(:class), opts.fetch(:if)).tap do |strategy|
EntryStrategy.new(name, opts.fetch(:if)).tap do |strategy|
strategies.append(strategy)
end
end
Loading
Loading
@@ -36,7 +37,7 @@ module Gitlab
 
def self.entry_class(strategy)
if strategy.present?
strategy.klass || self.const_get(strategy.name, false)
self.const_get(strategy.name, false)
else
self::UnknownStrategy
end
Loading
Loading
Loading
Loading
@@ -7,27 +7,14 @@ module Gitlab
extend ActiveSupport::Concern
 
def self.included(node)
node.with_aspect -> do
validate(:new)
node.aspects.append -> do
@validator = self.class.validator.new(self)
@validator.validate(:new)
end
end
 
def validator
@validator ||= self.class.validator.new(self)
end
def validate(context = nil)
validator.validate(context)
end
def compose!(deps = nil, &blk)
super(deps, &blk)
validate(:composed)
end
def errors
validator.messages + descendants.flat_map(&:errors)
@validator.messages + descendants.flat_map(&:errors) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
 
class_methods do
Loading
Loading
Loading
Loading
@@ -348,6 +348,48 @@ describe UsersController do
end
end
 
describe 'GET #suggests' do
context 'when user exists' do
it 'returns JSON indicating the user exists and a suggestion' do
get :suggests, params: { username: user.username }
expected_json = { exists: true, suggests: ["#{user.username}1"] }.to_json
expect(response.body).to eq(expected_json)
end
context 'when the casing is different' do
let(:user) { create(:user, username: 'CamelCaseUser') }
it 'returns JSON indicating the user exists and a suggestion' do
get :suggests, params: { username: user.username.downcase }
expected_json = { exists: true, suggests: ["#{user.username.downcase}1"] }.to_json
expect(response.body).to eq(expected_json)
end
end
end
context 'when the user does not exist' do
it 'returns JSON indicating the user does not exist' do
get :suggests, params: { username: 'foo' }
expected_json = { exists: false, suggests: [] }.to_json
expect(response.body).to eq(expected_json)
end
context 'when a user changed their username' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-username') }
it 'returns JSON indicating a user by that username does not exist' do
get :suggests, params: { username: 'old-username' }
expected_json = { exists: false, suggests: [] }.to_json
expect(response.body).to eq(expected_json)
end
end
end
end
describe '#ensure_canonical_path' do
before do
sign_in(user)
Loading
Loading
Loading
Loading
@@ -23,7 +23,7 @@ describe Gitlab::Ci::Config::Entry::Job do
 
let(:result) do
%i[before_script script stage type after_script cache
image services only except rules needs variables artifacts
image services only except rules variables artifacts
environment coverage retry]
end
 
Loading
Loading
@@ -384,6 +384,21 @@ describe Gitlab::Ci::Config::Entry::Job do
end
 
context 'when has needs' do
context 'that are not a array of strings' do
let(:config) do
{
stage: 'test',
script: 'echo',
needs: 'build-job'
}
end
it 'returns error about invalid type' do
expect(entry).not_to be_valid
expect(entry.errors).to include 'job needs should be an array of strings'
end
end
context 'when have dependencies that are not subset of needs' do
let(:config) do
{
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe ::Gitlab::Ci::Config::Entry::Need do
subject(:need) { described_class.new(config) }
context 'when job is specified' do
let(:config) { 'job_name' }
describe '#valid?' do
it { is_expected.to be_valid }
end
describe '#value' do
it 'returns job needs configuration' do
expect(need.value).to eq(name: 'job_name')
end
end
end
context 'when need is empty' do
let(:config) { '' }
describe '#valid?' do
it { is_expected.not_to be_valid }
end
describe '#errors' do
it 'is returns an error about an empty config' do
expect(need.errors)
.to contain_exactly("job config can't be blank")
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe ::Gitlab::Ci::Config::Entry::Needs do
subject(:needs) { described_class.new(config) }
before do
needs.metadata[:allowed_needs] = %i[job]
end
describe 'validations' do
before do
needs.compose!
end
context 'when entry config value is correct' do
let(:config) { ['job_name'] }
describe '#valid?' do
it { is_expected.to be_valid }
end
end
context 'when config value has wrong type' do
let(:config) { 123 }
describe '#valid?' do
it { is_expected.not_to be_valid }
end
describe '#errors' do
it 'returns error about incorrect type' do
expect(needs.errors)
.to include('needs config can only be a hash or an array')
end
end
end
context 'when wrong needs type is used' do
let(:config) { [123] }
describe '#valid?' do
it { is_expected.not_to be_valid }
end
describe '#errors' do
it 'returns error about incorrect type' do
expect(needs.errors).to contain_exactly(
'need has an unsupported type')
end
end
end
end
describe '.compose!' do
context 'when valid job entries composed' do
let(:config) { %w[first_job_name second_job_name] }
before do
needs.compose!
end
describe '#value' do
it 'returns key value' do
expect(needs.value).to eq(
job: [
{ name: 'first_job_name' },
{ name: 'second_job_name' }
]
)
end
end
describe '#descendants' do
it 'creates valid descendant nodes' do
expect(needs.descendants.count).to eq 2
expect(needs.descendants)
.to all(be_an_instance_of(::Gitlab::Ci::Config::Entry::Need))
end
end
end
end
end
Loading
Loading
@@ -1293,7 +1293,7 @@ module Gitlab
end
end
 
describe "Job Needs" do
describe "Needs" do
let(:needs) { }
let(:dependencies) { }
 
Loading
Loading
@@ -1333,7 +1333,12 @@ module Gitlab
stage: "test",
stage_idx: 2,
name: "test1",
options: { script: ["test"] },
options: {
script: ["test"],
# This does not make sense, there is a follow-up:
# https://gitlab.com/gitlab-org/gitlab-foss/issues/65569
bridge_needs: %w[build1 build2]
},
needs_attributes: [
{ name: "build1" },
{ name: "build2" }
Loading
Loading
@@ -1345,6 +1350,12 @@ module Gitlab
end
end
 
context 'needs two builds defined as symbols' do
let(:needs) { [:build1, :build2] }
it { expect { subject }.not_to raise_error }
end
context 'undefined need' do
let(:needs) { ['undefined'] }
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment