Commit 20308a92 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 1b0cdd5d 73756dad
......@@ -224,7 +224,7 @@ export default {
<a
ref="titleWrapper"
:v-once="!viewDiffsFileByFile"
class="gl-mr-2"
class="gl-mr-2 gl-text-decoration-none!"
:href="titleLink"
@click="handleFileNameClick"
>
......
......@@ -170,13 +170,13 @@ export default {
.map(({ variable_type, key, value }) => ({
variable_type,
key,
value,
secret_value: value,
}));
return axios
.post(this.pipelinesPath, {
ref: this.refValue,
variables: filteredVariables,
variables_attributes: filteredVariables,
})
.then(({ data }) => {
redirectTo(`${this.pipelinesPath}/${data.id}`);
......
<script>
import { GlIcon } from '@gitlab/ui';
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import '~/lib/utils/datetime_utility';
import tooltip from '~/vue_shared/directives/tooltip';
import timeagoMixin from '~/vue_shared/mixins/timeago';
export default {
directives: {
tooltip,
GlTooltip: GlTooltipDirective,
},
components: { GlIcon },
mixins: [timeagoMixin],
......@@ -63,7 +62,7 @@ export default {
<gl-icon name="calendar" class="gl-vertical-align-baseline!" aria-hidden="true" />
<time
v-tooltip
v-gl-tooltip
:title="tooltipTitle(finishedTime)"
data-placement="top"
data-container="body"
......
import LineHighlighter from '~/line_highlighter';
import BlobViewer from '~/blob/viewer';
import ZenMode from '~/zen_mode';
import initNotes from '~/init_notes';
import snippetEmbed from '~/snippet/snippet_embed';
import { SnippetShowInit } from '~/snippets';
import loadAwardsHandler from '~/awards_handler';
document.addEventListener('DOMContentLoaded', () => {
if (!gon.features.snippetsVue) {
new LineHighlighter(); // eslint-disable-line no-new
new BlobViewer(); // eslint-disable-line no-new
initNotes();
new ZenMode(); // eslint-disable-line no-new
snippetEmbed();
} else {
SnippetShowInit();
initNotes();
}
loadAwardsHandler();
});
if (!gon.features.snippetsVue) {
const LineHighlighterModule = import('~/line_highlighter');
const BlobViewerModule = import('~/blob/viewer');
const ZenModeModule = import('~/zen_mode');
const SnippetEmbedModule = import('~/snippet/snippet_embed');
Promise.all([LineHighlighterModule, BlobViewerModule, ZenModeModule, SnippetEmbedModule])
.then(
([
{ default: LineHighlighter },
{ default: BlobViewer },
{ default: ZenMode },
{ default: SnippetEmbed },
]) => {
new LineHighlighter(); // eslint-disable-line no-new
new BlobViewer(); // eslint-disable-line no-new
new ZenMode(); // eslint-disable-line no-new
SnippetEmbed();
},
)
.catch(() => {});
} else {
import('~/snippets')
.then(({ SnippetShowInit }) => {
SnippetShowInit();
})
.catch(() => {});
}
initNotes();
loadAwardsHandler();
......@@ -3,8 +3,6 @@ import VueApollo from 'vue-apollo';
import Translate from '~/vue_shared/translate';
import createDefaultClient from '~/lib/graphql';
import SnippetsShow from './components/show.vue';
import SnippetsEdit from './components/edit.vue';
import { SNIPPET_LEVELS_MAP, SNIPPET_VISIBILITY_PRIVATE } from '~/snippets/constants';
Vue.use(VueApollo);
......@@ -48,9 +46,17 @@ function appFactory(el, Component) {
}
export const SnippetShowInit = () => {
appFactory(document.getElementById('js-snippet-view'), SnippetsShow);
import('./components/show.vue')
.then(({ default: SnippetsShow }) => {
appFactory(document.getElementById('js-snippet-view'), SnippetsShow);
})
.catch(() => {});
};
export const SnippetEditInit = () => {
appFactory(document.getElementById('js-snippet-edit'), SnippetsEdit);
import('./components/edit.vue')
.then(({ default: SnippetsEdit }) => {
appFactory(document.getElementById('js-snippet-edit'), SnippetsEdit);
})
.catch(() => {});
};
......@@ -189,15 +189,6 @@
background-color: $gray-darker;
color: $gl-text-color;
outline: 0;
// make sure the text color is not overridden
&.text-danger {
color: $brand-danger;
}
.avatar {
border-color: $white;
}
}
@mixin dropdown-link {
......@@ -216,11 +207,6 @@
text-align: left;
width: 100%;
// make sure the text color is not overridden
&.text-danger {
color: $brand-danger;
}
&.disable-hover {
text-decoration: none;
}
......@@ -232,10 +218,6 @@
@include dropdown-item-hover;
text-decoration: none;
.badge.badge-pill {
background-color: darken($blue-50, 5%);
}
}
&.dropdown-menu-user-link {
......
......@@ -28,10 +28,6 @@
text-decoration: none;
color: $black;
border-bottom: 2px solid $gray-darkest;
.badge.badge-pill {
color: $black;
}
}
}
......
......@@ -439,10 +439,6 @@
content: '\f0c6';
}
&:hover::before {
text-decoration: none;
}
&.no-attachment-icon {
&::before {
display: none;
......
......@@ -29,11 +29,6 @@
.ref-name {
font-size: 12px;
&:hover {
text-decoration: underline;
color: $gl-text-color;
}
}
}
......
......@@ -70,10 +70,6 @@
}
}
a:hover {
text-decoration: none;
}
&:hover {
background-color: $gray-normal;
}
......
......@@ -80,7 +80,7 @@ module Mutations
raise Gitlab::Graphql::Errors::ArgumentError, ANNOTATION_SOURCE_ARGUMENT_ERROR
end
super(args)
super(**args)
end
def find_object(id:)
......
......@@ -1690,6 +1690,10 @@ class MergeRequest < ApplicationRecord
Feature.enabled?(:merge_request_reviewers, project)
end
def allows_multiple_reviewers?
false
end
private
def with_rebase_lock
......
......@@ -110,6 +110,10 @@ module MergeRequests
return
end
unless merge_request.allows_multiple_reviewers?
params[:reviewer_ids] = params[:reviewer_ids].first(1)
end
reviewer_ids = params[:reviewer_ids].select { |reviewer_id| user_can_read?(merge_request, reviewer_id) }
if params[:reviewer_ids].map(&:to_s) == [IssuableFinder::Params::NONE]
......
......@@ -21,12 +21,12 @@ if app.config.public_file_server.enabled
settings = {
enabled: true,
host: dev_server.host,
manifest_host: dev_server.host,
manifest_port: dev_server.port,
port: dev_server.port
}
if Rails.env.development?
# /assets are proxied through a Rails middlware to the Webpack
# server, so we have to use the local Rails settings.
settings.merge!(
host: Gitlab.config.gitlab.host,
port: Gitlab.config.gitlab.port,
......
......@@ -9,8 +9,6 @@ type: howto
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20912) in GitLab 12.6.
## Overview
GitLab administrators are responsible for the overall security of their instance. To assist, GitLab provides a Credentials inventory to keep track of all the credentials that can be used to access their self-managed instance.
Using Credentials inventory, you can see all the personal access tokens (PAT) and SSH keys that exist in your GitLab instance. In addition, you can [revoke them](#revoke-a-users-personal-access-token) and see:
......
......@@ -9,8 +9,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - Introduced in [GitLab Starter](https://about.gitlab.com/pricing/) 8.3.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3090) for subgroups in GitLab 12.2.
## Overview
With Contribution Analytics you can get an overview of the following activity in your
group:
......
......@@ -51,7 +51,7 @@ Furthermore, the bot user can not be added to any other project.
- The username is set to `project_{project_id}_bot` for the first access token, such as `project_123_bot`.
- The username is set to `project_{project_id}_bot{bot_count}` for further access tokens, such as `project_123_bot1`.
After the project access token is [revoked](#revoking-a-project-access-token), the bot user is removed from the project and blocked. All associated records are moved to a system-wide user named "Ghost User". For more information, see [Associated Records](../../profile/account/delete_account.md#associated-records).
When the project access token is [revoked](#revoking-a-project-access-token) the bot user is then deleted and all records are moved to a system-wide user with the username "Ghost User". For more information, see [Associated Records](../../profile/account/delete_account.md#associated-records).
Project bot users are a [GitLab-created service account](../../../subscriptions/self_managed/index.md#choose-the-number-of-users), but count as a licensed seat.
These users will not count against your licensed seat in the future when [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/223695) is resolved.
......
......@@ -8,6 +8,7 @@ class TrialsController < ApplicationController
before_action :check_if_gl_com_or_dev
before_action :authenticate_user!
before_action :find_or_create_namespace, only: :apply
before_action :record_user_for_group_only_trials_experiment, only: :select
def new
end
......@@ -97,4 +98,8 @@ class TrialsController < ApplicationController
group
end
def record_user_for_group_only_trials_experiment
record_experiment_user(:group_only_trials)
end
end
......@@ -66,6 +66,8 @@ module EE
end
def trial_user_namespaces
return [] if experiment_enabled?(:group_only_trials)
strong_memoize(:trial_user_namespaces) do
user_namespace = current_user.namespace
user_namespace.eligible_for_trial? ? [user_namespace] : []
......
......@@ -120,6 +120,10 @@ module EE
project.feature_available?(:multiple_merge_request_assignees)
end
def allows_multiple_reviewers?
project.feature_available?(:multiple_merge_request_reviewers)
end
def visible_blocking_merge_requests(user)
Ability.merge_requests_readable_by_user(blocking_merge_requests, user)
end
......
......@@ -29,6 +29,7 @@ class License < ApplicationRecord
multiple_issue_assignees
multiple_ldap_servers
multiple_merge_request_assignees
multiple_merge_request_reviewers
project_merge_request_analytics
protected_refs_for_users
push_rules
......
......@@ -16,7 +16,7 @@ module Geo
rescue Gitlab::Shell::Error, Gitlab::Git::BaseError => e
# In some cases repository does not exist, the only way to know about this is to parse the error text.
# If it does not exist we should consider it as successfully downloaded.
if e.message.include? Gitlab::GitAccess::ERROR_MESSAGES[:no_repo] # rubocop:disable Cop/LineBreakAroundConditionalBlock
if e.message.include? Gitlab::GitAccessDesign::ERROR_MESSAGES[:no_repo] # rubocop:disable Cop/LineBreakAroundConditionalBlock
log_info('Design repository is not found, marking it as successfully synced')
mark_sync_as_successful(missing_on_primary: true)
else
......
......@@ -16,7 +16,7 @@ module Geo
rescue Gitlab::Shell::Error, Gitlab::Git::BaseError, Wiki::CouldNotCreateWikiError => e
# In some cases repository does not exist, the only way to know about this is to parse the error text.
# If it does not exist we should consider it as successfully downloaded.
if e.message.include? Gitlab::GitAccess::ERROR_MESSAGES[:no_repo] # rubocop:disable Cop/LineBreakAroundConditionalBlock
if e.message.include? Gitlab::GitAccessWiki::ERROR_MESSAGES[:no_repo] # rubocop:disable Cop/LineBreakAroundConditionalBlock
if repository_presumably_exists_on_primary?
log_info('Wiki is not found, but it seems to exist on the primary')
fail_registry_sync!('Wiki is not found', e)
......
......@@ -3,5 +3,6 @@
- api_paths = @group.present? ? { milestones_path: group_milestones_path(@group), labels_path: group_labels_path(@group) } : {}
- image_paths = { empty_state_svg_path: image_path("illustrations/analytics/cycle-analytics-empty-chart.svg"), no_data_svg_path: image_path("illustrations/analytics/cycle-analytics-empty-chart.svg"), no_access_svg_path: image_path("illustrations/analytics/no-access.svg")}
- data_attributes.merge!(api_paths, image_paths)
- add_page_specific_style 'page_bundles/cycle_analytics'
#js-cycle-analytics-app{ data: data_attributes }
---
title: Geo - Fix wikis with no repository on the primary trying to sync over and over
merge_request: 43765
author:
type: fixed
---
name: gitlab_employee_badge
introduced_by_url:
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/212259
rollout_issue_url:
group:
group: group::access
type: development
default_enabled: false
......@@ -7,7 +7,7 @@ module Gitlab
def wrap_errors(**args)
yield
rescue Aws::Errors::ServiceError => e
raise Error, bucket: bucket_name, error: e, **args
raise Error.new(bucket: bucket_name, error: e, **args)
end
end
end
......
......@@ -120,13 +120,43 @@ RSpec.describe TrialsController do
end
describe '#select' do
subject do
def get_select
get :select
end
subject do
get_select
response
end
it_behaves_like 'an authenticated endpoint'
it_behaves_like 'a dot-com only feature'
context 'when the group-only trials experiment is active' do
before do
stub_experiment(group_only_trials: true)
stub_experiment_for_user(group_only_trials: user_is_in_experiment?)
end
def expected_group_type
user_is_in_experiment? ? 'experimental' : 'control'
end
where(user_is_in_experiment?: [true, false])
with_them do
it 'records the user as being part of the experiment' do
expect { get_select }.to change { ExperimentUser.count }.by(1)
expect(ExperimentUser.last.group_type).to eq(expected_group_type)
end
end
end
context 'when the group-only trials experiment is not active' do
it 'does not record the user as being part of the experiment' do
expect { get_select }.not_to change { ExperimentUser.count }
end
end
end
describe '#apply' do
......
......@@ -118,6 +118,24 @@ RSpec.describe MergeRequest do
end
end
describe '#allows_multiple_reviewers?' do
it 'returns false without license' do
stub_licensed_features(multiple_merge_request_reviewers: false)
merge_request = build_stubbed(:merge_request)
expect(merge_request.allows_multiple_reviewers?).to be(false)
end
it 'returns true when licensed' do
stub_licensed_features(multiple_merge_request_reviewers: true)
merge_request = build(:merge_request)
expect(merge_request.allows_multiple_reviewers?).to be(true)
end
end
describe '#participants' do
context 'with approval rule' do
before do
......
......@@ -111,7 +111,7 @@ RSpec.describe Geo::DesignRepositorySyncService do
allow(repository).to receive(:fetch_as_mirror)
.with(url_to_repo, remote_name: 'geo', forced: true)
.and_raise(Gitlab::Shell::Error.new(Gitlab::GitAccess::ERROR_MESSAGES[:no_repo]))
.and_raise(Gitlab::Shell::Error.new(Gitlab::GitAccessDesign::ERROR_MESSAGES[:no_repo]))
subject.execute
......
......@@ -85,7 +85,7 @@ RSpec.describe Geo::WikiSyncService, :geo do
allow(repository).to receive(:fetch_as_mirror)
.with(url_to_repo, remote_name: 'geo', forced: true)
.and_raise(Gitlab::Shell::Error.new(Gitlab::GitAccess::ERROR_MESSAGES[:no_repo]))
.and_raise(Gitlab::Shell::Error.new(Gitlab::GitAccessWiki::ERROR_MESSAGES[:no_repo]))
subject.execute
......@@ -115,7 +115,7 @@ RSpec.describe Geo::WikiSyncService, :geo do
allow(repository).to receive(:fetch_as_mirror)
.with(url_to_repo, remote_name: 'geo', forced: true)
.and_raise(Gitlab::Shell::Error.new(Gitlab::GitAccess::ERROR_MESSAGES[:no_repo]))
.and_raise(Gitlab::Shell::Error.new(Gitlab::GitAccessWiki::ERROR_MESSAGES[:no_repo]))
subject.execute
......
......@@ -57,11 +57,11 @@ module Gitlab
end
def duration
Time.current - @started
(Time.current - @started).ceil
end
def slot
return 0 if duration <= 1
return 0 if duration < 2
Math.log(duration, 2).floor - 1
end
......
......@@ -65,6 +65,9 @@ module Gitlab
},
invitation_reminders: {
tracking_category: 'Growth::Acquisition::Experiment::InvitationReminders'
},
group_only_trials: {
tracking_category: 'Growth::Conversion::Experiment::GroupOnlyTrials'
}
}.freeze
......
......@@ -46,7 +46,7 @@ module Gitlab
links&.each do |link|
next unless link.is_a? Hash
Gitlab::UrlBlocker.validate!(link[:url], blocker_args)
Gitlab::UrlBlocker.validate!(link[:url], **blocker_args)
rescue Gitlab::UrlBlocker::BlockedUrlError
link[:url] = ''
end
......
......@@ -88,10 +88,9 @@ module Gitlab
end
def load_dev_server_manifest
host = ::Rails.configuration.webpack.dev_server.host
port = ::Rails.configuration.webpack.dev_server.port
scheme = ::Rails.configuration.webpack.dev_server.https ? 'https' : 'http'
uri = Addressable::URI.new(scheme: scheme, host: host, port: port, path: dev_server_path)
host = ::Rails.configuration.webpack.dev_server.manifest_host
port = ::Rails.configuration.webpack.dev_server.manifest_port
uri = Addressable::URI.new(scheme: 'http', host: host, port: port, path: dev_server_path)
# localhost could be blocked via Gitlab::HTTP
response = HTTParty.get(uri.to_s, verify: false) # rubocop:disable Gitlab/HTTParty
......
......@@ -14,9 +14,9 @@ export const mockProjectId = '21';
export const mockPostParams = {
ref: 'tag-1',
variables: [
{ key: 'test_var', value: 'test_var_val', variable_type: 'env_var' },
{ key: 'test_file', value: 'test_file_val', variable_type: 'file' },
variables_attributes: [
{ key: 'test_var', secret_value: 'test_var_val', variable_type: 'env_var' },
{ key: 'test_file', secret_value: 'test_file_val', variable_type: 'file' },
],
};
......
......@@ -5,6 +5,7 @@ import initSnippet from '~/snippet/snippet_bundle';
jest.mock('~/snippet/snippet_bundle');
jest.mock('~/snippets');
jest.mock('~/gl_form');
describe('Snippet edit form initialization', () => {
const setFF = flag => {
......
......@@ -15,14 +15,36 @@ RSpec.describe Gitlab::Ci::Runner::Backoff do
end
end
end
it 'returns an integer value' do
freeze_time do
described_class.new(5.seconds.ago).then do |backoff|
expect(backoff.duration).to be 5
end
end
end
it 'returns the smallest number greater than or equal to duration' do
freeze_time do
described_class.new(0.5.seconds.ago).then do |backoff|
expect(backoff.duration).to be 1
end
end
end
end
describe '#slot' do
using RSpec::Parameterized::TableSyntax
where(:started, :slot) do
0 | 0
0.1 | 0
0.9 | 0
1 | 0
1.1 | 0
1.9 | 0
2 | 0
2.9 | 0
3 | 0
4 | 1
5 | 1
......@@ -30,6 +52,7 @@ RSpec.describe Gitlab::Ci::Runner::Backoff do
7 | 1
8 | 2
9 | 2
9.9 | 2
10 | 2
15 | 2
16 | 3
......@@ -59,15 +82,22 @@ RSpec.describe Gitlab::Ci::Runner::Backoff do
using RSpec::Parameterized::TableSyntax
where(:started, :backoff) do
0 | 1
0.1 | 1
0.9 | 1
1 | 1
1.1 | 1
1.9 | 1
2 | 1
3 | 1
4 | 2
5 | 2
6 | 2
6.5 | 2
7 | 2
8 | 4
9 | 4
9.9 | 4
10 | 4
15 | 4
16 | 8
......
......@@ -4,12 +4,12 @@ require 'spec_helper'
RSpec.describe Gitlab::Prometheus::QueryVariables do
describe '.call' do
let_it_be_with_refind(:environment) { create(:environment) }
let(:project) { environment.project }
let(:environment) { create(:environment) }
let(:slug) { environment.slug }
let(:params) { {} }
subject { described_class.call(environment, params) }
subject { described_class.call(environment, **params) }
it { is_expected.to include(ci_environment_slug: slug) }
it { is_expected.to include(ci_project_name: project.name) }
......
......@@ -41,7 +41,9 @@ RSpec.describe Gitlab::Webpack::Manifest do
before do
# Test that config variables work while we're here
::Rails.configuration.webpack.dev_server.host = 'hostname'
::Rails.configuration.webpack.dev_server.port = 2000
::Rails.configuration.webpack.dev_server.port = 1999
::Rails.configuration.webpack.dev_server.manifest_host = 'hostname'
::Rails.configuration.webpack.dev_server.manifest_port = 2000
::Rails.configuration.webpack.manifest_filename = "my_manifest.json"
::Rails.configuration.webpack.public_path = "public_path"
::Rails.configuration.webpack.output_dir = "manifest_output"
......
......@@ -34,6 +34,26 @@ RSpec.shared_examples 'reviewer_ids filter' do
it 'contains reviewers who can read the merge_request' do
expect(execute.reviewers).to contain_exactly(reviewer1, reviewer2)
end
context 'with multiple_merge_request_reviewers feature on' do
before do
stub_licensed_features(multiple_merge_request_reviewers: true)
end
it 'allows multiple reviewers' do
expect(execute.reviewers).to contain_exactly(reviewer1, reviewer2)
end
end
context 'with multiple_merge_request_reviewers feature off' do
before do
stub_licensed_features(multiple_merge_request_reviewers: false)
end
it 'only allows one reviewer' do
expect(execute.reviewers).to contain_exactly(reviewer1)
end
end
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment