summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue15
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml6
-rw-r--r--app/views/projects/protected_tags/_create_protected_tag.html.haml2
-rw-r--r--app/views/projects/protected_tags/shared/_create_protected_tag.html.haml2
-rw-r--r--app/views/projects/protected_tags/shared/_dropdown.html.haml2
-rw-r--r--app/views/projects/protected_tags/shared/_index.html.haml2
-rw-r--r--app/views/projects/tags/index.html.haml2
-rw-r--r--app/views/projects/tags/new.html.haml8
-rw-r--r--app/views/projects/tags/show.html.haml6
-rw-r--r--app/views/shared/_zen.html.haml2
-rw-r--r--changelogs/unreleased/223162-enclose-release-cli-steps-in-an-array.yml5
-rw-r--r--changelogs/unreleased/223279-confidential-warning-doesnt-show-the-issuable-type.yml5
-rw-r--r--doc/update/restore_after_failure.md4
-rw-r--r--doc/user/project/requirements/index.md31
-rw-r--r--lib/gitlab/ci/build/releaser.rb2
-rw-r--r--qa/qa.rb7
-rw-r--r--qa/qa/page/component/dropdown_filter.rb2
-rw-r--r--qa/qa/page/project/settings/protected_tags.rb41
-rw-r--r--qa/qa/page/project/settings/repository.rb10
-rw-r--r--qa/qa/page/project/sub_menus/repository.rb15
-rw-r--r--qa/qa/page/project/tag/index.rb19
-rw-r--r--qa/qa/page/project/tag/new.rb41
-rw-r--r--qa/qa/page/project/tag/show.rb29
-rw-r--r--qa/qa/resource/project.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb109
-rw-r--r--spec/frontend/ide/components/repo_editor_spec.js10
-rw-r--r--spec/frontend/vue_shared/components/notes/noteable_warning_spec.js17
-rw-r--r--spec/lib/gitlab/ci/build/releaser_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/build/step_spec.rb2
-rw-r--r--spec/requests/api/runner_spec.rb2
-rw-r--r--spec/services/spam/spam_verdict_service_spec.rb11
31 files changed, 356 insertions, 63 deletions
diff --git a/app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue b/app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue
index e3986af695d..f986b105f20 100644
--- a/app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue
@@ -8,16 +8,10 @@ function buildDocsLinkStart(path) {
return `<a href="${escape(path)}" target="_blank" rel="noopener noreferrer">`;
}
-const NoteableType = {
- Issue: 'issue',
- Epic: 'epic',
- MergeRequest: 'merge_request',
-};
-
const NoteableTypeText = {
- [NoteableType.Issue]: __('issue'),
- [NoteableType.Epic]: __('epic'),
- [NoteableType.MergeRequest]: __('merge request'),
+ Issue: __('issue'),
+ Epic: __('epic'),
+ MergeRequest: __('merge request'),
};
export default {
@@ -39,7 +33,8 @@ export default {
noteableType: {
type: String,
required: false,
- default: NoteableType.Issue,
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ default: 'Issue',
},
lockedNoteableDocsPath: {
type: String,
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index 16902ebe1d4..0c3a69cf569 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -37,7 +37,7 @@
- if project_nav_tab? :files
= nav_link(controller: sidebar_repository_paths, unless: -> { current_path?('projects/graphs#charts') }) do
- = link_to project_tree_path(@project), class: 'shortcuts-tree qa-project-menu-repo' do
+ = link_to project_tree_path(@project), class: 'shortcuts-tree', data: { qa_selector: "repository_link" } do
.nav-icon-container
= sprite_icon('doc-text')
%span.nav-item-name#js-onboarding-repo-link
@@ -58,11 +58,11 @@
= _('Commits')
= nav_link(html_options: {class: branches_tab_class}) do
- = link_to project_branches_path(@project), class: 'qa-branches-link', id: 'js-onboarding-branches-link' do
+ = link_to project_branches_path(@project), data: { qa_selector: "branches_link" }, id: 'js-onboarding-branches-link' do
= _('Branches')
= nav_link(controller: [:tags]) do
- = link_to project_tags_path(@project) do
+ = link_to project_tags_path(@project), data: { qa_selector: "tags_link" } do
= _('Tags')
= nav_link(path: 'graphs#show') do
diff --git a/app/views/projects/protected_tags/_create_protected_tag.html.haml b/app/views/projects/protected_tags/_create_protected_tag.html.haml
index f53b81cada6..b58df9de380 100644
--- a/app/views/projects/protected_tags/_create_protected_tag.html.haml
+++ b/app/views/projects/protected_tags/_create_protected_tag.html.haml
@@ -3,6 +3,6 @@
= dropdown_tag('Select',
options: { toggle_class: 'js-allowed-to-create wide',
dropdown_class: 'dropdown-menu-selectable capitalize-header',
- data: { field_name: 'protected_tag[create_access_levels_attributes][0][access_level]', input_id: 'create_access_levels_attributes' }})
+ data: { field_name: 'protected_tag[create_access_levels_attributes][0][access_level]', input_id: 'create_access_levels_attributes', qa_selector: 'access_levels_dropdown' }})
= render 'projects/protected_tags/shared/create_protected_tag'
diff --git a/app/views/projects/protected_tags/shared/_create_protected_tag.html.haml b/app/views/projects/protected_tags/shared/_create_protected_tag.html.haml
index 020e6e187a6..8a6ae53a7c4 100644
--- a/app/views/projects/protected_tags/shared/_create_protected_tag.html.haml
+++ b/app/views/projects/protected_tags/shared/_create_protected_tag.html.haml
@@ -25,4 +25,4 @@
= yield :create_access_levels
.card-footer
- = f.submit 'Protect', class: 'btn-success btn', disabled: true
+ = f.submit 'Protect', class: 'btn-success btn', disabled: true, data: { qa_selector: 'protect_tag_button' }
diff --git a/app/views/projects/protected_tags/shared/_dropdown.html.haml b/app/views/projects/protected_tags/shared/_dropdown.html.haml
index 824a8604f6f..9c7f532fa29 100644
--- a/app/views/projects/protected_tags/shared/_dropdown.html.haml
+++ b/app/views/projects/protected_tags/shared/_dropdown.html.haml
@@ -6,7 +6,7 @@
footer_content: true,
data: { show_no: true, show_any: true, show_upcoming: true,
selected: params[:protected_tag_name],
- project_id: @project.try(:id) } }) do
+ project_id: @project.try(:id), qa_selector: 'tags_dropdown' } }) do
%ul.dropdown-footer-list
%li
diff --git a/app/views/projects/protected_tags/shared/_index.html.haml b/app/views/projects/protected_tags/shared/_index.html.haml
index b0c87ac8c17..4bf3ce09fc7 100644
--- a/app/views/projects/protected_tags/shared/_index.html.haml
+++ b/app/views/projects/protected_tags/shared/_index.html.haml
@@ -1,6 +1,6 @@
- expanded = expanded_by_default?
-%section.settings.no-animate#js-protected-tags-settings{ class: ('expanded' if expanded) }
+%section.settings.no-animate#js-protected-tags-settings{ class: ('expanded' if expanded), data: { qa_selector: 'protected_tag_settings_content' } }
.settings-header
%h4
Protected Tags
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index 6ad7cf1848f..e3d3f2226a8 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -24,7 +24,7 @@
%li
= link_to title, filter_tags_path(sort: value), class: ("is-active" if @sort == value)
- if can?(current_user, :admin_tag, @project)
- = link_to new_project_tag_path(@project), class: 'btn btn-success new-tag-btn' do
+ = link_to new_project_tag_path(@project), class: 'btn btn-success new-tag-btn', data: { qa_selector: "new_tag_button" } do
= s_('TagsPage|New tag')
= link_to project_tags_path(@project, rss_url_options), title: _("Tags feed"), class: 'btn d-none d-sm-inline-block has-tooltip' do
= icon("rss")
diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml
index 5aabfdd022a..c874a510e61 100644
--- a/app/views/projects/tags/new.html.haml
+++ b/app/views/projects/tags/new.html.haml
@@ -14,7 +14,7 @@
.form-group.row
= label_tag :tag_name, nil, class: 'col-form-label col-sm-2'
.col-sm-10
- = text_field_tag :tag_name, params[:tag_name], required: true, autofocus: true, class: 'form-control'
+ = text_field_tag :tag_name, params[:tag_name], required: true, autofocus: true, class: 'form-control', data: { qa_selector: "tag_name_field" }
.form-group.row
= label_tag :ref, 'Create from', class: 'col-form-label col-sm-2'
.col-sm-10.create-from
@@ -29,7 +29,7 @@
.form-group.row
= label_tag :message, nil, class: 'col-form-label col-sm-2'
.col-sm-10
- = text_area_tag :message, @message, required: false, class: 'form-control', rows: 5
+ = text_area_tag :message, @message, required: false, class: 'form-control', rows: 5, data: { qa_selector: "tag_message_field" }
.form-text.text-muted
= tag_description_help_text
%hr
@@ -47,10 +47,10 @@
= s_('TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}').html_safe % replacements
= render layout: 'shared/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
- = render 'shared/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here…'), current_text: @release_description
+ = render 'shared/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here…'), current_text: @release_description, qa_selector: 'release_notes_field'
= render 'shared/notes/hints'
.form-actions
- = button_tag s_('TagsPage|Create tag'), class: 'btn btn-success'
+ = button_tag s_('TagsPage|Create tag'), class: 'btn btn-success', data: { qa_selector: "create_tag_button" }
= link_to s_('TagsPage|Cancel'), project_tags_path(@project), class: 'btn btn-cancel'
-# haml-lint:disable InlineJavaScript
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml
index 6f53a687fb9..b98906a6863 100644
--- a/app/views/projects/tags/show.html.haml
+++ b/app/views/projects/tags/show.html.haml
@@ -9,7 +9,7 @@
.top-area.multi-line.flex-wrap
.nav-text
.title
- %span.item-title.ref-name
+ %span.item-title.ref-name{ data: { qa_selector: 'tag_name_content' } }
= icon('tag')
= @tag.name
- if protected_tag?(@project, @tag)
@@ -56,12 +56,12 @@
%i.fa.fa-trash-o
- if @tag.message.present?
- %pre.wrap
+ %pre.wrap{ data: { qa_selector: 'tag_message_content' } }
= strip_signature(@tag.message)
.append-bottom-default.prepend-top-default
- if @release.description.present?
- .description.md
+ .description.md{ data: { qa_selector: 'tag_release_notes_content' } }
= markdown_field(@release, :description)
- else
= s_('TagsPage|This tag has no release notes.')
diff --git a/app/views/shared/_zen.html.haml b/app/views/shared/_zen.html.haml
index 8dd0e5a92a7..914409d0e65 100644
--- a/app/views/shared/_zen.html.haml
+++ b/app/views/shared/_zen.html.haml
@@ -14,6 +14,6 @@
supports_autocomplete: supports_autocomplete,
qa_selector: qa_selector }
- else
- = text_area_tag attr, current_text, class: classes, placeholder: placeholder
+ = text_area_tag attr, current_text, data: { qa_selector: qa_selector }, class: classes, placeholder: placeholder
%a.zen-control.zen-control-leave.js-zen-leave.gl-text-gray-700{ href: "#" }
= sprite_icon('compress', size: 16)
diff --git a/changelogs/unreleased/223162-enclose-release-cli-steps-in-an-array.yml b/changelogs/unreleased/223162-enclose-release-cli-steps-in-an-array.yml
new file mode 100644
index 00000000000..c5fc7ee561f
--- /dev/null
+++ b/changelogs/unreleased/223162-enclose-release-cli-steps-in-an-array.yml
@@ -0,0 +1,5 @@
+---
+title: Enclose `release-cli` steps in an array
+merge_request: 34913
+author:
+type: fixed
diff --git a/changelogs/unreleased/223279-confidential-warning-doesnt-show-the-issuable-type.yml b/changelogs/unreleased/223279-confidential-warning-doesnt-show-the-issuable-type.yml
new file mode 100644
index 00000000000..48451ea8c4b
--- /dev/null
+++ b/changelogs/unreleased/223279-confidential-warning-doesnt-show-the-issuable-type.yml
@@ -0,0 +1,5 @@
+---
+title: Fix confidential warning not showing the issuable type
+merge_request: 34988
+author:
+type: fixed
diff --git a/doc/update/restore_after_failure.md b/doc/update/restore_after_failure.md
index c850bbff1cf..2c70e38d041 100644
--- a/doc/update/restore_after_failure.md
+++ b/doc/update/restore_after_failure.md
@@ -10,7 +10,9 @@ the previous version you were using.
First, roll back the code or package. For source installations this involves
checking out the older version (branch or tag). For Omnibus installations this
-means installing the older `.deb` or `.rpm` package. Then, restore from a backup.
+means installing the older
+[`.deb` or `.rpm` package](https://packages.gitlab.com/gitlab). Then, restore from a
+backup.
Follow the instructions in the
[Backup and Restore](../raketasks/backup_restore.md#restore-gitlab)
documentation.
diff --git a/doc/user/project/requirements/index.md b/doc/user/project/requirements/index.md
index d9bd02518a4..f80b10275fc 100644
--- a/doc/user/project/requirements/index.md
+++ b/doc/user/project/requirements/index.md
@@ -76,7 +76,7 @@ As soon as a requirement is reopened, it no longer appears in the **Archived** t
## Search for a requirement from the requirements list page
-> - Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.1.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/212543) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.1.
You can search for a requirement from the list of requirements using filtered search bar (similar to
that of Issues and Merge Requests) based on following parameters:
@@ -96,7 +96,8 @@ You can also sort requirements list by:
## Allow requirements to be satisfied from a CI job
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2859) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.1.
+> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2859) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.1.
+> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/215514) ability to specify individual requirements and their statuses in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.2.
GitLab supports [requirements test
reports](../../../ci/pipelines/job_artifacts.md#artifactsreportsrequirements-ultimate) now.
@@ -132,6 +133,32 @@ the requirement report is checked for the "all passed" record
(`{"*":"passed"}`), and on success, it marks all existing open requirements as
Satisfied.
+#### Specifying individual requirements
+
+It is possible to specify individual requirements and their statuses.
+
+If the following requirements exist:
+
+- `REQ-1` (with IID `1`)
+- `REQ-2` (with IID `2`)
+- `REQ-3` (with IID `3`)
+
+It is possible to specify that the first requirement passed, and the second failed.
+Valid values are "passed" and "failed".
+By omitting a requirement IID (in this case `REQ-3`'s IID `3`), no result is noted.
+
+```yaml
+requirements_confirmation:
+ when: manual
+ allow_failure: false
+ script:
+ - mkdir tmp
+ - echo "{\"1\":\"passed\", \"2\":\"failed\"}" > tmp/requirements.json
+ artifacts:
+ reports:
+ requirements: tmp/requirements.json
+```
+
### Add the manual job to CI conditionally
To configure your CI to include the manual job only when there are some open
diff --git a/lib/gitlab/ci/build/releaser.rb b/lib/gitlab/ci/build/releaser.rb
index ba6c7857e96..cc28ed14464 100644
--- a/lib/gitlab/ci/build/releaser.rb
+++ b/lib/gitlab/ci/build/releaser.rb
@@ -16,7 +16,7 @@ module Gitlab
command = BASE_COMMAND.dup
config.each { |k, v| command.concat(" --#{k.to_s.dasherize} \"#{v}\"") }
- command
+ [command]
end
end
end
diff --git a/qa/qa.rb b/qa/qa.rb
index 6d4acffd3de..d848aca9a66 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -254,6 +254,12 @@ module QA
autoload :Show, 'qa/page/project/pipeline/show'
end
+ module Tag
+ autoload :Index, 'qa/page/project/tag/index'
+ autoload :New, 'qa/page/project/tag/new'
+ autoload :Show, 'qa/page/project/tag/show'
+ end
+
module Job
autoload :Show, 'qa/page/project/job/show'
end
@@ -273,6 +279,7 @@ module QA
autoload :Runners, 'qa/page/project/settings/runners'
autoload :MergeRequest, 'qa/page/project/settings/merge_request'
autoload :MirroringRepositories, 'qa/page/project/settings/mirroring_repositories'
+ autoload :ProtectedTags, 'qa/page/project/settings/protected_tags'
autoload :VisibilityFeaturesPermissions, 'qa/page/project/settings/visibility_features_permissions'
module Services
diff --git a/qa/qa/page/component/dropdown_filter.rb b/qa/qa/page/component/dropdown_filter.rb
index a39a04a668d..30c6f13eaf7 100644
--- a/qa/qa/page/component/dropdown_filter.rb
+++ b/qa/qa/page/component/dropdown_filter.rb
@@ -8,7 +8,7 @@ module QA
page.has_css?('.dropdown-input-field', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
find('.dropdown-input-field').set(item)
- click_link item
+ click_on item
end
end
end
diff --git a/qa/qa/page/project/settings/protected_tags.rb b/qa/qa/page/project/settings/protected_tags.rb
new file mode 100644
index 00000000000..a11c15fdc4f
--- /dev/null
+++ b/qa/qa/page/project/settings/protected_tags.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Settings
+ class ProtectedTags < Page::Base
+ include Page::Component::DropdownFilter
+
+ view 'app/views/projects/protected_tags/shared/_dropdown.html.haml' do
+ element :tags_dropdown
+ end
+
+ view 'app/views/projects/protected_tags/_create_protected_tag.html.haml' do
+ element :access_levels_dropdown
+ end
+
+ view 'app/views/projects/protected_tags/shared/_create_protected_tag.html.haml' do
+ element :protect_tag_button
+ end
+
+ def set_tag(tag_name)
+ click_element :tags_dropdown
+ filter_and_select(tag_name)
+ end
+
+ def choose_access_level_role(role)
+ click_element :access_levels_dropdown
+ click_on role
+ end
+
+ def click_protect_tag_button
+ click_element :protect_tag_button
+ end
+ end
+ end
+ end
+ end
+end
+
+QA::Page::Project::Settings::ProtectedTags.prepend_if_ee('QA::EE::Page::Project::Settings::ProtectedTags')
diff --git a/qa/qa/page/project/settings/repository.rb b/qa/qa/page/project/settings/repository.rb
index 8e9a24a4741..fd3a590c2c1 100644
--- a/qa/qa/page/project/settings/repository.rb
+++ b/qa/qa/page/project/settings/repository.rb
@@ -23,6 +23,10 @@ module QA
element :deploy_keys_settings
end
+ view 'app/views/projects/protected_tags/shared/_index.html.haml' do
+ element :protected_tag_settings_content
+ end
+
def expand_deploy_tokens(&block)
expand_section(:deploy_tokens_settings) do
Settings::DeployTokens.perform(&block)
@@ -46,6 +50,12 @@ module QA
MirroringRepositories.perform(&block)
end
end
+
+ def expand_protected_tags(&block)
+ expand_section(:protected_tag_settings_content) do
+ ProtectedTags.perform(&block)
+ end
+ end
end
end
end
diff --git a/qa/qa/page/project/sub_menus/repository.rb b/qa/qa/page/project/sub_menus/repository.rb
index 38d6b8e50f4..c78c7521b64 100644
--- a/qa/qa/page/project/sub_menus/repository.rb
+++ b/qa/qa/page/project/sub_menus/repository.rb
@@ -14,15 +14,16 @@ module QA
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
- element :project_menu_repo
+ element :repository_link
element :branches_link
+ element :tags_link
end
end
end
def click_repository
within_sidebar do
- click_element(:project_menu_repo)
+ click_element(:repository_link)
end
end
@@ -34,11 +35,19 @@ module QA
end
end
+ def go_to_repository_tags
+ hover_repository do
+ within_submenu do
+ click_element(:tags_link)
+ end
+ end
+ end
+
private
def hover_repository
within_sidebar do
- find_element(:project_menu_repo).hover
+ find_element(:repository_link).hover
yield
end
diff --git a/qa/qa/page/project/tag/index.rb b/qa/qa/page/project/tag/index.rb
new file mode 100644
index 00000000000..b8f7bd3b0b4
--- /dev/null
+++ b/qa/qa/page/project/tag/index.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Tag
+ class Index < Page::Base
+ view 'app/views/projects/tags/index.html.haml' do
+ element :new_tag_button
+ end
+
+ def click_new_tag_button
+ click_element :new_tag_button
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/tag/new.rb b/qa/qa/page/project/tag/new.rb
new file mode 100644
index 00000000000..dc59c07ec98
--- /dev/null
+++ b/qa/qa/page/project/tag/new.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Tag
+ class New < Page::Base
+ view 'app/views/projects/tags/new.html.haml' do
+ element :tag_name_field
+ element :tag_message_field
+ element :release_notes_field
+ element :create_tag_button
+ end
+
+ view 'app/views/shared/_zen.html.haml' do
+ # This partial adds the `release_notes_field` selector passed from 'app/views/projects/tags/new.html.haml'
+ # The checks below ensure that required lines are not removed without updating this page object
+ element :_, "qa_selector = local_assigns.fetch(:qa_selector, '')" # rubocop:disable QA/ElementWithPattern
+ element :_, "text_area_tag attr, current_text, data: { qa_selector: qa_selector }" # rubocop:disable QA/ElementWithPattern
+ end
+
+ def fill_tag_name(text)
+ fill_element(:tag_name_field, text)
+ end
+
+ def fill_tag_message(text)
+ fill_element(:tag_message_field, text)
+ end
+
+ def fill_release_notes(text)
+ fill_element(:release_notes_field, text)
+ end
+
+ def click_create_tag_button
+ click_element :create_tag_button
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/tag/show.rb b/qa/qa/page/project/tag/show.rb
new file mode 100644
index 00000000000..1974448a7c5
--- /dev/null
+++ b/qa/qa/page/project/tag/show.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Tag
+ class Show < Page::Base
+ view 'app/views/projects/tags/show.html.haml' do
+ element :tag_name_content
+ element :tag_message_content
+ element :tag_release_notes_content
+ end
+
+ def has_tag_name?(text)
+ has_element?(:tag_name_content, text: text)
+ end
+
+ def has_tag_message?(text)
+ has_element?(:tag_message_content, text: text)
+ end
+
+ def has_tag_release_notes?(text)
+ has_element?(:tag_release_notes_content, text: text)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index 645f4e97ee0..358e87b0eb9 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -96,7 +96,11 @@ module QA
end
def has_file?(file_path)
- repository_tree.any? { |file| file[:path] == file_path }
+ response = repository_tree
+
+ raise ResourceNotFoundError, "#{response[:message]}" if response.is_a?(Hash) && response.has_key?(:message)
+
+ response.any? { |file| file[:path] == file_path }
end
def api_get_path
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb
new file mode 100644
index 00000000000..db1af970c40
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+module QA
+ context 'Manage' do
+ describe 'Repository tags' do
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'project-for-tags'
+ project.initialize_with_readme = true
+ end
+ end
+
+ let(:developer_user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
+ let(:maintainer_user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_2, Runtime::Env.gitlab_qa_password_2) }
+ let(:tag_name) { 'v0.0.1' }
+ let(:tag_message) { 'Version 0.0.1' }
+ let(:tag_release_notes) { 'Release It!' }
+
+ shared_examples 'successful tag creation' do |user|
+ it "can be created by #{user}" do
+ Flow::Login.sign_in(as: send(user))
+
+ create_tag_for_project(project, tag_name, tag_message, tag_release_notes)
+
+ Page::Project::Tag::Show.perform do |show|
+ expect(show).to have_tag_name(tag_name)
+ expect(show).to have_tag_message(tag_message)
+ expect(show).to have_tag_release_notes(tag_release_notes)
+ expect(show).not_to have_element(:create_tag_button)
+ end
+ end
+ end
+
+ shared_examples 'unsuccessful tag creation' do |user|
+ it "cannot be created by an unauthorized #{user}" do
+ Flow::Login.sign_in(as: send(user))
+
+ create_tag_for_project(project, tag_name, tag_message, tag_release_notes)
+
+ Page::Project::Tag::New.perform do |new_tag|
+ expect(new_tag).to have_content('You are not allowed to create this tag as it is protected.')
+ expect(new_tag).to have_element(:create_tag_button)
+ end
+ end
+ end
+
+ context 'when not protected' do
+ before do
+ add_members_to_project(project)
+ end
+
+ it_behaves_like 'successful tag creation', :developer_user
+ it_behaves_like 'successful tag creation', :maintainer_user
+ end
+
+ context 'when protected' do
+ before do
+ add_members_to_project(project)
+
+ Flow::Login.sign_in
+
+ protect_tag_for_project(project, 'v*', 'Maintainers')
+
+ Page::Main::Menu.perform(&:sign_out)
+ end
+
+ it_behaves_like 'unsuccessful tag creation', :developer_user
+ it_behaves_like 'successful tag creation', :maintainer_user
+ end
+
+ def create_tag_for_project(project, name, message, release_notes)
+ project.visit!
+
+ Page::Project::Menu.perform(&:go_to_repository_tags)
+ Page::Project::Tag::Index.perform(&:click_new_tag_button)
+
+ Page::Project::Tag::New.perform do |new_tag|
+ new_tag.fill_tag_name(name)
+ new_tag.fill_tag_message(message)
+ new_tag.fill_release_notes(release_notes)
+ new_tag.click_create_tag_button
+ end
+ end
+
+ def protect_tag_for_project(project, tag, role)
+ project.visit!
+
+ Page::Project::Menu.perform(&:go_to_repository_settings)
+
+ Page::Project::Settings::Repository.perform do |setting|
+ setting.expand_protected_tags do |protected_tags|
+ protected_tags.set_tag(tag)
+ protected_tags.choose_access_level_role(role)
+
+ protected_tags.click_protect_tag_button
+ end
+ end
+ end
+
+ def add_members_to_project(project)
+ @developer_user = developer_user
+ @maintainer_user = maintainer_user
+
+ project.add_member(@developer_user, Resource::Members::AccessLevel::DEVELOPER)
+ project.add_member(@maintainer_user, Resource::Members::AccessLevel::MAINTAINER)
+ end
+ end
+ end
+end
diff --git a/spec/frontend/ide/components/repo_editor_spec.js b/spec/frontend/ide/components/repo_editor_spec.js
index 0ba58561f08..a77edfc3fa8 100644
--- a/spec/frontend/ide/components/repo_editor_spec.js
+++ b/spec/frontend/ide/components/repo_editor_spec.js
@@ -546,7 +546,7 @@ describe('RepoEditor', () => {
store.state.viewer = viewerTypes.diff;
// we delay returning the file to make sure editor doesn't initialize before we fetch file content
- await waitUsingRealTimer(10);
+ await waitUsingRealTimer(30);
return 'rawFileData123\n';
});
@@ -555,8 +555,7 @@ describe('RepoEditor', () => {
vm.file = f;
- // use the real timer to accurately simulate the race condition
- await waitUsingRealTimer(20);
+ await waitForEditorSetup();
expect(vm.model.getModel().getValue()).toBe('rawFileData123\n');
});
@@ -575,14 +574,13 @@ describe('RepoEditor', () => {
})
.mockImplementationOnce(async () => {
// we delay returning fileB content to make sure the editor doesn't initialize prematurely
- await waitUsingRealTimer(10);
+ await waitUsingRealTimer(30);
return 'fileB-rawContent\n';
});
vm.file = fileA;
- // use the real timer to accurately simulate the race condition
- await waitUsingRealTimer(20);
+ await waitForEditorSetup();
expect(vm.model.getModel().getValue()).toBe('fileB-rawContent\n');
});
});
diff --git a/spec/frontend/vue_shared/components/notes/noteable_warning_spec.js b/spec/frontend/vue_shared/components/notes/noteable_warning_spec.js
index 67889c0cdb4..ae8c9a0928e 100644
--- a/spec/frontend/vue_shared/components/notes/noteable_warning_spec.js
+++ b/spec/frontend/vue_shared/components/notes/noteable_warning_spec.js
@@ -60,9 +60,12 @@ describe('Issue Warning Component', () => {
});
});
- it('renders information about confidential issue', () => {
+ it('renders information about confidential issue', async () => {
expect(findConfidentialBlock().exists()).toBe(true);
expect(findConfidentialBlock().element).toMatchSnapshot();
+
+ await wrapper.vm.$nextTick();
+ expect(findConfidentialBlock(wrapper).text()).toContain('This is a confidential issue.');
});
it('renders warning icon', () => {
@@ -142,13 +145,13 @@ describe('Issue Warning Component', () => {
it('renders confidential & locked messages with noteable "epic"', async () => {
wrapperLocked.setProps({
- noteableType: 'epic',
+ noteableType: 'Epic',
});
wrapperConfidential.setProps({
- noteableType: 'epic',
+ noteableType: 'Epic',
});
wrapperLockedAndConfidential.setProps({
- noteableType: 'epic',
+ noteableType: 'Epic',
});
await wrapperLocked.vm.$nextTick();
@@ -167,13 +170,13 @@ describe('Issue Warning Component', () => {
it('renders confidential & locked messages with noteable "merge request"', async () => {
wrapperLocked.setProps({
- noteableType: 'merge_request',
+ noteableType: 'MergeRequest',
});
wrapperConfidential.setProps({
- noteableType: 'merge_request',
+ noteableType: 'MergeRequest',
});
wrapperLockedAndConfidential.setProps({
- noteableType: 'merge_request',
+ noteableType: 'MergeRequest',
});
await wrapperLocked.vm.$nextTick();
diff --git a/spec/lib/gitlab/ci/build/releaser_spec.rb b/spec/lib/gitlab/ci/build/releaser_spec.rb
index 2f7bca777dd..b338cd3a2d2 100644
--- a/spec/lib/gitlab/ci/build/releaser_spec.rb
+++ b/spec/lib/gitlab/ci/build/releaser_spec.rb
@@ -19,7 +19,7 @@ describe Gitlab::Ci::Build::Releaser do
end
it 'generates the script' do
- expect(subject).to eq('release-cli create --name "Release $CI_COMMIT_SHA" --description "Created using the release-cli $EXTRA_DESCRIPTION" --tag-name "release-$CI_COMMIT_SHA" --ref "$CI_COMMIT_SHA"')
+ expect(subject).to eq(['release-cli create --name "Release $CI_COMMIT_SHA" --description "Created using the release-cli $EXTRA_DESCRIPTION" --tag-name "release-$CI_COMMIT_SHA" --ref "$CI_COMMIT_SHA"'])
end
end
@@ -43,7 +43,7 @@ describe Gitlab::Ci::Build::Releaser do
end
it 'generates the script' do
- expect(subject).to eq(result)
+ expect(subject).to eq([result])
end
end
end
diff --git a/spec/lib/gitlab/ci/build/step_spec.rb b/spec/lib/gitlab/ci/build/step_spec.rb
index 1cebda2cc7e..ea36d38bb10 100644
--- a/spec/lib/gitlab/ci/build/step_spec.rb
+++ b/spec/lib/gitlab/ci/build/step_spec.rb
@@ -62,7 +62,7 @@ describe Gitlab::Ci::Build::Step do
let(:job) { create(:ci_build, :release_options) }
it 'returns the release-cli command line' do
- expect(subject.script).to eq("release-cli create --name \"Release $CI_COMMIT_SHA\" --description \"Created using the release-cli $EXTRA_DESCRIPTION\" --tag-name \"release-$CI_COMMIT_SHA\" --ref \"$CI_COMMIT_SHA\"")
+ expect(subject.script).to eq(["release-cli create --name \"Release $CI_COMMIT_SHA\" --description \"Created using the release-cli $EXTRA_DESCRIPTION\" --tag-name \"release-$CI_COMMIT_SHA\" --ref \"$CI_COMMIT_SHA\""])
end
end
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index fe1435826a0..fc0d4b91aa2 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -668,7 +668,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
{
"name" => "release",
"script" =>
- "release-cli create --ref \"$CI_COMMIT_SHA\" --name \"Release $CI_COMMIT_SHA\" --tag-name \"release-$CI_COMMIT_SHA\" --description \"Created using the release-cli $EXTRA_DESCRIPTION\"",
+ ["release-cli create --ref \"$CI_COMMIT_SHA\" --name \"Release $CI_COMMIT_SHA\" --tag-name \"release-$CI_COMMIT_SHA\" --description \"Created using the release-cli $EXTRA_DESCRIPTION\""],
"timeout" => 3600,
"when" => "on_success",
"allow_failure" => false
diff --git a/spec/services/spam/spam_verdict_service_spec.rb b/spec/services/spam/spam_verdict_service_spec.rb
index fe70da7a894..b9f9657f20f 100644
--- a/spec/services/spam/spam_verdict_service_spec.rb
+++ b/spec/services/spam/spam_verdict_service_spec.rb
@@ -81,17 +81,6 @@ describe Spam::SpamVerdictService do
end
end
- context 'and one is supported' do
- before do
- allow(service).to receive(:akismet_verdict).and_return('nonsense')
- allow(service).to receive(:spam_verdict).and_return(BLOCK_USER)
- end
-
- it 'renders the more restrictive verdict' do
- expect(subject).to eq BLOCK_USER
- end
- end
-
context 'and none are supported' do
before do
allow(service).to receive(:akismet_verdict).and_return('nonsense')