Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
3b30c28dc6
commit
69eacec239
|
|
@ -1008,8 +1008,6 @@ module Ci
|
||||||
# Set scheduling type of processables if they were created before scheduling_type
|
# Set scheduling type of processables if they were created before scheduling_type
|
||||||
# data was deployed (https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22246).
|
# data was deployed (https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22246).
|
||||||
def ensure_scheduling_type!
|
def ensure_scheduling_type!
|
||||||
return unless ::Gitlab::Ci::Features.ensure_scheduling_type_enabled?
|
|
||||||
|
|
||||||
processables.populate_scheduling_type!
|
processables.populate_scheduling_type!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ class Project < ApplicationRecord
|
||||||
|
|
||||||
cache_markdown_field :description, pipeline: :description
|
cache_markdown_field :description, pipeline: :description
|
||||||
|
|
||||||
|
default_value_for :packages_enabled, true
|
||||||
default_value_for :archived, false
|
default_value_for :archived, false
|
||||||
default_value_for :resolve_outdated_diff_discussions, false
|
default_value_for :resolve_outdated_diff_discussions, false
|
||||||
default_value_for :container_registry_enabled, gitlab_config_features.container_registry
|
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
|
# Sometimes queries (e.g. using CTEs) require explicit disambiguation with table name
|
||||||
scope :projects_order_id_desc, -> { reorder(self.arel_table['id'].desc) }
|
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 :in_namespace, ->(namespace_ids) { where(namespace_id: namespace_ids) }
|
||||||
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
|
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
|
||||||
scope :joined, ->(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
|
||||||
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
|
def cleanup
|
||||||
@repository = nil
|
@repository = nil
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,9 @@ class ProjectPolicy < BasePolicy
|
||||||
::Feature.enabled?(:build_service_proxy, @subject)
|
::Feature.enabled?(:build_service_proxy, @subject)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
with_scope :subject
|
||||||
|
condition(:packages_disabled) { !@subject.packages_enabled }
|
||||||
|
|
||||||
features = %w[
|
features = %w[
|
||||||
merge_requests
|
merge_requests
|
||||||
issues
|
issues
|
||||||
|
|
@ -296,12 +299,17 @@ class ProjectPolicy < BasePolicy
|
||||||
enable :read_metrics_user_starred_dashboard
|
enable :read_metrics_user_starred_dashboard
|
||||||
end
|
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 { owner | admin | guest | group_member }.prevent :request_access
|
||||||
rule { ~request_access_enabled }.prevent :request_access
|
rule { ~request_access_enabled }.prevent :request_access
|
||||||
|
|
||||||
rule { can?(:developer_access) & can?(:create_issue) }.enable :import_issues
|
rule { can?(:developer_access) & can?(:create_issue) }.enable :import_issues
|
||||||
|
|
||||||
rule { can?(:developer_access) }.policy do
|
rule { can?(:developer_access) }.policy do
|
||||||
|
enable :create_package
|
||||||
enable :admin_board
|
enable :admin_board
|
||||||
enable :admin_merge_request
|
enable :admin_merge_request
|
||||||
enable :admin_milestone
|
enable :admin_milestone
|
||||||
|
|
@ -342,6 +350,7 @@ class ProjectPolicy < BasePolicy
|
||||||
end
|
end
|
||||||
|
|
||||||
rule { can?(:maintainer_access) }.policy do
|
rule { can?(:maintainer_access) }.policy do
|
||||||
|
enable :destroy_package
|
||||||
enable :admin_board
|
enable :admin_board
|
||||||
enable :push_to_delete_protected_branch
|
enable :push_to_delete_protected_branch
|
||||||
enable :update_snippet
|
enable :update_snippet
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,6 @@ module Ci
|
||||||
|
|
||||||
attributes[:user] = current_user
|
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
|
Ci::Build.transaction do
|
||||||
# mark all other builds of that name as retried
|
# mark all other builds of that name as retried
|
||||||
build.pipeline.builds.latest
|
build.pipeline.builds.latest
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
|
|
||||||
- if note_editable
|
- if note_editable
|
||||||
.note-actions-item
|
.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
|
%span.link-highlight
|
||||||
= custom_icon('icon_pencil')
|
= custom_icon('icon_pencil')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
- if note_editable || !is_current_user
|
- if note_editable || !is_current_user
|
||||||
.dropdown.more-actions.note-actions-item
|
.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
|
%span.icon
|
||||||
= custom_icon('ellipsis_v')
|
= custom_icon('ellipsis_v')
|
||||||
%ul.dropdown-menu.more-actions-dropdown.dropdown-open-left
|
%ul.dropdown-menu.more-actions-dropdown.dropdown-open-left
|
||||||
|
|
@ -14,6 +14,6 @@
|
||||||
= _('Report abuse to admin')
|
= _('Report abuse to admin')
|
||||||
- if note_editable
|
- if note_editable
|
||||||
%li
|
%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
|
%span.text-danger
|
||||||
= _('Delete comment')
|
= _('Delete comment')
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
- noteable_name = @note.noteable.human_class_name
|
- noteable_name = @note.noteable.human_class_name
|
||||||
|
|
||||||
.float-left.btn-group.append-right-10.droplab-dropdown.comment-type-dropdown.js-comment-type-dropdown
|
.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?
|
- 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
|
= 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_id, '', class: 'js-form-target-id'
|
||||||
= hidden_field_tag :target_type, '', class: 'js-form-target-type'
|
= 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 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'
|
= render 'shared/notes/hints'
|
||||||
|
|
||||||
.note-form-actions.clearfix
|
.note-form-actions.clearfix
|
||||||
.settings-message.note-edit-warning.js-finish-edit-warning
|
.settings-message.note-edit-warning.js-finish-edit-warning
|
||||||
= _("Finish editing this message first!")
|
= _("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' }
|
%button.btn.btn-nr.btn-cancel.note-edit-cancel{ type: 'button' }
|
||||||
= _("Cancel")
|
= _("Cancel")
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
.discussion-form-container.discussion-with-resolve-btn.flex-column.p-0
|
.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 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,
|
attr: :note,
|
||||||
classes: 'note-textarea js-note-text',
|
classes: 'note-textarea js-note-text',
|
||||||
placeholder: _("Write a comment or drag your files here…"),
|
placeholder: _("Write a comment or drag your files here…"),
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
%span.note-header-author-name.bold
|
%span.note-header-author-name.bold
|
||||||
= note.author.name
|
= note.author.name
|
||||||
= user_status(note.author)
|
= user_status(note.author)
|
||||||
%span.note-headline-light
|
%span.note-headline-light{ data: { qa_selector: 'note_author_content' } }
|
||||||
= note.author.to_reference
|
= note.author.to_reference
|
||||||
%span.note-headline-light.note-headline-meta
|
%span.note-headline-light.note-headline-meta
|
||||||
- if note.system
|
- if note.system
|
||||||
|
|
@ -51,7 +51,7 @@
|
||||||
- else
|
- else
|
||||||
= render 'projects/notes/actions', note: note, note_editable: note_editable
|
= render 'projects/notes/actions', note: note, note_editable: note_editable
|
||||||
.note-body{ class: note_editable ? 'js-task-list-container' : '' }
|
.note-body{ class: note_editable ? 'js-task-list-container' : '' }
|
||||||
.note-text.md
|
.note-text.md{ data: { qa_selector: 'note_content' } }
|
||||||
= markdown_field(note, :note)
|
= markdown_field(note, :note)
|
||||||
= edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago')
|
= 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 } }
|
.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
|
- if note_editable
|
||||||
.note-actions-item
|
.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
|
%span.link-highlight
|
||||||
= custom_icon('icon_pencil')
|
= custom_icon('icon_pencil')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Add installed state metrics for Cilium cluster application
|
||||||
|
merge_request: 35808
|
||||||
|
author:
|
||||||
|
type: added
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
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.
|
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
|
- **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
|
- **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
|
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
|
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)
|
# 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.-->
|
<!--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).
|
> [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.
|
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.
|
- 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
|
- Start with an h2 (`##`), break complex steps into small steps using
|
||||||
subheadings h3 > h4 > h5 > h6. _Never skip a hierarchy level, such
|
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.
|
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
|
- 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.
|
is simple and the document is short.
|
||||||
|
|
||||||
<!-- ## Troubleshooting
|
<!-- ## 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_runner` | `counts` | `configure` | | | Total GitLab Managed clusters with Runner enabled |
|
||||||
| `clusters_applications_knative` | `counts` | `configure` | | | Total GitLab Managed clusters with Knative 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_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 |
|
| `clusters_management_project` | `counts` | `configure` | | | Total GitLab Managed clusters with defined cluster management project |
|
||||||
| `in_review_folder` | `counts` | | | | |
|
| `in_review_folder` | `counts` | | | | |
|
||||||
| `grafana_integrated_projects` | `counts` | | | | |
|
| `grafana_integrated_projects` | `counts` | | | | |
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,6 @@ module Gitlab
|
||||||
::Feature.enabled?(:ci_artifacts_exclude, default_enabled: true)
|
::Feature.enabled?(:ci_artifacts_exclude, default_enabled: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.ensure_scheduling_type_enabled?
|
|
||||||
::Feature.enabled?(:ci_ensure_scheduling_type, default_enabled: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.job_heartbeats_runner?(project)
|
def self.job_heartbeats_runner?(project)
|
||||||
::Feature.enabled?(:ci_job_heartbeats_runner, project, default_enabled: true)
|
::Feature.enabled?(:ci_job_heartbeats_runner, project, default_enabled: true)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ module Gitlab
|
||||||
clusters_applications_knative: count(::Clusters::Applications::Knative.available),
|
clusters_applications_knative: count(::Clusters::Applications::Knative.available),
|
||||||
clusters_applications_elastic_stack: count(::Clusters::Applications::ElasticStack.available),
|
clusters_applications_elastic_stack: count(::Clusters::Applications::ElasticStack.available),
|
||||||
clusters_applications_jupyter: count(::Clusters::Applications::Jupyter.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),
|
clusters_management_project: count(::Clusters::Cluster.with_management_project),
|
||||||
in_review_folder: count(::Environment.in_review_folder),
|
in_review_folder: count(::Environment.in_review_folder),
|
||||||
grafana_integrated_projects: count(GrafanaIntegration.enabled),
|
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."
|
msgid "Dashboard|Unable to add %{invalidProjects}. This dashboard is available for public projects, and private projects in groups with a Silver plan."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DastProfiles|Manage profiles"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DastProfiles|New Site Profile"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DastProfiles|New site profile"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Data is still calculating..."
|
msgid "Data is still calculating..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
||||||
3
qa/qa.rb
3
qa/qa.rb
|
|
@ -365,6 +365,7 @@ module QA
|
||||||
|
|
||||||
module Snippet
|
module Snippet
|
||||||
autoload :New, 'qa/page/project/snippet/new'
|
autoload :New, 'qa/page/project/snippet/new'
|
||||||
|
autoload :Show, 'qa/page/project/snippet/show'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -462,6 +463,8 @@ module QA
|
||||||
autoload :CustomMetric, 'qa/page/component/custom_metric'
|
autoload :CustomMetric, 'qa/page/component/custom_metric'
|
||||||
autoload :DesignManagement, 'qa/page/component/design_management'
|
autoload :DesignManagement, 'qa/page/component/design_management'
|
||||||
autoload :ProjectSelector, 'qa/page/component/project_selector'
|
autoload :ProjectSelector, 'qa/page/component/project_selector'
|
||||||
|
autoload :Snippet, 'qa/page/component/snippet'
|
||||||
|
autoload :NewSnippet, 'qa/page/component/new_snippet'
|
||||||
|
|
||||||
module Issuable
|
module Issuable
|
||||||
autoload :Common, 'qa/page/component/issuable/common'
|
autoload :Common, 'qa/page/component/issuable/common'
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
# 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
|
||||||
|
|
@ -0,0 +1,174 @@
|
||||||
|
# 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 Dashboard
|
||||||
module Snippet
|
module Snippet
|
||||||
class New < Page::Base
|
class New < Page::Base
|
||||||
view 'app/assets/javascripts/snippets/components/edit.vue' do
|
include Page::Component::NewSnippet
|
||||||
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
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -5,102 +5,7 @@ module QA
|
||||||
module Dashboard
|
module Dashboard
|
||||||
module Snippet
|
module Snippet
|
||||||
class Show < Page::Base
|
class Show < Page::Base
|
||||||
view 'app/assets/javascripts/snippets/components/snippet_description_view.vue' do
|
include Page::Component::Snippet
|
||||||
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
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ module QA
|
||||||
module Page
|
module Page
|
||||||
module Project
|
module Project
|
||||||
module Snippet
|
module Snippet
|
||||||
class New < Page::Dashboard::Snippet::New
|
class New < Page::Base
|
||||||
|
include Page::Component::NewSnippet
|
||||||
include Component::LazyLoader
|
include Component::LazyLoader
|
||||||
view 'app/views/shared/empty_states/_snippets.html.haml' do
|
view 'app/views/shared/empty_states/_snippets.html.haml' do
|
||||||
element :create_first_snippet_link
|
element :create_first_snippet_link
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
# 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
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
# 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_knative, :installed, cluster: gcp_cluster)
|
||||||
create(:clusters_applications_elastic_stack, :installed, cluster: gcp_cluster)
|
create(:clusters_applications_elastic_stack, :installed, cluster: gcp_cluster)
|
||||||
create(:clusters_applications_jupyter, :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[0], enabled: true)
|
||||||
create(:grafana_integration, project: projects[1], 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[:clusters_applications_elastic_stack]).to eq(1)
|
||||||
expect(count_data[:grafana_integrated_projects]).to eq(2)
|
expect(count_data[:grafana_integrated_projects]).to eq(2)
|
||||||
expect(count_data[:clusters_applications_jupyter]).to eq(1)
|
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[:clusters_management_project]).to eq(1)
|
||||||
|
|
||||||
expect(count_data[:deployments]).to eq(4)
|
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(:metrics_users_starred_dashboards).inverse_of(:project) }
|
||||||
it { is_expected.to have_many(:repository_storage_moves) }
|
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(: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
|
it_behaves_like 'model with repository' do
|
||||||
let_it_be(:container) { create(:project, :repository, path: 'somewhere') }
|
let_it_be(:container) { create(:project, :repository, path: 'somewhere') }
|
||||||
|
|
@ -6167,6 +6169,39 @@ RSpec.describe Project do
|
||||||
end
|
end
|
||||||
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
|
describe '#design_management_enabled?' do
|
||||||
let(:project) { build(:project) }
|
let(:project) { build(:project) }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -941,4 +941,64 @@ RSpec.describe ProjectPolicy do
|
||||||
it { is_expected.to be_disallowed(:read_build_report_results) }
|
it { is_expected.to be_disallowed(:read_build_report_results) }
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
||||||
|
|
@ -278,28 +278,6 @@ RSpec.describe Ci::RetryBuildService do
|
||||||
expect(new_build.metadata.expanded_environment_name).to eq('production')
|
expect(new_build.metadata.expanded_environment_name).to eq('production')
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
context 'when user does not have ability to execute build' do
|
context 'when user does not have ability to execute build' do
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue