提交 69eacec2 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 3b30c28d
......@@ -1008,8 +1008,6 @@ module Ci
# Set scheduling type of processables if they were created before scheduling_type
# data was deployed (https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22246).
def ensure_scheduling_type!
return unless ::Gitlab::Ci::Features.ensure_scheduling_type_enabled?
processables.populate_scheduling_type!
end
......
......@@ -65,6 +65,7 @@ class Project < ApplicationRecord
cache_markdown_field :description, pipeline: :description
default_value_for :packages_enabled, true
default_value_for :archived, false
default_value_for :resolve_outdated_diff_discussions, false
default_value_for :container_registry_enabled, gitlab_config_features.container_registry
......@@ -446,6 +447,7 @@ class Project < ApplicationRecord
# Sometimes queries (e.g. using CTEs) require explicit disambiguation with table name
scope :projects_order_id_desc, -> { reorder(self.arel_table['id'].desc) }
scope :with_packages, -> { joins(:packages) }
scope :in_namespace, ->(namespace_ids) { where(namespace_id: namespace_ids) }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
scope :joined, ->(user) { where('namespace_id != ?', user.namespace_id) }
......@@ -866,6 +868,15 @@ class Project < ApplicationRecord
end
end
# Because we use default_value_for we need to be sure
# packages_enabled= method does exist even if we rollback migration.
# Otherwise many tests from spec/migrations will fail.
def packages_enabled=(value)
if has_attribute?(:packages_enabled)
write_attribute(:packages_enabled, value)
end
end
def cleanup
@repository = nil
end
......
......@@ -154,6 +154,9 @@ class ProjectPolicy < BasePolicy
::Feature.enabled?(:build_service_proxy, @subject)
end
with_scope :subject
condition(:packages_disabled) { !@subject.packages_enabled }
features = %w[
merge_requests
issues
......@@ -296,12 +299,17 @@ class ProjectPolicy < BasePolicy
enable :read_metrics_user_starred_dashboard
end
rule { packages_disabled | repository_disabled }.policy do
prevent(*create_read_update_admin_destroy(:package))
end
rule { owner | admin | guest | group_member }.prevent :request_access
rule { ~request_access_enabled }.prevent :request_access
rule { can?(:developer_access) & can?(:create_issue) }.enable :import_issues
rule { can?(:developer_access) }.policy do
enable :create_package
enable :admin_board
enable :admin_merge_request
enable :admin_milestone
......@@ -342,6 +350,7 @@ class ProjectPolicy < BasePolicy
end
rule { can?(:maintainer_access) }.policy do
enable :destroy_package
enable :admin_board
enable :push_to_delete_protected_branch
enable :update_snippet
......
......@@ -34,10 +34,6 @@ module Ci
attributes[:user] = current_user
# TODO: we can probably remove this logic
# see: https://gitlab.com/gitlab-org/gitlab/-/issues/217930
attributes[:scheduling_type] ||= build.find_legacy_scheduling_type
Ci::Build.transaction do
# mark all other builds of that name as retried
build.pipeline.builds.latest
......
......@@ -45,7 +45,7 @@
- if note_editable
.note-actions-item
= button_tag title: 'Edit comment', class: 'note-action-button js-note-edit has-tooltip btn btn-transparent', data: { container: 'body' } do
= button_tag title: 'Edit comment', class: 'note-action-button js-note-edit has-tooltip btn btn-transparent', data: { container: 'body', qa_selector: 'edit_comment_button' } do
%span.link-highlight
= custom_icon('icon_pencil')
......
......@@ -2,7 +2,7 @@
- if note_editable || !is_current_user
.dropdown.more-actions.note-actions-item
= button_tag title: 'More actions', class: 'note-action-button more-actions-toggle has-tooltip btn btn-transparent', data: { toggle: 'dropdown', container: 'body' } do
= button_tag title: 'More actions', class: 'note-action-button more-actions-toggle has-tooltip btn btn-transparent', data: { toggle: 'dropdown', container: 'body', qa_selector: 'more_actions_dropdown' } do
%span.icon
= custom_icon('ellipsis_v')
%ul.dropdown-menu.more-actions-dropdown.dropdown-open-left
......@@ -14,6 +14,6 @@
= _('Report abuse to admin')
- if note_editable
%li
= link_to note_url(note), method: :delete, data: { confirm: 'Are you sure you want to delete this comment?' }, remote: true, class: 'js-note-delete' do
= link_to note_url(note), method: :delete, data: { confirm: 'Are you sure you want to delete this comment?', qa_selector: 'delete_comment_button' }, remote: true, class: 'js-note-delete' do
%span.text-danger
= _('Delete comment')
- noteable_name = @note.noteable.human_class_name
.float-left.btn-group.append-right-10.droplab-dropdown.comment-type-dropdown.js-comment-type-dropdown
%input.btn.btn-nr.btn-success.js-comment-button.js-comment-submit-button{ type: 'submit', value: _('Comment') }
%input.btn.btn-nr.btn-success.js-comment-button.js-comment-submit-button{ type: 'submit', value: _('Comment'), data: { qa_selector: 'comment_button' } }
- if @note.can_be_discussion_note?
= button_tag type: 'button', class: 'btn btn-nr dropdown-toggle btn-success js-note-new-discussion js-disable-on-submit', data: { 'dropdown-trigger' => '#resolvable-comment-menu' }, 'aria-label' => _('Open comment type dropdown') do
......
......@@ -3,12 +3,12 @@
= hidden_field_tag :target_id, '', class: 'js-form-target-id'
= hidden_field_tag :target_type, '', class: 'js-form-target-type'
= render layout: 'shared/md_preview', locals: { url: preview_markdown_path(project), referenced_users: true } do
= render 'shared/zen', attr: 'note[note]', classes: 'note-textarea js-note-text js-task-list-field', placeholder: _("Write a comment or drag your files here…")
= render 'shared/zen', attr: 'note[note]', classes: 'note-textarea js-note-text js-task-list-field', qa_selector: 'edit_note_field', placeholder: _("Write a comment or drag your files here…")
= render 'shared/notes/hints'
.note-form-actions.clearfix
.settings-message.note-edit-warning.js-finish-edit-warning
= _("Finish editing this message first!")
= submit_tag _('Save comment'), class: 'btn btn-nr btn-success js-comment-save-button'
= submit_tag _('Save comment'), class: 'btn btn-nr btn-success js-comment-save-button', data: { qa_selector: 'save_comment_button' }
%button.btn.btn-nr.btn-cancel.note-edit-cancel{ type: 'button' }
= _("Cancel")
......@@ -26,7 +26,7 @@
.discussion-form-container.discussion-with-resolve-btn.flex-column.p-0
= render layout: 'shared/md_preview', locals: { url: preview_url, referenced_users: true } do
= render 'shared/zen', f: f,
= render 'shared/zen', f: f, qa_selector: 'note_field',
attr: :note,
classes: 'note-textarea js-note-text',
placeholder: _("Write a comment or drag your files here…"),
......
......@@ -34,7 +34,7 @@
%span.note-header-author-name.bold
= note.author.name
= user_status(note.author)
%span.note-headline-light
%span.note-headline-light{ data: { qa_selector: 'note_author_content' } }
= note.author.to_reference
%span.note-headline-light.note-headline-meta
- if note.system
......@@ -51,7 +51,7 @@
- else
= render 'projects/notes/actions', note: note, note_editable: note_editable
.note-body{ class: note_editable ? 'js-task-list-container' : '' }
.note-text.md
.note-text.md{ data: { qa_selector: 'note_content' } }
= markdown_field(note, :note)
= edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago')
.original-note-content.hidden{ data: { post_url: note_url(note), target_id: note.noteable.id, target_type: note.noteable.class.name.underscore } }
......
......@@ -8,7 +8,7 @@
- if note_editable
.note-actions-item
= button_tag title: _('Edit comment'), class: 'note-action-button js-note-edit has-tooltip btn btn-transparent', data: { container: 'body' } do
= button_tag title: _('Edit comment'), class: 'note-action-button js-note-edit has-tooltip btn btn-transparent', data: { container: 'body', qa_selector: 'edit_comment_button' } do
%span.link-highlight
= custom_icon('icon_pencil')
......
---
title: Add installed state metrics for Cilium cluster application
merge_request: 35808
author:
type: added
---
title: Removes ci_ensure_scheduling_type feature flag
merge_request: 36140
author:
type: other
......@@ -20,7 +20,7 @@ Every feature or use case document should include the following content in the f
with exceptions and details noted below and in the template included on this page.
- **Title**: Top-level heading with the feature name, or a use case name, which would start with
a verb, like Configuring, Enabling, and so on.
a verb, like "Configure", "Enable", and so on.
- **Introduction**: A couple sentences about the subject matter and what's to be found
on this page. Describe what the feature or topic is, what it does, and in what context it should
be used. There is no need to add a title called "Introduction" or "Overview," because people rarely
......@@ -53,7 +53,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
---
# Feature Name or Use Case Name **[TIER]** (1)
<!--If writing about a use case, drop the tier, and start with a verb, e.g. 'Configuring', 'Implementing', + the goal/scenario-->
<!--If writing about a use case, drop the tier, and start with a verb, e.g. "Configure", "Implement", + the goal/scenario-->
<!--For pages on newly introduced features, add the following line. If only some aspects of the feature have been introduced, specify what parts of the feature.-->
> [Introduced](link_to_issue_or_mr) in GitLab (Tier) X.Y (2).
......@@ -102,12 +102,12 @@ Larger instruction sets may have subsections covering specific phases of the pro
Where appropriate, provide examples of code or configuration files to better clarify intended usage.
- Write a step-by-step guide, with no gaps between the steps.
- Include example code or configurations as part of the relevant step. Use appropriate markdown to [wrap code blocks with syntax highlighting](../../user/markdown.md#colored-code-and-syntax-highlighting).
- Include example code or configurations as part of the relevant step. Use appropriate Markdown to [wrap code blocks with syntax highlighting](../../user/markdown.md#colored-code-and-syntax-highlighting).
- Start with an h2 (`##`), break complex steps into small steps using
subheadings h3 > h4 > h5 > h6. _Never skip a hierarchy level, such
as h2 > h4_, as it will break the TOC and may affect the breadcrumbs.
- Use short and descriptive headings (up to ~50 chars). You can use one
single heading like `## Configuring X` for instructions when the feature
single heading like `## Configure X` for instructions when the feature
is simple and the document is short.
<!-- ## Troubleshooting
......
......@@ -451,6 +451,7 @@ appear to be associated to any of the services running, since they all appear to
| `clusters_applications_runner` | `counts` | `configure` | | | Total GitLab Managed clusters with Runner enabled |
| `clusters_applications_knative` | `counts` | `configure` | | | Total GitLab Managed clusters with Knative enabled |
| `clusters_applications_elastic_stack` | `counts` | `configure` | | | Total GitLab Managed clusters with Elastic Stack enabled |
| `clusters_applications_cilium` | `counts` | `configure` | | | Total GitLab Managed clusters with Cilium enabled |
| `clusters_management_project` | `counts` | `configure` | | | Total GitLab Managed clusters with defined cluster management project |
| `in_review_folder` | `counts` | | | | |
| `grafana_integrated_projects` | `counts` | | | | |
......
......@@ -10,10 +10,6 @@ module Gitlab
::Feature.enabled?(:ci_artifacts_exclude, default_enabled: true)
end
def self.ensure_scheduling_type_enabled?
::Feature.enabled?(:ci_ensure_scheduling_type, default_enabled: true)
end
def self.job_heartbeats_runner?(project)
::Feature.enabled?(:ci_job_heartbeats_runner, project, default_enabled: true)
end
......
......@@ -109,6 +109,7 @@ module Gitlab
clusters_applications_knative: count(::Clusters::Applications::Knative.available),
clusters_applications_elastic_stack: count(::Clusters::Applications::ElasticStack.available),
clusters_applications_jupyter: count(::Clusters::Applications::Jupyter.available),
clusters_applications_cilium: count(::Clusters::Applications::Cilium.available),
clusters_management_project: count(::Clusters::Cluster.with_management_project),
in_review_folder: count(::Environment.in_review_folder),
grafana_integrated_projects: count(GrafanaIntegration.enabled),
......
......@@ -7318,6 +7318,15 @@ msgstr ""
msgid "Dashboard|Unable to add %{invalidProjects}. This dashboard is available for public projects, and private projects in groups with a Silver plan."
msgstr ""
msgid "DastProfiles|Manage profiles"
msgstr ""
msgid "DastProfiles|New Site Profile"
msgstr ""
msgid "DastProfiles|New site profile"
msgstr ""
msgid "Data is still calculating..."
msgstr ""
......
......@@ -365,6 +365,7 @@ module QA
module Snippet
autoload :New, 'qa/page/project/snippet/new'
autoload :Show, 'qa/page/project/snippet/show'
end
end
......@@ -462,6 +463,8 @@ module QA
autoload :CustomMetric, 'qa/page/component/custom_metric'
autoload :DesignManagement, 'qa/page/component/design_management'
autoload :ProjectSelector, 'qa/page/component/project_selector'
autoload :Snippet, 'qa/page/component/snippet'
autoload :NewSnippet, 'qa/page/component/new_snippet'
module Issuable
autoload :Common, 'qa/page/component/issuable/common'
......
# frozen_string_literal: true
module QA
module Page
module Component
module NewSnippet
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/assets/javascripts/snippets/components/edit.vue' do
element :snippet_title_field, required: true
element :submit_button
end
base.view 'app/assets/javascripts/snippets/components/snippet_description_edit.vue' do
element :snippet_description_field
element :description_placeholder, required: true
end
base.view 'app/assets/javascripts/snippets/components/snippet_blob_edit.vue' do
element :file_name_field
end
base.view 'app/views/shared/form_elements/_description.html.haml' do
element :issuable_form_description
end
base.view 'app/views/shared/snippets/_form.html.haml' do
element :snippet_description_field
element :description_placeholder
element :snippet_title_field
element :file_name_field
element :submit_button
end
base.view 'app/views/shared/_zen.html.haml' do
# This 'element' is here only to ensure the changes in the view source aren't mistakenly changed
element :_, "qa_selector = local_assigns.fetch(:qa_selector, '')" # rubocop:disable QA/ElementWithPattern
end
end
def fill_title(title)
fill_element :snippet_title_field, title
end
def fill_description(description)
click_element :description_placeholder
fill_element :snippet_description_field, description
end
def set_visibility(visibility)
choose visibility
end
def fill_file_name(name)
finished_loading?
fill_element :file_name_field, name
end
def fill_file_content(content)
finished_loading?
text_area.set content
end
def click_create_snippet_button
wait_until(reload: false) { !find_element(:submit_button).disabled? }
click_element(:submit_button, Page::Dashboard::Snippet::Show)
end
private
def text_area
find('#editor textarea', visible: false)
end
end
end
end
end
# frozen_string_literal: true
module QA
module Page
module Component
module Snippet
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/assets/javascripts/snippets/components/snippet_title.vue' do
element :snippet_title_content, required: true
end
base.view 'app/assets/javascripts/snippets/components/snippet_description_view.vue' do
element :snippet_description_content
end
base.view 'app/assets/javascripts/snippets/components/snippet_header.vue' do
element :snippet_container
end
base.view 'app/assets/javascripts/blob/components/blob_header_filepath.vue' do
element :file_title_content
end
base.view 'app/assets/javascripts/vue_shared/components/blob_viewers/simple_viewer.vue' do
element :file_content
end
base.view 'app/assets/javascripts/blob/components/blob_content.vue' do
element :file_content
end
base.view 'app/assets/javascripts/snippets/components/snippet_header.vue' do
element :snippet_action_button
element :delete_snippet_button
end
base.view 'app/assets/javascripts/snippets/components/snippet_blob_view.vue' do
element :clone_button
end
base.view 'app/assets/javascripts/vue_shared/components/clone_dropdown.vue' do
element :copy_http_url_button
element :copy_ssh_url_button
end
base.view 'app/views/shared/notes/_comment_button.html.haml' do
element :comment_button
end
base.view 'app/views/shared/notes/_form.html.haml' do
element :note_field
end
base.view 'app/views/snippets/notes/_actions.html.haml' do
element :edit_comment_button
end
base.view 'app/views/shared/notes/_edit_form.html.haml' do
element :edit_note_field
element :save_comment_button
end
base.view 'app/views/shared/notes/_note.html.haml' do
element :note_content
element :note_author_content
end
base.view 'app/views/projects/notes/_more_actions_dropdown.html.haml' do
element :more_actions_dropdown
element :delete_comment_button
end
end
def has_snippet_title?(snippet_title)
has_element? :snippet_title_content, text: snippet_title
end
def has_snippet_description?(snippet_description)
has_element? :snippet_description_content, text: snippet_description
end
def has_no_snippet_description?
has_no_element?(:snippet_description_field)
end
def has_visibility_type?(visibility_type)
within_element(:snippet_container) do
has_text?(visibility_type)
end
end
def has_file_name?(file_name)
within_element(:file_title_content) do
has_text?(file_name)
end
end
def has_file_content?(file_content)
finished_loading?
within_element(:file_content) do
has_text?(file_content)
end
end
def click_edit_button
finished_loading?
click_element(:snippet_action_button, action: 'Edit')
end
def click_delete_button
finished_loading?
click_element(:snippet_action_button, action: 'Delete')
click_element(:delete_snippet_button)
# wait for the page to reload after deletion
wait_until(reload: false) do
has_no_element?(:delete_snippet_button) &&
has_no_element?(:snippet_action_button, action: 'Delete')
end
end
def get_repository_uri_http
finished_loading?
click_element(:clone_button)
Git::Location.new(find_element(:copy_http_url_button)['data-clipboard-text']).uri.to_s
end
def get_repository_uri_ssh
finished_loading?
click_element(:clone_button)
Git::Location.new(find_element(:copy_ssh_url_button)['data-clipboard-text']).uri.to_s
end
def add_comment(comment)
finished_loading?
fill_element(:note_field, comment)
click_element(:comment_button)
end
def has_comment_author?(author_username)
finished_loading?
within_element(:note_author_content) do
has_text?('@' + author_username)
end
end
def has_comment_content?(comment_content)
finished_loading?
within_element(:note_content) do
has_text?(comment_content)
end
end
def edit_comment(comment)
finished_loading?
click_element(:edit_comment_button)
fill_element(:edit_note_field, comment)
click_element(:save_comment_button)
end
def delete_comment(comment)
finished_loading?
click_element(:more_actions_dropdown)
accept_alert do
click_element(:delete_comment_button)
end
end
end
end
end
end
......@@ -5,70 +5,7 @@ module QA
module Dashboard
module Snippet
class New < Page::Base
view 'app/assets/javascripts/snippets/components/edit.vue' do
element :snippet_title_field, required: true
element :submit_button
end
view 'app/assets/javascripts/snippets/components/snippet_description_edit.vue' do
element :snippet_description_field
element :description_placeholder, required: true
end
view 'app/assets/javascripts/snippets/components/snippet_blob_edit.vue' do
element :file_name_field
end
view 'app/views/shared/form_elements/_description.html.haml' do
element :issuable_form_description
end
view 'app/views/shared/snippets/_form.html.haml' do
element :snippet_description_field
element :description_placeholder
element :snippet_title_field
element :file_name_field
element :submit_button
end
view 'app/views/shared/_zen.html.haml' do
# This 'element' is here only to ensure the changes in the view source aren't mistakenly changed
element :_, "qa_selector = local_assigns.fetch(:qa_selector, '')" # rubocop:disable QA/ElementWithPattern
end
def fill_title(title)
fill_element :snippet_title_field, title
end
def fill_description(description)
click_element :description_placeholder
fill_element :snippet_description_field, description
end
def set_visibility(visibility)
choose visibility
end
def fill_file_name(name)
finished_loading?
fill_element :file_name_field, name
end
def fill_file_content(content)
finished_loading?
text_area.set content
end
def click_create_snippet_button
wait_until(reload: false) { !find_element(:submit_button).disabled? }
click_element :submit_button
end
private
def text_area
find('#editor textarea', visible: false)
end
include Page::Component::NewSnippet
end
end
end
......
......@@ -5,102 +5,7 @@ module QA
module Dashboard
module Snippet
class Show < Page::Base
view 'app/assets/javascripts/snippets/components/snippet_description_view.vue' do
element :snippet_description_content
end
view 'app/assets/javascripts/snippets/components/snippet_title.vue' do
element :snippet_title_content, required: true
end
view 'app/assets/javascripts/snippets/components/snippet_header.vue' do
element :snippet_container
end
view 'app/assets/javascripts/blob/components/blob_header_filepath.vue' do
element :file_title_content
end
view 'app/assets/javascripts/vue_shared/components/blob_viewers/simple_viewer.vue' do
element :file_content
end
view 'app/assets/javascripts/blob/components/blob_content.vue' do
element :file_content
end
view 'app/assets/javascripts/snippets/components/snippet_header.vue' do
element :snippet_action_button
element :delete_snippet_button
end
view 'app/assets/javascripts/snippets/components/snippet_blob_view.vue' do
element :clone_button
end
view 'app/assets/javascripts/vue_shared/components/clone_dropdown.vue' do
element :copy_http_url_button
element :copy_ssh_url_button
end
def has_snippet_title?(snippet_title)
has_element? :snippet_title_content, text: snippet_title
end
def has_snippet_description?(snippet_description)
has_element? :snippet_description_content, text: snippet_description
end
def has_no_snippet_description?
has_no_element?(:snippet_description_field)
end
def has_visibility_type?(visibility_type)
within_element(:snippet_container) do
has_text?(visibility_type)
end
end
def has_file_name?(file_name)
within_element(:file_title_content) do
has_text?(file_name)
end
end
def has_file_content?(file_content)
finished_loading?
within_element(:file_content) do
has_text?(file_content)
end
end
def click_edit_button
finished_loading?
click_element(:snippet_action_button, action: 'Edit')
end
def click_delete_button
finished_loading?
click_element(:snippet_action_button, action: 'Delete')
click_element(:delete_snippet_button)
# wait for the page to reload after deletion
wait_until(reload: false) do
has_no_element?(:delete_snippet_button) &&
has_no_element?(:snippet_action_button, action: 'Delete')
end
end
def get_repository_uri_http
finished_loading?
click_element(:clone_button)
Git::Location.new(find_element(:copy_http_url_button)['data-clipboard-text']).uri.to_s
end
def get_repository_uri_ssh
finished_loading?
click_element(:clone_button)
Git::Location.new(find_element(:copy_ssh_url_button)['data-clipboard-text']).uri.to_s
end
include Page::Component::Snippet
end
end
end
......
......@@ -4,7 +4,8 @@ module QA
module Page
module Project
module Snippet
class New < Page::Dashboard::Snippet::New
class New < Page::Base
include Page::Component::NewSnippet
include Component::LazyLoader
view 'app/views/shared/empty_states/_snippets.html.haml' do
element :create_first_snippet_link
......
# frozen_string_literal: true
module QA
module Page
module Project
module Snippet
class Show < Page::Base
include Page::Component::Snippet
view 'app/views/projects/notes/_actions.html.haml' do
element :edit_comment_button
end
end
end
end
end
end
# frozen_string_literal: true
module QA
RSpec.describe 'Create' do
describe 'Adding comments on snippets' do
let(:comment_author) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
let(:comment_content) { 'Comment 123' }
let(:edited_comment_content) { 'Nice snippet!' }
let(:personal_snippet) do
Resource::Snippet.fabricate! do |snippet|
snippet.title = 'Personal snippet with a comment'
end
end
let(:project_snippet) do
Resource::ProjectSnippet.fabricate! do |snippet|
snippet.title = 'Project snippet with a comment'
end
end
before do
Flow::Login.sign_in
end
shared_examples 'comments on snippets' do |snippet_type|
it "adds, edits, and deletes a comment on a #{snippet_type}" do
send(snippet_type)
Page::Main::Menu.perform(&:sign_out)
Flow::Login.sign_in(as: comment_author)
send(snippet_type).visit!
create_comment
verify_comment_content(comment_author.username, comment_content)
edit_comment
verify_comment_content(comment_author.username, edited_comment_content)
delete_comment
verify_comment_deleted
end
end
it_behaves_like 'comments on snippets', :personal_snippet
it_behaves_like 'comments on snippets', :project_snippet
def create_comment
Page::Dashboard::Snippet::Show.perform do |snippet|
snippet.add_comment(comment_content)
end
end
def edit_comment
Page::Dashboard::Snippet::Show.perform do |snippet|
snippet.edit_comment(edited_comment_content)
end
end
def delete_comment
Page::Dashboard::Snippet::Show.perform do |snippet|
snippet.delete_comment(edited_comment_content)
end
end
def verify_comment_content(author, comment_content)
Page::Dashboard::Snippet::Show.perform do |comment|
expect(comment).to have_comment_author(author)
expect(comment).to have_comment_content(comment_content)
end
end
def verify_comment_deleted
expect(page).not_to have_content(comment_author.username)
expect(page).not_to have_content(edited_comment_content)
end
end
end
end
......@@ -84,6 +84,7 @@ FactoryBot.define do
create(:clusters_applications_knative, :installed, cluster: gcp_cluster)
create(:clusters_applications_elastic_stack, :installed, cluster: gcp_cluster)
create(:clusters_applications_jupyter, :installed, cluster: gcp_cluster)
create(:clusters_applications_cilium, :installed, cluster: gcp_cluster)
create(:grafana_integration, project: projects[0], enabled: true)
create(:grafana_integration, project: projects[1], enabled: true)
......
......@@ -377,6 +377,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
expect(count_data[:clusters_applications_elastic_stack]).to eq(1)
expect(count_data[:grafana_integrated_projects]).to eq(2)
expect(count_data[:clusters_applications_jupyter]).to eq(1)
expect(count_data[:clusters_applications_cilium]).to eq(1)
expect(count_data[:clusters_management_project]).to eq(1)
expect(count_data[:deployments]).to eq(4)
......
......@@ -119,6 +119,8 @@ RSpec.describe Project do
it { is_expected.to have_many(:metrics_users_starred_dashboards).inverse_of(:project) }
it { is_expected.to have_many(:repository_storage_moves) }
it { is_expected.to have_many(:reviews).inverse_of(:project) }
it { is_expected.to have_many(:packages).class_name('Packages::Package') }
it { is_expected.to have_many(:package_files).class_name('Packages::PackageFile') }
it_behaves_like 'model with repository' do
let_it_be(:container) { create(:project, :repository, path: 'somewhere') }
......@@ -6167,6 +6169,39 @@ RSpec.describe Project do
end
end
describe '#packages_enabled' do
subject { create(:project).packages_enabled }
it { is_expected.to be true }
end
describe '#package_already_taken?' do
let(:namespace) { create(:namespace) }
let(:project) { create(:project, :public, namespace: namespace) }
let!(:package) { create(:npm_package, project: project, name: "@#{namespace.path}/foo") }
context 'no package exists with the same name' do
it 'returns false' do
result = project.package_already_taken?("@#{namespace.path}/bar")
expect(result).to be false
end
it 'returns false if it is the project that the package belongs to' do
result = project.package_already_taken?("@#{namespace.path}/foo")
expect(result).to be false
end
end
context 'a package already exists with the same name' do
let(:alt_project) { create(:project, :public, namespace: namespace) }
it 'returns true' do
result = alt_project.package_already_taken?("@#{namespace.path}/foo")
expect(result).to be true
end
end
end
describe '#design_management_enabled?' do
let(:project) { build(:project) }
......
......@@ -941,4 +941,64 @@ RSpec.describe ProjectPolicy do
it { is_expected.to be_disallowed(:read_build_report_results) }
end
end
describe 'read_package' do
subject { described_class.new(current_user, project) }
context 'with admin' do
let(:current_user) { admin }
it { is_expected.to be_allowed(:read_package) }
context 'when repository is disabled' do
before do
project.project_feature.update(repository_access_level: ProjectFeature::DISABLED)
end
it { is_expected.to be_disallowed(:read_package) }
end
end
context 'with owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:read_package) }
end
context 'with maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:read_package) }
end
context 'with developer' do
let(:current_user) { developer }
it { is_expected.to be_allowed(:read_package) }
end
context 'with reporter' do
let(:current_user) { reporter }
it { is_expected.to be_allowed(:read_package) }
end
context 'with guest' do
let(:current_user) { guest }
it { is_expected.to be_allowed(:read_package) }
end
context 'with non member' do
let(:current_user) { create(:user) }
it { is_expected.to be_allowed(:read_package) }
end
context 'with anonymous' do
let(:current_user) { nil }
it { is_expected.to be_allowed(:read_package) }
end
end
end
......@@ -278,28 +278,6 @@ RSpec.describe Ci::RetryBuildService do
expect(new_build.metadata.expanded_environment_name).to eq('production')
end
end
context 'when scheduling_type of build is nil' do
before do
build.update_columns(scheduling_type: nil)
end
context 'when build has not needs' do
it 'sets scheduling_type as :stage' do
expect(new_build.scheduling_type).to eq('stage')
end
end
context 'when build has needs' do
before do
create(:ci_build_need, build: build)
end
it 'sets scheduling_type as :dag' do
expect(new_build.scheduling_type).to eq('dag')
end
end
end
end
context 'when user does not have ability to execute build' do
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册