Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-07-05 09:07:37 +00:00
parent 5fd38b5f78
commit cf98b5d69a
30 changed files with 194 additions and 100 deletions

View file

@ -2146,11 +2146,6 @@ Gitlab/NamespacedClass:
- 'spec/tasks/gitlab/task_helpers_spec.rb' - 'spec/tasks/gitlab/task_helpers_spec.rb'
- 'spec/uploaders/object_storage_spec.rb' - 'spec/uploaders/object_storage_spec.rb'
Style/ClassEqualityComparison:
Exclude:
- spec/lib/peek/views/active_record_spec.rb
- ee/spec/lib/peek/views/active_record_spec.rb
# WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/207950 # WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/207950
Cop/UserAdmin: Cop/UserAdmin:
Exclude: Exclude:

View file

@ -660,23 +660,6 @@ Style/BisectedAttrAccessor:
Style/CaseLikeIf: Style/CaseLikeIf:
Enabled: false Enabled: false
# Offense count: 10
# Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods.
# IgnoredMethods: ==, equal?, eql?
Style/ClassEqualityComparison:
Exclude:
- 'app/finders/security/jobs_finder.rb'
- 'app/services/projects/overwrite_project_service.rb'
- 'app/uploaders/dependency_proxy/file_uploader.rb'
- 'ee/app/graphql/resolvers/vulnerabilities/issue_links_resolver.rb'
- 'lib/gitlab/background_migration/user_mentions/models/note.rb'
- 'lib/gitlab/diff/file.rb'
- 'lib/gitlab/git.rb'
- 'lib/gitlab/import_export/relation_tree_restorer.rb'
- 'spec/requests/api/services_spec.rb'
- 'spec/support/shared_examples/lib/gitlab/import_export/relation_factory_shared_examples.rb'
# Offense count: 13 # Offense count: 13
Style/CombinableLoops: Style/CombinableLoops:
Exclude: Exclude:

View file

@ -305,11 +305,7 @@ gem 'sentry-raven', '~> 3.1'
# PostgreSQL query parsing # PostgreSQL query parsing
# #
# We need this fork until https://github.com/pganalyze/pg_query/pull/212 gem 'pg_query', '~> 2.1'
# and https://github.com/pganalyze/pg_query/pull/213 are
# released. gitlab-labkit will need to be updated to use the pg_query
# version.
gem 'gitlab-pg_query', '~> 2.0.4', require: 'pg_query'
gem 'premailer-rails', '~> 1.10.3' gem 'premailer-rails', '~> 1.10.3'

View file

@ -921,6 +921,8 @@ GEM
peek (1.1.0) peek (1.1.0)
railties (>= 4.0.0) railties (>= 4.0.0)
pg (1.2.3) pg (1.2.3)
pg_query (2.1.0)
google-protobuf (>= 3.17.1)
plist (3.6.0) plist (3.6.0)
png_quantizator (0.2.1) png_quantizator (0.2.1)
po_to_json (1.0.1) po_to_json (1.0.1)
@ -1495,7 +1497,6 @@ DEPENDENCIES
gitlab-markup (~> 1.7.1) gitlab-markup (~> 1.7.1)
gitlab-net-dns (~> 0.9.1) gitlab-net-dns (~> 0.9.1)
gitlab-omniauth-openid-connect (~> 0.4.0) gitlab-omniauth-openid-connect (~> 0.4.0)
gitlab-pg_query (~> 2.0.4)
gitlab-rdoc (~> 6.3.2) gitlab-rdoc (~> 6.3.2)
gitlab-sidekiq-fetcher (= 0.5.6) gitlab-sidekiq-fetcher (= 0.5.6)
gitlab-styles (~> 6.2.0) gitlab-styles (~> 6.2.0)
@ -1585,6 +1586,7 @@ DEPENDENCIES
parslet (~> 1.8) parslet (~> 1.8)
peek (~> 1.1) peek (~> 1.1)
pg (~> 1.1) pg (~> 1.1)
pg_query (~> 2.1)
png_quantizator (~> 0.2.1) png_quantizator (~> 0.2.1)
premailer-rails (~> 1.10.3) premailer-rails (~> 1.10.3)
prometheus-client-mmap (~> 0.12.0) prometheus-client-mmap (~> 0.12.0)

View file

@ -1,5 +1,6 @@
<script> <script>
import { GlAlert, GlButton } from '@gitlab/ui'; import { GlAlert, GlButton } from '@gitlab/ui';
import { mapState } from 'vuex';
import { CENTERED_LIMITED_CONTAINER_CLASSES, EVT_EXPAND_ALL_FILES } from '../constants'; import { CENTERED_LIMITED_CONTAINER_CLASSES, EVT_EXPAND_ALL_FILES } from '../constants';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
@ -27,11 +28,15 @@ export default {
}; };
}, },
computed: { computed: {
...mapState('diffs', ['diffFiles']),
containerClasses() { containerClasses() {
return { return {
[CENTERED_LIMITED_CONTAINER_CLASSES]: this.limited, [CENTERED_LIMITED_CONTAINER_CLASSES]: this.limited,
}; };
}, },
shouldDisplay() {
return !this.isDismissed && this.diffFiles.length > 1;
},
}, },
methods: { methods: {
@ -48,7 +53,7 @@ export default {
</script> </script>
<template> <template>
<div v-if="!isDismissed" data-testid="root" :class="containerClasses" class="col-12"> <div v-if="shouldDisplay" data-testid="root" :class="containerClasses" class="col-12">
<gl-alert <gl-alert
:dismissible="true" :dismissible="true"
:title="__('Some changes are not shown')" :title="__('Some changes are not shown')"

View file

@ -20,7 +20,7 @@ module Security
end end
def initialize(pipeline:, job_types: []) def initialize(pipeline:, job_types: [])
if self.class == Security::JobsFinder if self.instance_of?(Security::JobsFinder)
raise NotImplementedError, 'This is an abstract class, please instantiate its descendants' raise NotImplementedError, 'This is an abstract class, please instantiate its descendants'
end end

View file

@ -14,9 +14,7 @@ module BlobViewer
{}.tap do |h| {}.tap do |h|
h[:rendered] = blob.rendered_markup if blob.respond_to?(:rendered_markup) h[:rendered] = blob.rendered_markup if blob.respond_to?(:rendered_markup)
if Feature.enabled?(:cached_markdown_blob, blob.project, default_enabled: true) h[:cache_key] = ['blob', blob.id, 'commit', blob.commit_id]
h[:cache_key] = ['blob', blob.id, 'commit', blob.commit_id]
end
end end
end end
end end

View file

@ -20,7 +20,7 @@ module Projects
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException
attempt_restore_repositories(source_project) attempt_restore_repositories(source_project)
if e.class == Exception if e.instance_of?(Exception)
raise StandardError, e.message raise StandardError, e.message
else else
raise raise

View file

@ -5,6 +5,8 @@ module Releases
include BaseServiceUtility include BaseServiceUtility
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
ReleaseProtectedTagAccessError = Class.new(StandardError)
attr_accessor :project, :current_user, :params attr_accessor :project, :current_user, :params
def initialize(project, user = nil, params = {}) def initialize(project, user = nil, params = {})
@ -81,6 +83,15 @@ module Releases
release.execute_hooks(action) release.execute_hooks(action)
end end
def track_protected_tag_access_error!
unless ::Gitlab::UserAccess.new(current_user, container: project).can_create_tag?(tag_name)
Gitlab::ErrorTracking.log_exception(
ReleaseProtectedTagAccessError.new,
project_id: project.id,
user_id: current_user.id)
end
end
# overridden in EE # overridden in EE
def project_group_id; end def project_group_id; end
end end

View file

@ -7,6 +7,8 @@ module Releases
return error('Release already exists', 409) if release return error('Release already exists', 409) if release
return error("Milestone(s) not found: #{inexistent_milestones.join(', ')}", 400) if inexistent_milestones.any? return error("Milestone(s) not found: #{inexistent_milestones.join(', ')}", 400) if inexistent_milestones.any?
track_protected_tag_access_error!
# should be found before the creation of new tag # should be found before the creation of new tag
# because tag creation can spawn new pipeline # because tag creation can spawn new pipeline
# which won't have any data for evidence yet # which won't have any data for evidence yet

View file

@ -6,6 +6,8 @@ module Releases
return error('Release does not exist', 404) unless release return error('Release does not exist', 404) unless release
return error('Access Denied', 403) unless allowed? return error('Access Denied', 403) unless allowed?
track_protected_tag_access_error!
if release.destroy if release.destroy
success(tag: existing_tag, release: release) success(tag: existing_tag, release: release)
else else

View file

@ -7,6 +7,8 @@ module Releases
return error return error
end end
track_protected_tag_access_error!
if param_for_milestone_titles_provided? if param_for_milestone_titles_provided?
previous_milestones = release.milestones.map(&:title) previous_milestones = release.milestones.map(&:title)
params[:milestones] = milestones params[:milestones] = milestones

View file

@ -24,7 +24,7 @@ class DependencyProxy::FileUploader < GitlabUploader
# so we must store the custom content type in object storage. # so we must store the custom content type in object storage.
# This does not apply to DependencyProxy::Blob uploads. # This does not apply to DependencyProxy::Blob uploads.
def set_content_type(file) def set_content_type(file)
return unless model.class == DependencyProxy::Manifest return unless model.instance_of?(DependencyProxy::Manifest)
file.content_type = model.content_type file.content_type = model.content_type
end end

View file

@ -1,8 +1,8 @@
--- ---
name: cached_markdown_blob name: allow_archive_as_web_access_format
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44300 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64471
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/263406 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/334944
milestone: '13.5' milestone: '14.1'
type: development type: development
group: group::source code group: group::release
default_enabled: true default_enabled: false

View file

@ -71,6 +71,10 @@ to execute scripts. Each shell has its own set of reserved variable names.
Make sure each variable is defined for the [scope you want to use it in](where_variables_can_be_used.md). Make sure each variable is defined for the [scope you want to use it in](where_variables_can_be_used.md).
By default, pipelines from forked projects can't access CI/CD variables in the parent project.
If you [run a merge request pipeline in the parent project for a merge request from a fork](../pipelines/merge_request_pipelines.md#run-pipelines-in-the-parent-project-for-merge-requests-from-a-forked-project),
all variables become available to the pipeline.
### Create a custom CI/CD variable in the `.gitlab-ci.yml` file ### Create a custom CI/CD variable in the `.gitlab-ci.yml` file
To create a custom variable in the [`.gitlab-ci.yml`](../yaml/index.md#variables) file, To create a custom variable in the [`.gitlab-ci.yml`](../yaml/index.md#variables) file,
@ -303,6 +307,10 @@ The value of the variable must:
- The `~` character ([In GitLab 13.12](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61517) and later). - The `~` character ([In GitLab 13.12](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61517) and later).
- Not match the name of an existing predefined or custom CI/CD variable. - Not match the name of an existing predefined or custom CI/CD variable.
NOTE:
Masking a CI/CD variable is not a guaranteed way to prevent malicious users from accessing
variable values. To make variables more secure, you can [use external secrets](../secrets/index.md).
### Protect a CI/CD variable ### Protect a CI/CD variable
You can protect a project, group or instance CI/CD variable so it is only passed You can protect a project, group or instance CI/CD variable so it is only passed

View file

@ -499,7 +499,7 @@ Follow these guidelines for punctuation:
| Do not use tabs for indentation. Use spaces instead. You can configure your code editor to output spaces instead of tabs when pressing the tab key. | --- | | Do not use tabs for indentation. Use spaces instead. You can configure your code editor to output spaces instead of tabs when pressing the tab key. | --- |
| Use serial commas (_Oxford commas_) before the final _and_ or _or_ in a list of three or more items. (Tested in [`OxfordComma.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/OxfordComma.yml).) | _You can create new issues, merge requests, and milestones._ | | Use serial commas (_Oxford commas_) before the final _and_ or _or_ in a list of three or more items. (Tested in [`OxfordComma.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/OxfordComma.yml).) | _You can create new issues, merge requests, and milestones._ |
| Always add a space before and after dashes when using it in a sentence (for replacing a comma, for example). | _You should try this - or not._ | | Always add a space before and after dashes when using it in a sentence (for replacing a comma, for example). | _You should try this - or not._ |
| Always use lowercase after a colon. | Linked issues: a way to create a relationship between issues._ | | When a colon is part of a sentence, always use lowercase after the colon. | _Linked issues: a way to create a relationship between issues._ |
<!-- vale gitlab.Repetition = YES --> <!-- vale gitlab.Repetition = YES -->

View file

@ -89,9 +89,11 @@ module Gitlab
job.user job.user
end end
# We only allow Private Access Tokens with `api` scope to be used by web # We allow Private Access Tokens with `api` scope to be used by web
# requests on RSS feeds or ICS files for backwards compatibility. # requests on RSS feeds or ICS files for backwards compatibility.
# It is also used by GraphQL/API requests. # It is also used by GraphQL/API requests.
# And to allow accessing /archive programatically as it was a big pain point
# for users https://gitlab.com/gitlab-org/gitlab/-/issues/28978.
def find_user_from_web_access_token(request_format, scopes: [:api]) def find_user_from_web_access_token(request_format, scopes: [:api])
return unless access_token && valid_web_access_format?(request_format) return unless access_token && valid_web_access_format?(request_format)
@ -269,6 +271,8 @@ module Gitlab
ics_request? ics_request?
when :api when :api
api_request? api_request?
when :archive
archive_request? if Feature.enabled?(:allow_archive_as_web_access_format, default_enabled: :yaml)
end end
end end

View file

@ -21,7 +21,7 @@ module Gitlab
belongs_to :project, class_name: "::Gitlab::BackgroundMigration::UserMentions::Models::Project" belongs_to :project, class_name: "::Gitlab::BackgroundMigration::UserMentions::Models::Project"
def for_personal_snippet? def for_personal_snippet?
noteable && noteable.class.name == 'PersonalSnippet' noteable && noteable.instance_of?(PersonalSnippet)
end end
def for_project_noteable? def for_project_noteable?

View file

@ -449,7 +449,7 @@ module Gitlab
end end
def alternate_viewer_class def alternate_viewer_class
return unless viewer.class == DiffViewer::Renamed return unless viewer.instance_of?(DiffViewer::Renamed)
find_renderable_viewer_class(RICH_VIEWERS) || (DiffViewer::Text if text?) find_renderable_viewer_class(RICH_VIEWERS) || (DiffViewer::Text if text?)
end end

View file

@ -80,7 +80,7 @@ module Gitlab
def shas_eql?(sha1, sha2) def shas_eql?(sha1, sha2)
return true if sha1.nil? && sha2.nil? return true if sha1.nil? && sha2.nil?
return false if sha1.nil? || sha2.nil? return false if sha1.nil? || sha2.nil?
return false unless sha1.class == sha2.class return false unless sha1.instance_of?(sha2.class)
# If either of the shas is below the minimum length, we cannot be sure # If either of the shas is below the minimum length, we cannot be sure
# that they actually refer to the same commit because of hash collision. # that they actually refer to the same commit because of hash collision.

View file

@ -37,7 +37,7 @@ module Gitlab
ActiveRecord::Base.no_touching do ActiveRecord::Base.no_touching do
update_params! update_params!
BulkInsertableAssociations.with_bulk_insert(enabled: @importable.class == ::Project) do BulkInsertableAssociations.with_bulk_insert(enabled: @importable.instance_of?(::Project)) do
fix_ci_pipelines_not_sorted_on_legacy_project_json! fix_ci_pipelines_not_sorted_on_legacy_project_json!
create_relations! create_relations!
end end

View file

@ -1,10 +1,13 @@
import { shallowMount, mount, createLocalVue } from '@vue/test-utils'; import { shallowMount, mount, createLocalVue } from '@vue/test-utils';
import { nextTick } from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vue'; import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vue';
import { CENTERED_LIMITED_CONTAINER_CLASSES, EVT_EXPAND_ALL_FILES } from '~/diffs/constants'; import { CENTERED_LIMITED_CONTAINER_CLASSES, EVT_EXPAND_ALL_FILES } from '~/diffs/constants';
import eventHub from '~/diffs/event_hub'; import eventHub from '~/diffs/event_hub';
import createStore from '~/diffs/store/modules'; import createStore from '~/diffs/store/modules';
import file from '../mock_data/diff_file';
const propsData = { const propsData = {
limited: true, limited: true,
mergeable: true, mergeable: true,
@ -12,6 +15,13 @@ const propsData = {
}; };
const limitedClasses = CENTERED_LIMITED_CONTAINER_CLASSES.split(' '); const limitedClasses = CENTERED_LIMITED_CONTAINER_CLASSES.split(' ');
async function files(store, count) {
const copies = Array(count).fill(file);
store.state.diffs.diffFiles.push(...copies);
return nextTick();
}
describe('CollapsedFilesWarning', () => { describe('CollapsedFilesWarning', () => {
const localVue = createLocalVue(); const localVue = createLocalVue();
let store; let store;
@ -42,48 +52,63 @@ describe('CollapsedFilesWarning', () => {
wrapper.destroy(); wrapper.destroy();
}); });
it.each` describe('when there is more than one file', () => {
limited | containerClasses it.each`
${true} | ${limitedClasses} limited | containerClasses
${false} | ${[]} ${true} | ${limitedClasses}
`( ${false} | ${[]}
'has the correct container classes when limited is $limited', `(
({ limited, containerClasses }) => { 'has the correct container classes when limited is $limited',
createComponent({ limited }); async ({ limited, containerClasses }) => {
createComponent({ limited });
await files(store, 2);
expect(wrapper.classes()).toEqual(['col-12'].concat(containerClasses)); expect(wrapper.classes()).toEqual(['col-12'].concat(containerClasses));
}, },
); );
it.each` it.each`
present | dismissed present | dismissed
${false} | ${true} ${false} | ${true}
${true} | ${false} ${true} | ${false}
`('toggles the alert when dismissed is $dismissed', ({ present, dismissed }) => { `('toggles the alert when dismissed is $dismissed', async ({ present, dismissed }) => {
createComponent({ dismissed }); createComponent({ dismissed });
await files(store, 2);
expect(wrapper.find('[data-testid="root"]').exists()).toBe(present); expect(wrapper.find('[data-testid="root"]').exists()).toBe(present);
});
it('dismisses the component when the alert "x" is clicked', async () => {
createComponent({}, { full: true });
await files(store, 2);
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
getAlertCloseButton().element.click();
await wrapper.vm.$nextTick();
expect(wrapper.find('[data-testid="root"]').exists()).toBe(false);
});
it(`emits the \`${EVT_EXPAND_ALL_FILES}\` event when the alert action button is clicked`, async () => {
createComponent({}, { full: true });
await files(store, 2);
jest.spyOn(eventHub, '$emit');
getAlertActionButton().vm.$emit('click');
expect(eventHub.$emit).toHaveBeenCalledWith(EVT_EXPAND_ALL_FILES);
});
}); });
it('dismisses the component when the alert "x" is clicked', async () => { describe('when there is a single file', () => {
createComponent({}, { full: true }); it('should not display', async () => {
createComponent();
await files(store, 1);
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true); expect(wrapper.find('[data-testid="root"]').exists()).toBe(false);
});
getAlertCloseButton().element.click();
await wrapper.vm.$nextTick();
expect(wrapper.find('[data-testid="root"]').exists()).toBe(false);
});
it(`emits the \`${EVT_EXPAND_ALL_FILES}\` event when the alert action button is clicked`, () => {
createComponent({}, { full: true });
jest.spyOn(eventHub, '$emit');
getAlertActionButton().vm.$emit('click');
expect(eventHub.$emit).toHaveBeenCalledWith(EVT_EXPAND_ALL_FILES);
}); });
}); });

View file

@ -460,7 +460,7 @@ RSpec.describe Gitlab::Auth::AuthFinders do
expect { find_user_from_access_token }.to raise_error(Gitlab::Auth::UnauthorizedError) expect { find_user_from_access_token }.to raise_error(Gitlab::Auth::UnauthorizedError)
end end
context 'no feed or API requests' do context 'no feed, API or archive requests' do
it 'returns nil if the request is not RSS' do it 'returns nil if the request is not RSS' do
expect(find_user_from_web_access_token(:rss)).to be_nil expect(find_user_from_web_access_token(:rss)).to be_nil
end end
@ -472,6 +472,10 @@ RSpec.describe Gitlab::Auth::AuthFinders do
it 'returns nil if the request is not API' do it 'returns nil if the request is not API' do
expect(find_user_from_web_access_token(:api)).to be_nil expect(find_user_from_web_access_token(:api)).to be_nil
end end
it 'returns nil if the request is not ARCHIVE' do
expect(find_user_from_web_access_token(:archive)).to be_nil
end
end end
it 'returns the user for RSS requests' do it 'returns the user for RSS requests' do
@ -486,6 +490,24 @@ RSpec.describe Gitlab::Auth::AuthFinders do
expect(find_user_from_web_access_token(:ics)).to eq(user) expect(find_user_from_web_access_token(:ics)).to eq(user)
end end
it 'returns the user for ARCHIVE requests' do
set_header('SCRIPT_NAME', '/-/archive/main.zip')
expect(find_user_from_web_access_token(:archive)).to eq(user)
end
context 'when allow_archive_as_web_access_format feature flag is disabled' do
before do
stub_feature_flags(allow_archive_as_web_access_format: false)
end
it 'returns nil for ARCHIVE requests' do
set_header('SCRIPT_NAME', '/-/archive/main.zip')
expect(find_user_from_web_access_token(:archive)).to be_nil
end
end
context 'for API requests' do context 'for API requests' do
it 'returns the user' do it 'returns the user' do
set_header('SCRIPT_NAME', '/api/endpoint') set_header('SCRIPT_NAME', '/api/endpoint')

View file

@ -24,15 +24,5 @@ RSpec.describe BlobViewer::Markup do
expect(subject.banzai_render_context.keys).to include(:rendered) expect(subject.banzai_render_context.keys).to include(:rendered)
end end
end end
context 'when cached_markdown_blob feature flag is disabled' do
before do
stub_feature_flags(cached_markdown_blob: false)
end
it 'does not set cache_key key' do
expect(subject.banzai_render_context.keys).not_to include(:cache_key)
end
end
end end
end end

View file

@ -76,7 +76,7 @@ RSpec.describe API::Services do
required_attributes = service_attrs_list.select do |attr| required_attributes = service_attrs_list.select do |attr|
service_klass.validators_on(attr).any? do |v| service_klass.validators_on(attr).any? do |v|
v.class == ActiveRecord::Validations::PresenceValidator && v.instance_of?(ActiveRecord::Validations::PresenceValidator) &&
# exclude presence validators with conditional since those are not really required # exclude presence validators with conditional since those are not really required
![:if, :unless].any? { |cond| v.options.include?(cond) } ![:if, :unless].any? { |cond| v.options.include?(cond) }
end end

View file

@ -44,6 +44,21 @@ RSpec.describe Releases::CreateService do
it_behaves_like 'a successful release creation' it_behaves_like 'a successful release creation'
context 'when tag is protected and user does not have access to it' do
let!(:protected_tag) { create(:protected_tag, :no_one_can_create, name: '*', project: project) }
it 'track the error event' do
stub_feature_flags(evalute_protected_tag_for_release_permissions: false)
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
kind_of(described_class::ReleaseProtectedTagAccessError),
project_id: project.id,
user_id: user.id)
service.execute
end
end
context 'when the tag does not exist' do context 'when the tag does not exist' do
let(:tag_name) { 'non-exist-tag' } let(:tag_name) { 'non-exist-tag' }

View file

@ -28,6 +28,21 @@ RSpec.describe Releases::DestroyService do
it 'returns the destroyed object' do it 'returns the destroyed object' do
is_expected.to include(status: :success, release: release) is_expected.to include(status: :success, release: release)
end end
context 'when tag is protected and user does not have access to it' do
let!(:protected_tag) { create(:protected_tag, :no_one_can_create, name: '*', project: project) }
it 'track the error event' do
stub_feature_flags(evalute_protected_tag_for_release_permissions: false)
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
kind_of(described_class::ReleaseProtectedTagAccessError),
project_id: project.id,
user_id: user.id)
service.execute
end
end
end end
context 'when tag does not exist in the repository' do context 'when tag does not exist in the repository' do

View file

@ -38,6 +38,21 @@ RSpec.describe Releases::UpdateService do
service.execute service.execute
end end
context 'when tag is protected and user does not have access to it' do
let!(:protected_tag) { create(:protected_tag, :no_one_can_create, name: '*', project: project) }
it 'track the error event' do
stub_feature_flags(evalute_protected_tag_for_release_permissions: false)
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
kind_of(described_class::ReleaseProtectedTagAccessError),
project_id: project.id,
user_id: user.id)
service.execute
end
end
context 'when the tag does not exists' do context 'when the tag does not exists' do
let(:tag_name) { 'foobar' } let(:tag_name) { 'foobar' }

View file

@ -12,9 +12,7 @@ module CycleAnalyticsHelpers
page.all('.gl-path-button').collect(&:text).map {|name_with_median| name_with_median.split("\n")[0] } page.all('.gl-path-button').collect(&:text).map {|name_with_median| name_with_median.split("\n")[0] }
end end
def add_custom_stage_to_form def fill_in_custom_stage_fields
page.find_button(s_('CreateValueStreamForm|Add another stage')).click
index = page.all('[data-testid="value-stream-stage-fields"]').length index = page.all('[data-testid="value-stream-stage-fields"]').length
last_stage = page.all('[data-testid="value-stream-stage-fields"]').last last_stage = page.all('[data-testid="value-stream-stage-fields"]').last
@ -25,6 +23,12 @@ module CycleAnalyticsHelpers
end end
end end
def add_custom_stage_to_form
page.find_button(s_('CreateValueStreamForm|Add another stage')).click
fill_in_custom_stage_fields
end
def save_value_stream(custom_value_stream_name) def save_value_stream(custom_value_stream_name)
fill_in 'create-value-stream-name', with: custom_value_stream_name fill_in 'create-value-stream-name', with: custom_value_stream_name

View file

@ -12,7 +12,7 @@ RSpec.shared_examples 'Notes user references' do
'id' => 111, 'id' => 111,
'access_level' => 30, 'access_level' => 30,
'source_id' => 1, 'source_id' => 1,
'source_type' => importable.class.name == 'Project' ? 'Project' : 'Namespace', 'source_type' => importable.instance_of?(Project) ? 'Project' : 'Namespace',
'user_id' => 3, 'user_id' => 3,
'notification_level' => 3, 'notification_level' => 3,
'created_at' => '2016-11-18T09:29:42.634Z', 'created_at' => '2016-11-18T09:29:42.634Z',