Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-08-11 12:09:19 +00:00
parent 34facbbce9
commit 30f9120ba6
37 changed files with 408 additions and 66 deletions

View File

@ -1,5 +1,4 @@
#import "ee_else_ce/runner/graphql/list/list_item.fragment.graphql"
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
#import "~/runner/graphql/list/all_runners_connection.fragment.graphql"
query getAllRunners(
$before: String
@ -25,13 +24,6 @@ query getAllRunners(
search: $search
sort: $sort
) {
nodes {
...ListItem
adminUrl
editAdminUrl
}
pageInfo {
...PageInfo
}
...AllRunnersConnection
}
}

View File

@ -0,0 +1,13 @@
#import "ee_else_ce/runner/graphql/list/list_item.fragment.graphql"
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
fragment AllRunnersConnection on CiRunnerConnection {
nodes {
...ListItem
adminUrl
editAdminUrl
}
pageInfo {
...PageInfo
}
}

View File

@ -5,7 +5,6 @@ class AutocompleteController < ApplicationController
skip_before_action :authenticate_user!, only: [:users, :award_emojis, :merge_request_target_branches]
before_action :check_search_rate_limit!, only: [:users, :projects]
before_action :authorize_admin_project, only: :deploy_keys_with_owners
feature_category :users, [:users, :user]
feature_category :projects, [:projects]
@ -61,7 +60,9 @@ class AutocompleteController < ApplicationController
end
def deploy_keys_with_owners
deploy_keys = DeployKey.with_write_access_for_project(project)
deploy_keys = Autocomplete::DeployKeysWithWriteAccessFinder
.new(current_user, project)
.execute
render json: DeployKeys::BasicDeployKeySerializer.new.represent(
deploy_keys, { with_owner: true, user: current_user }
@ -70,10 +71,6 @@ class AutocompleteController < ApplicationController
private
def authorize_admin_project
render_403 unless Ability.allowed?(current_user, :admin_project, project)
end
def project
@project ||= Autocomplete::ProjectFinder
.new(current_user, params)

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
module Groups
class GroupTransferedEvent < ::Gitlab::EventStore::Event
def schema
{
'type' => 'object',
'properties' => {
'group_id' => { 'type' => 'integer' },
'old_root_namespace_id' => { 'type' => 'integer' },
'new_root_namespace_id' => { 'type' => 'integer' }
},
'required' => %w[group_id old_root_namespace_id new_root_namespace_id]
}
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
module Autocomplete
# Finder for retrieving deploy keys to use for autocomplete data sources.
class DeployKeysWithWriteAccessFinder
attr_reader :current_user, :project
def initialize(current_user, project)
@current_user = current_user
@project = project
end
def execute
return DeployKey.none if project.nil?
raise Gitlab::Access::AccessDeniedError unless current_user.can?(:admin_project, project)
project.deploy_keys.merge(DeployKeysProject.with_write_access)
end
end
end

View File

@ -37,12 +37,12 @@ module StorageHelper
"about how to reduce your storage.")).html_safe % text_args[:p2]
else
html_escape_once(s_("UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. " \
"View and manage your usage from %{strong_start}Group settings &gt; Usage quotas%{strong_end}. %{docs_link_start}Learn more%{link_end} " \
"about how to reduce your storage.")).html_safe % text_args[:p2]
"Group owners can view namespace storage usage and purchase more from %{strong_start}Group settings &gt; Usage quotas%{strong_end}. %{docs_link_start}Learn more.%{link_end}" \
)).html_safe % text_args[:p2]
end
{
text_paragraph_1: html_escape_once(s_("UsageQuota|Effective %{storage_enforcement_date}, %{announcement_link_start}namespace storage limits will apply%{link_end} " \
text_paragraph_1: html_escape_once(s_("UsageQuota|Effective %{storage_enforcement_date}, namespace storage limits will apply " \
"to the %{strong_start}%{namespace_name}%{strong_end} namespace. %{extra_message}" \
"View the %{rollout_link_start}rollout schedule for this change%{link_end}.")).html_safe % text_args[:p1],
text_paragraph_2: text_paragraph_2,
@ -92,8 +92,7 @@ module StorageHelper
storage_enforcement_date: root_ancestor.storage_enforcement_date,
namespace_name: root_ancestor.name,
extra_message: extra_message,
announcement_link_start: '<a href="%{url}" >'.html_safe % { url: "#{Gitlab::Saas.community_forum_url}/t/gitlab-introduces-storage-and-transfer-limits-for-users-on-saas/69883" },
rollout_link_start: '<a href="%{url}" >'.html_safe % { url: help_page_path('user/usage_quotas', anchor: 'tbd') },
rollout_link_start: '<a href="%{url}" >'.html_safe % { url: help_page_path('user/usage_quotas', anchor: 'namespace-storage-limit-enforcement-schedule') },
link_end: "</a>".html_safe
}.merge(strong_tags),
p2: {
@ -102,7 +101,7 @@ module StorageHelper
link_end: "</a>".html_safe
}.merge(strong_tags),
p3: {
faq_link_start: '<a href="%{url}" >'.html_safe % { url: "#{Gitlab::Saas.about_pricing_url}faq-efficient-free-tier/#storage-and-transfer-limits-on-gitlab-saas-free-tier" },
faq_link_start: '<a href="%{url}" >'.html_safe % { url: "#{Gitlab::Saas.about_pricing_url}faq-efficient-free-tier/#storage-limits-on-gitlab-saas-free-tier" },
link_end: "</a>".html_safe
}
}

View File

@ -99,6 +99,7 @@ class Issue < ApplicationRecord
validates :project, presence: true
validates :issue_type, presence: true
validates :namespace, presence: true, if: -> { project.present? }
validates :work_item_type, presence: true
validate :due_date_after_start_date
validate :parent_link_confidentiality
@ -204,7 +205,7 @@ class Issue < ApplicationRecord
scope :with_null_relative_position, -> { where(relative_position: nil) }
scope :with_non_null_relative_position, -> { where.not(relative_position: nil) }
before_validation :ensure_namespace_id
before_validation :ensure_namespace_id, :ensure_work_item_type
after_commit :expire_etag_cache, unless: :importing?
after_save :ensure_metrics, unless: :importing?
@ -732,6 +733,12 @@ class Issue < ApplicationRecord
def ensure_namespace_id
self.namespace = project.project_namespace if project
end
def ensure_work_item_type
return if work_item_type_id.present? || work_item_type_id_change&.last.present?
self.work_item_type = WorkItems::Type.default_by_type(issue_type)
end
end
Issue.prepend_mod_with('Issue')

View File

@ -59,6 +59,7 @@ class Member < ApplicationRecord
},
if: :project_bot?
validate :access_level_inclusion
validate :validate_member_role_access_level
scope :with_invited_user_state, -> do
joins('LEFT JOIN users as invited_user ON invited_user.email = members.invite_email')
@ -429,6 +430,14 @@ class Member < ApplicationRecord
errors.add(:access_level, "is not included in the list")
end
def validate_member_role_access_level
return unless member_role_id
if access_level != member_role.base_access_level
errors.add(:member_role_id, _("role's base access level does not match the access level of the membership"))
end
end
def send_invite
# override in subclass
end

View File

@ -669,6 +669,7 @@ class Project < ApplicationRecord
scope :imported_from, -> (type) { where(import_type: type) }
scope :imported, -> { where.not(import_type: nil) }
scope :with_enabled_error_tracking, -> { joins(:error_tracking_setting).where(project_error_tracking_settings: { enabled: true }) }
scope :last_activity_before, -> (time) { where('projects.last_activity_at < ?', time) }
scope :with_service_desk_key, -> (key) do
# project_key is not indexed for now

View File

@ -36,7 +36,7 @@ module Groups
update_crm_objects(was_root_group)
end
post_update_hooks(@updated_project_ids)
post_update_hooks(@updated_project_ids, old_root_ancestor_id)
propagate_integrations
update_pending_builds
@ -44,9 +44,10 @@ module Groups
end
# Overridden in EE
def post_update_hooks(updated_project_ids)
def post_update_hooks(updated_project_ids, old_root_ancestor_id)
refresh_project_authorizations
refresh_descendant_groups if @new_parent_group
publish_event(old_root_ancestor_id)
end
def ensure_allowed_transfer
@ -266,6 +267,18 @@ module Groups
CustomerRelations::IssueContact.delete_for_group(@group)
end
def publish_event(old_root_ancestor_id)
event = ::Groups::GroupTransferedEvent.new(
data: {
group_id: group.id,
old_root_namespace_id: old_root_ancestor_id,
new_root_namespace_id: group.root_ancestor.id
}
)
Gitlab::EventStore.publish(event)
end
end
end

View File

@ -0,0 +1,8 @@
---
name: authenticate_markdown_api
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93727
rollout_issue_url:
milestone: '15.3'
type: ops
group: group::project management
default_enabled: true

View File

@ -779,6 +779,11 @@ Gitlab.ee do
Settings.cron_jobs['licenses_reset_submit_license_usage_data_banner'] ||= Settingslogic.new({})
Settings.cron_jobs['licenses_reset_submit_license_usage_data_banner']['cron'] ||= "0 0 * * *"
Settings.cron_jobs['licenses_reset_submit_license_usage_data_banner']['job_class'] = 'Licenses::ResetSubmitLicenseUsageDataBannerWorker'
Gitlab.com do
Settings.cron_jobs['disable_legacy_open_source_license_for_inactive_projects'] ||= Settingslogic.new({})
Settings.cron_jobs['disable_legacy_open_source_license_for_inactive_projects']['cron'] ||= "30 5 * * 0"
Settings.cron_jobs['disable_legacy_open_source_license_for_inactive_projects']['job_class'] = 'Projects::DisableLegacyOpenSourceLicenseForInactiveProjectsWorker'
end
end
#

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
class AddPartialLegacyOpenSourceLicenseAvailableIndex < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
INDEX_NAME = 'index_project_settings_on_legacy_open_source_license_available'
def up
add_concurrent_index :project_settings,
%i[legacy_open_source_license_available],
where: "legacy_open_source_license_available = TRUE",
name: INDEX_NAME
end
def down
remove_concurrent_index_by_name(:project_settings, INDEX_NAME)
end
end

View File

@ -0,0 +1 @@
0e8b193943aa02c8b700c06110725fd643378cf79715d1398238abc407639c67

View File

@ -29484,6 +29484,8 @@ CREATE UNIQUE INDEX index_project_repository_states_on_project_id ON project_rep
CREATE INDEX index_project_repository_storage_moves_on_project_id ON project_repository_storage_moves USING btree (project_id);
CREATE INDEX index_project_settings_on_legacy_open_source_license_available ON project_settings USING btree (legacy_open_source_license_available) WHERE (legacy_open_source_license_available = true);
CREATE INDEX index_project_settings_on_project_id_partially ON project_settings USING btree (project_id) WHERE (has_vulnerabilities IS TRUE);
CREATE UNIQUE INDEX index_project_settings_on_push_rule_id ON project_settings USING btree (push_rule_id);

View File

@ -1,6 +1,6 @@
---
stage: Data Stores
group: Memory
group: Application Performance
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Data Stores
group: Memory
group: Application Performance
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Data Stores
group: Memory
group: Application Performance
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Data Stores
group: Memory
group: Application Performance
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,13 +1,27 @@
---
stage: Create
group: Source Code
stage: Plan
group: Project Management
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Markdown API **(FREE)**
Convert Markdown content to HTML.
Available only in APIv4.
## Required authentication
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93727) in GitLab 15.3 [with a flag](../administration/feature_flags.md) named `authenticate_markdown_api`. Enabled by default.
FLAG:
On self-managed GitLab, by default this feature is enabled and authentication is required.
To remove the requirement to authenticate, ask an administrator to
[disable the feature flag](../administration/feature_flags.md) named `authenticate_markdown_api`.
On GitLab.com, this feature is available.
All API calls to the Markdown API must be [authenticated](index.md#authentication).
## Render an arbitrary Markdown document
```plaintext
@ -18,10 +32,12 @@ POST /markdown
| --------- | ------- | ------------- | ------------------------------------------ |
| `text` | string | yes | The Markdown text to render |
| `gfm` | boolean | no | Render text using GitLab Flavored Markdown. Default is `false` |
| `project` | string | no | Use `project` as a context when creating references using GitLab Flavored Markdown. [Authentication](index.md#authentication) is required if a project is not public. |
| `project` | string | no | Use `project` as a context when creating references using GitLab Flavored Markdown |
```shell
curl --header Content-Type:application/json --data '{"text":"Hello world! :tada:", "gfm":true, "project":"group_example/project_example"}' "https://gitlab.example.com/api/v4/markdown"
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
--header "Content-Type:application/json" \
--data '{"text":"Hello world! :tada:", "gfm":true, "project":"group_example/project_example"}' "https://gitlab.example.com/api/v4/markdown"
```
Response example:

View File

@ -1,6 +1,6 @@
---
stage: Data Stores
group: Memory
group: Application Performance
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Data Stores
group: Memory
group: Application Performance
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -341,6 +341,7 @@ Support includes:
- Creating and editing the structure of tables.
- Inserting and formatting code blocks with syntax highlighting.
- Live preview of Mermaid, PlantUML, and Kroki diagrams ([Introduced]<https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86701> in GitLab 15.2).
- Real-time visualization of table of contents.
### Use the Content Editor

View File

@ -2,7 +2,9 @@
module API
class Markdown < ::API::Base
feature_category :not_owned # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned
before { authenticate! if Feature.enabled?(:authenticate_markdown_api, type: :ops) }
feature_category :team_planning
params do
requires :text, type: String, desc: "The markdown text to render"

View File

@ -41934,7 +41934,7 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
msgid "UsageQuota|Effective %{storage_enforcement_date}, %{announcement_link_start}namespace storage limits will apply%{link_end} to the %{strong_start}%{namespace_name}%{strong_end} namespace. %{extra_message}View the %{rollout_link_start}rollout schedule for this change%{link_end}."
msgid "UsageQuota|Effective %{storage_enforcement_date}, namespace storage limits will apply to the %{strong_start}%{namespace_name}%{strong_end} namespace. %{extra_message}View the %{rollout_link_start}rollout schedule for this change%{link_end}."
msgstr ""
msgid "UsageQuota|File attachments and smaller design graphics."
@ -42045,7 +42045,7 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}Group settings &gt; Usage quotas%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}Group settings &gt; Usage quotas%{strong_end}. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}User settings &gt; Usage quotas%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
@ -47170,6 +47170,9 @@ msgstr ""
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
msgid "satisfied"
msgstr ""

View File

@ -0,0 +1,8 @@
# frozen_string_literal: true
FactoryBot.define do
factory :member_role do
namespace { association(:group) }
base_access_level { Gitlab::Access::DEVELOPER }
end
end

View File

@ -0,0 +1,53 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Autocomplete::DeployKeysWithWriteAccessFinder do
let_it_be(:user) { create(:user) }
let(:finder) { described_class.new(user, project) }
describe '#execute' do
subject(:execute) { finder.execute }
context 'when project is missing' do
let(:project) { nil }
it 'returns an empty ActiveRecord::Relation' do
expect(execute).to eq(DeployKey.none)
end
end
context 'when project is present' do
let_it_be(:project) { create(:project, :public) }
context 'and current user cannot admin project' do
it 'raises Gitlab::Access::AccessDeniedError' do
expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
context 'and current user can admin project' do
before do
project.add_maintainer(user)
end
context 'when deploy key does not have write access to project' do
let(:deploy_key_project) { create(:deploy_keys_project, project: project) }
it 'returns an empty ActiveRecord::Relation' do
expect(execute).to eq(DeployKey.none)
end
end
context 'when deploy key has write access to project' do
let(:deploy_key_project) { create(:deploy_keys_project, :write_access, project: project) }
it 'returns the deploy keys' do
expect(execute).to match_array([deploy_key_project.deploy_key])
end
end
end
end
end
end

View File

@ -351,7 +351,7 @@ describe('Design discussions component', () => {
createComponent();
findReplyPlaceholder().vm.$emit('focus');
expect(wrapper.emitted('open-form')).toBeTruthy();
expect(wrapper.emitted('open-form')).toHaveLength(1);
});
describe('when user is not logged in', () => {

View File

@ -239,7 +239,7 @@ describe('DiffRow', () => {
const coverage = wrapper.find('.line-coverage.right-side');
expect(coverage.attributes('title')).toContain('Test coverage: 5 hits');
expect(coverage.classes('coverage')).toBeTruthy();
expect(coverage.classes('coverage')).toBe(true);
});
it('for lines without coverage', () => {
@ -248,7 +248,7 @@ describe('DiffRow', () => {
const coverage = wrapper.find('.line-coverage.right-side');
expect(coverage.attributes('title')).toContain('No test coverage');
expect(coverage.classes('no-coverage')).toBeTruthy();
expect(coverage.classes('no-coverage')).toBe(true);
});
it('for unknown lines', () => {
@ -256,9 +256,9 @@ describe('DiffRow', () => {
wrapper = createWrapper({ props, state: { coverageFiles } });
const coverage = wrapper.find('.line-coverage.right-side');
expect(coverage.attributes('title')).toBeFalsy();
expect(coverage.classes('coverage')).toBeFalsy();
expect(coverage.classes('no-coverage')).toBeFalsy();
expect(coverage.attributes('title')).toBeUndefined();
expect(coverage.classes('coverage')).toBe(false);
expect(coverage.classes('no-coverage')).toBe(false);
});
});

View File

@ -100,9 +100,9 @@ RSpec.describe StorageHelper do
used_storage = helper.storage_counter(free_group.root_storage_statistics&.storage_size || 0)
expect(helper.storage_enforcement_banner_info(free_group)).to eql({
text_paragraph_1: "Effective #{storage_enforcement_date}, <a href=\"https://forum.gitlab.com/t/gitlab-introduces-storage-and-transfer-limits-for-users-on-saas/69883\" >namespace storage limits will apply</a> to the <strong>#{free_group.name}</strong> namespace. View the <a href=\"/help/user/usage_quotas#tbd\" >rollout schedule for this change</a>.",
text_paragraph_2: "The namespace is currently using <strong>#{used_storage}</strong> of namespace storage. View and manage your usage from <strong>Group settings &gt; Usage quotas</strong>. <a href=\"/help/user/usage_quotas#manage-your-storage-usage\" >Learn more</a> about how to reduce your storage.",
text_paragraph_3: "See our <a href=\"https://about.gitlab.com/pricing/faq-efficient-free-tier/#storage-and-transfer-limits-on-gitlab-saas-free-tier\" >FAQ</a> for more information.",
text_paragraph_1: "Effective #{storage_enforcement_date}, namespace storage limits will apply to the <strong>#{free_group.name}</strong> namespace. View the <a href=\"/help/user/usage_quotas#namespace-storage-limit-enforcement-schedule\" >rollout schedule for this change</a>.",
text_paragraph_2: "The namespace is currently using <strong>#{used_storage}</strong> of namespace storage. Group owners can view namespace storage usage and purchase more from <strong>Group settings &gt; Usage quotas</strong>. <a href=\"/help/user/usage_quotas#manage-your-storage-usage\" >Learn more.</a>",
text_paragraph_3: "See our <a href=\"https://about.gitlab.com/pricing/faq-efficient-free-tier/#storage-limits-on-gitlab-saas-free-tier\" >FAQ</a> for more information.",
variant: 'warning',
namespace_id: free_group.id,
callouts_feature_name: 'storage_enforcement_banner_second_enforcement_threshold',
@ -116,7 +116,7 @@ RSpec.describe StorageHelper do
end
it 'returns a hash with the correct storage size text' do
expect(helper.storage_enforcement_banner_info(free_group)[:text_paragraph_2]).to eql("The namespace is currently using <strong>100 KB</strong> of namespace storage. View and manage your usage from <strong>Group settings &gt; Usage quotas</strong>. <a href=\"/help/user/usage_quotas#manage-your-storage-usage\" >Learn more</a> about how to reduce your storage.")
expect(helper.storage_enforcement_banner_info(free_group)[:text_paragraph_2]).to eql("The namespace is currently using <strong>100 KB</strong> of namespace storage. Group owners can view namespace storage usage and purchase more from <strong>Group settings &gt; Usage quotas</strong>. <a href=\"/help/user/usage_quotas#manage-your-storage-usage\" >Learn more.</a>")
end
end
@ -141,7 +141,8 @@ RSpec.describe StorageHelper do
end
it 'returns the enforcement info' do
expect(helper.storage_enforcement_banner_info(free_group)[:text_paragraph_1]).to include("Effective #{Date.current}, <a href=\"https://forum.gitlab.com/t/gitlab-introduces-storage-and-transfer-limits-for-users-on-saas/69883\" >namespace storage limits will apply</a>")
puts helper.storage_enforcement_banner_info(free_group)[:text_paragraph_1]
expect(helper.storage_enforcement_banner_info(free_group)[:text_paragraph_1]).to include("Effective #{Date.current}, namespace storage limits will apply")
end
end

View File

@ -222,6 +222,61 @@ RSpec.describe Issue do
end
end
describe '#ensure_work_item_type' do
let_it_be(:issue_type) { create(:work_item_type, :issue, :default) }
let_it_be(:task_type) { create(:work_item_type, :issue, :default) }
let_it_be(:project) { create(:project) }
context 'when a type was already set' do
let_it_be(:issue, refind: true) { create(:issue, project: project) }
it 'does not fetch a work item type from the DB' do
expect(issue.work_item_type_id).to eq(issue_type.id)
expect(WorkItems::Type).not_to receive(:default_by_type)
expect(issue).to be_valid
end
it 'does not fetch a work item type from the DB when updating the type' do
expect(issue.work_item_type_id).to eq(issue_type.id)
expect(WorkItems::Type).not_to receive(:default_by_type)
issue.update!(work_item_type: task_type, issue_type: 'task')
expect(issue.work_item_type_id).to eq(task_type.id)
end
it 'ensures a work item type if updated to nil' do
expect(issue.work_item_type_id).to eq(issue_type.id)
expect do
issue.update!(work_item_type: nil)
end.to not_change(issue, :work_item_type).from(issue_type)
end
end
context 'when no type was set' do
let_it_be(:issue, refind: true) { build(:issue, project: project, work_item_type: nil).tap { |issue| issue.save!(validate: false) } }
it 'sets a work item type before validation' do
expect(issue.work_item_type_id).to be_nil
issue.save!
expect(issue.work_item_type_id).to eq(issue_type.id)
end
it 'does not fetch type from DB if provided during update' do
expect(issue.work_item_type_id).to be_nil
expect(WorkItems::Type).not_to receive(:default_by_type)
issue.update!(work_item_type: task_type, issue_type: 'task')
expect(issue.work_item_type_id).to eq(task_type.id)
end
end
end
describe '#record_create_action' do
it 'records the creation action after saving' do
expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_created_action)
@ -387,7 +442,7 @@ RSpec.describe Issue do
# TODO: Remove when NOT NULL constraint is added to the relationship
describe '#work_item_type' do
let(:issue) { create(:issue, :incident, project: reusable_project, work_item_type: nil) }
let(:issue) { build(:issue, :incident, project: reusable_project, work_item_type: nil).tap { |issue| issue.save!(validate: false) } }
it 'returns a default type if the legacy issue does not have a work item type associated yet' do
expect(issue.work_item_type_id).to be_nil

View File

@ -167,6 +167,36 @@ RSpec.describe Member do
end
end
end
context 'member role access level' do
let_it_be(:member) { create(:group_member, access_level: Gitlab::Access::DEVELOPER) }
context 'no member role is associated' do
it 'is valid' do
expect(member).to be_valid
end
end
context 'member role is associated' do
let_it_be(:member_role) do
create(:member_role, members: [member])
end
context 'member role matches access level' do
it 'is valid' do
expect(member).to be_valid
end
end
context 'member role does not match access level' do
it 'is invalid' do
member_role.base_access_level = Gitlab::Access::MAINTAINER
expect(member).not_to be_valid
end
end
end
end
end
describe 'Scopes & finders' do

View File

@ -5,9 +5,11 @@ require "spec_helper"
RSpec.describe API::Markdown do
describe "POST /markdown" do
let(:user) {} # No-op. It gets overwritten in the contexts below.
let(:disable_authenticate_markdown_api) { false }
before do
stub_commonmark_sourcepos_disabled
stub_feature_flags(authenticate_markdown_api: false) if disable_authenticate_markdown_api
post api("/markdown", user), params: params
end
@ -21,25 +23,51 @@ RSpec.describe API::Markdown do
end
end
shared_examples "404 Project Not Found" do
it "responses with 404 Not Found" do
shared_examples '404 Project Not Found' do
it 'responds with 404 Not Found' do
expect(response).to have_gitlab_http_status(:not_found)
expect(response.headers["Content-Type"]).to eq("application/json")
expect(json_response).to be_a(Hash)
expect(json_response["message"]).to eq("404 Project Not Found")
expect(json_response['message']).to eq('404 Project Not Found')
end
end
context "when arguments are invalid" do
context "when text is missing" do
shared_examples '400 Bad Request' do
it 'responds with 400 Bad Request' do
expect(response).to have_gitlab_http_status(:bad_request)
expect(response.headers['Content-Type']).to eq('application/json')
expect(json_response).to be_a(Hash)
expect(json_response['error']).to eq('text is missing')
end
end
context 'when not logged in' do
let(:user) {}
let(:params) { {} }
context 'and authenticate_markdown_api turned on' do
it 'responds with 401 Unathorized' do
expect(response).to have_gitlab_http_status(:unauthorized)
expect(response.headers['Content-Type']).to eq('application/json')
expect(json_response).to be_a(Hash)
expect(json_response['message']).to eq('401 Unauthorized')
end
end
context 'and authenticate_markdown_api turned off' do
let(:disable_authenticate_markdown_api) { true }
it_behaves_like '400 Bad Request'
end
end
context 'when arguments are invalid' do
let(:user) { create(:user) }
context 'when text is missing' do
let(:params) { {} }
it "responses with 400 Bad Request" do
expect(response).to have_gitlab_http_status(:bad_request)
expect(response.headers["Content-Type"]).to eq("application/json")
expect(json_response).to be_a(Hash)
expect(json_response["error"]).to eq("text is missing")
end
it_behaves_like '400 Bad Request'
end
context "when project is not found" do
@ -53,6 +81,7 @@ RSpec.describe API::Markdown do
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
let(:user) { create(:user) }
let(:issue_url) { "http://#{Gitlab.config.gitlab.host}/#{issue.project.namespace.path}/#{issue.project.path}/-/issues/#{issue.iid}" }
let(:text) { ":tada: Hello world! :100: #{issue.to_reference}" }
@ -132,13 +161,12 @@ RSpec.describe API::Markdown do
context 'when not logged in' do
let(:user) {}
let(:disable_authenticate_markdown_api) { true }
it_behaves_like 'user without proper access'
end
context 'when logged in as user without access' do
let(:user) { create(:user) }
it_behaves_like 'user without proper access'
end
@ -175,8 +203,9 @@ RSpec.describe API::Markdown do
end
end
context 'when not logged in' do
context 'when not logged in and authenticate_markdown_api turned off' do
let(:user) {}
let(:disable_authenticate_markdown_api) { true }
it_behaves_like 'user without proper access'
end

View File

@ -22,6 +22,18 @@ RSpec.describe Groups::TransferService, :sidekiq_inline do
let!(:group_member) { create(:group_member, :owner, group: group, user: user) }
let(:transfer_service) { described_class.new(group, user) }
shared_examples 'publishes a GroupTransferedEvent' do
it do
expect { transfer_service.execute(target) }
.to publish_event(Groups::GroupTransferedEvent)
.with(
group_id: group.id,
old_root_namespace_id: group.root_ancestor.id,
new_root_namespace_id: target.root_ancestor.id
)
end
end
context 'handling packages' do
let_it_be(:group) { create(:group, :public) }
let_it_be(:new_group) { create(:group, :public) }
@ -895,6 +907,10 @@ RSpec.describe Groups::TransferService, :sidekiq_inline do
expect { transfer_service.execute(root_group) }
.not_to change { CustomerRelations::IssueContact.count }
end
it_behaves_like 'publishes a GroupTransferedEvent' do
let(:target) { root_group }
end
end
context 'moving down' do
@ -904,6 +920,10 @@ RSpec.describe Groups::TransferService, :sidekiq_inline do
expect { transfer_service.execute(another_subgroup) }
.not_to change { CustomerRelations::IssueContact.count }
end
it_behaves_like 'publishes a GroupTransferedEvent' do
let(:target) { another_subgroup }
end
end
context 'moving sideways' do
@ -913,6 +933,10 @@ RSpec.describe Groups::TransferService, :sidekiq_inline do
expect { transfer_service.execute(another_subgroup) }
.not_to change { CustomerRelations::IssueContact.count }
end
it_behaves_like 'publishes a GroupTransferedEvent' do
let(:target) { another_subgroup }
end
end
context 'moving to new root group' do
@ -932,6 +956,10 @@ RSpec.describe Groups::TransferService, :sidekiq_inline do
expect { transfer_service.execute(new_parent_group) }
.not_to change { CustomerRelations::IssueContact.count }
end
it_behaves_like 'publishes a GroupTransferedEvent' do
let(:target) { new_parent_group }
end
end
context 'moving to a subgroup within a new root group' do
@ -953,6 +981,10 @@ RSpec.describe Groups::TransferService, :sidekiq_inline do
expect { transfer_service.execute(subgroup_in_new_parent_group) }
.not_to change { CustomerRelations::IssueContact.count }
end
it_behaves_like 'publishes a GroupTransferedEvent' do
let(:target) { subgroup_in_new_parent_group }
end
end
context 'with permission on the subgroup' do
@ -965,6 +997,11 @@ RSpec.describe Groups::TransferService, :sidekiq_inline do
expect(transfer_service.error).to eq("Transfer failed: Group contains contacts/organizations and you don't have enough permissions to move them to the new root group.")
end
it 'does not publish a GroupTransferedEvent' do
expect { transfer_service.execute(subgroup_in_new_parent_group) }
.not_to publish_event(Groups::GroupTransferedEvent)
end
end
end
end

View File

@ -9,6 +9,9 @@ RSpec.shared_context 'with API::Markdown Snapshot shared context' do |glfm_speci
# rubocop:enable Layout/LineLength
include ApiHelpers
let_it_be(:user) { create(:user) }
let_it_be(:api_url) { api('/markdown', user) }
markdown_examples, html_examples = %w[markdown.yml html.yml].map do |file_name|
yaml = File.read("#{glfm_specification_dir}/example_snapshots/#{file_name}")
YAML.safe_load(yaml, symbolize_names: true, aliases: true)
@ -29,8 +32,6 @@ RSpec.shared_context 'with API::Markdown Snapshot shared context' do |glfm_speci
let(:normalizations) { normalizations_by_example_name.dig(name, :html, :static, :snapshot) }
it "verifies conversion of GLFM to HTML", :unlimited_max_formatted_output_length do
api_url = api "/markdown"
# noinspection RubyResolve
normalized_html = normalize_html(html, normalizations)

View File

@ -382,6 +382,7 @@ RSpec.describe 'Every Sidekiq worker' do
'ProjectScheduleBulkRepositoryShardMovesWorker' => 3,
'ProjectTemplateExportWorker' => false,
'ProjectUpdateRepositoryStorageWorker' => 3,
'Projects::DisableLegacyOpenSourceLicenseForInactiveProjectsWorker' => 3,
'Projects::GitGarbageCollectWorker' => false,
'Projects::InactiveProjectsDeletionNotificationWorker' => 3,
'Projects::PostCreationWorker' => 3,

View File

@ -63,6 +63,7 @@ module Tooling
%r{\A((ee|jh)/)?app/views/} => [:frontend, :backend],
%r{\A((ee|jh)/)?public/} => :frontend,
%r{\A((ee|jh)/)?spec/(javascripts|frontend|frontend_integration)/} => :frontend,
%r{\A((ee|jh)/)?spec/contracts/consumer} => :frontend,
%r{\A((ee|jh)/)?vendor/assets/} => :frontend,
%r{\A((ee|jh)/)?scripts/frontend/} => :frontend,
%r{(\A|/)(
@ -117,6 +118,7 @@ module Tooling
%r{\Alib/gitlab/ci/templates} => :ci_template,
%r{\A((ee|jh)/)?spec/features/} => :test,
%r{\A((ee|jh)/)?spec/contracts/} => :test,
%r{\A((ee|jh)/)?spec/support/shared_examples/features/} => :test,
%r{\A((ee|jh)/)?spec/support/shared_contexts/features/} => :test,
%r{\A((ee|jh)/)?spec/support/helpers/features/} => :test,