Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-06-01 06:07:59 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-06-01 06:07:59 +0300
commit72b4a0c010f3eb160c18d94050f5057131db4408 (patch)
tree5f3e44d7d45d8b2b05faf7016ba64a678d39d6d3
parente0a8496a094971dae746dae511b6a41d0cdc92c7 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/ide/components/ide.vue1
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/modal.vue5
-rw-r--r--doc/user/application_security/dast/index.md2
-rw-r--r--qa/qa.rb4
-rw-r--r--qa/qa/page/base.rb25
-rw-r--r--qa/qa/page/component/web_ide/modal/create_new_file.rb19
-rw-r--r--qa/qa/page/merge_request/show.rb25
-rw-r--r--qa/qa/page/project/settings/advanced.rb4
-rw-r--r--qa/qa/page/project/settings/main.rb2
-rw-r--r--qa/qa/page/project/web_ide/edit.rb22
-rw-r--r--qa/qa/resource/group.rb5
-rw-r--r--qa/qa/resource/project.rb2
-rw-r--r--qa/qa/resource/protected_branch.rb33
-rw-r--r--qa/qa/resource/sandbox.rb1
-rw-r--r--qa/qa/runtime/feature.rb37
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb39
-rw-r--r--qa/spec/runtime/feature_spec.rb31
-rw-r--r--qa/spec/support/shared_examples/merge_with_code_owner_shared_examples.rb71
18 files changed, 275 insertions, 53 deletions
diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue
index 562231f8002..e9f84eb8648 100644
--- a/app/assets/javascripts/ide/components/ide.vue
+++ b/app/assets/javascripts/ide/components/ide.vue
@@ -125,6 +125,7 @@ export default {
variant="success"
:title="__('New file')"
:aria-label="__('New file')"
+ data-qa-selector="first_file_button"
@click="createNewFile()"
>
{{ __('New file') }}
diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
index 4766a2fe6ae..ceaf7058c5a 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
@@ -133,7 +133,7 @@ export default {
<gl-modal
ref="modal"
modal-id="ide-new-entry"
- modal-class="qa-new-file-modal"
+ data-qa-selector="new_file_modal"
:title="modalTitle"
:ok-title="buttonLabel"
ok-variant="success"
@@ -148,7 +148,8 @@ export default {
ref="fieldName"
v-model.trim="entryName"
type="text"
- class="form-control qa-full-file-path"
+ class="form-control"
+ data-qa-selector="file_name_field"
:placeholder="placeholder"
/>
<ul
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index 2202d7567cd..03c7236c280 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -471,7 +471,7 @@ DAST can be [configured](#customizing-the-dast-settings) using environment varia
| `DAST_INCLUDE_ALPHA_VULNERABILITIES` | no | Include alpha passive and active scan rules. Boolean. `true`, `True`, or `1` are considered as true value, otherwise false. Defaults to `false`. |
| `DAST_USE_AJAX_SPIDER` | no | Use the AJAX spider in addition to the traditional spider, useful for crawling sites that require JavaScript. Boolean. `true`, `True`, or `1` are considered as true value, otherwise false. Defaults to `false`. |
| `DAST_ZAP_CLI_OPTIONS` | no | ZAP Server command-line options. For example, `-Xmx3072m` would set the Java maximum memory allocation pool size. |
-| `DAST_ZAP_GENERATE_CONFIG` | no | Generate sample ZAP config file for use with `DAST_ZAP_CONFIG_FILE`. Boolean. `true`, `True`, or `1` are considered as true value, otherwise false. Defaults to `false`. |
+| `DAST_ZAP_GENERATE_CONFIG` | no | The file name of the generated sample ZAP config file for use with `DAST_ZAP_CONFIG_FILE`. |
| `DAST_ZAP_CONFIG_FILE` | no | Name of config file used to determine thresholds of vulnerability rules. |
| `DAST_ZAP_CONFIG_URL` | no | URL of config file used to determine thresholds of vulnerability rules. |
diff --git a/qa/qa.rb b/qa/qa.rb
index 933ffe090ba..22444c6b0ae 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -440,6 +440,10 @@ module QA
module WebIDE
autoload :Alert, 'qa/page/component/web_ide/alert'
+
+ module Modal
+ autoload :CreateNewFile, 'qa/page/component/web_ide/modal/create_new_file'
+ end
end
module Project
diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb
index cb3827f8eb1..f0d4ae45ef8 100644
--- a/qa/qa/page/base.rb
+++ b/qa/qa/page/base.rb
@@ -99,7 +99,16 @@ module QA
def find_element(name, **kwargs)
wait_for_requests
- find(element_selector_css(name), kwargs)
+ element_selector = element_selector_css(name, reject_capybara_query_keywords(kwargs))
+ find(element_selector, only_capybara_query_keywords(kwargs))
+ end
+
+ def only_capybara_query_keywords(kwargs)
+ kwargs.select { |kwarg| Capybara::Queries::SelectorQuery::VALID_KEYS.include?(kwarg) }
+ end
+
+ def reject_capybara_query_keywords(kwargs)
+ kwargs.reject { |kwarg| Capybara::Queries::SelectorQuery::VALID_KEYS.include?(kwarg) }
end
def active_element?(name)
@@ -162,11 +171,17 @@ module QA
def has_element?(name, **kwargs)
wait_for_requests
- wait = kwargs.delete(:wait) || Capybara.default_max_wait_time
- text = kwargs.delete(:text)
- klass = kwargs.delete(:class)
+ disabled = kwargs.delete(:disabled)
- has_css?(element_selector_css(name, kwargs), text: text, wait: wait, class: klass)
+ if disabled.nil?
+ wait = kwargs.delete(:wait) || Capybara.default_max_wait_time
+ text = kwargs.delete(:text)
+ klass = kwargs.delete(:class)
+
+ has_css?(element_selector_css(name, kwargs), text: text, wait: wait, class: klass)
+ else
+ find_element(name, kwargs).disabled? == disabled
+ end
end
def has_no_element?(name, **kwargs)
diff --git a/qa/qa/page/component/web_ide/modal/create_new_file.rb b/qa/qa/page/component/web_ide/modal/create_new_file.rb
new file mode 100644
index 00000000000..48eb32fefd6
--- /dev/null
+++ b/qa/qa/page/component/web_ide/modal/create_new_file.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module WebIDE
+ module Modal
+ class CreateNewFile < Page::Base
+ view 'app/assets/javascripts/ide/components/new_dropdown/modal.vue' do
+ element :file_name_field, required: true
+ element :new_file_modal, required: true
+ element :template_list, required: true
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index 0da40b35938..175579dc994 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -154,8 +154,8 @@ module QA
end
def merge!
- click_element :merge_button if ready_to_merge?
-
+ wait_until_ready_to_merge
+ click_element(:merge_button)
finished_loading?
raise "Merge did not appear to be successful" unless merged?
@@ -165,11 +165,18 @@ module QA
has_element?(:merged_status_content, text: 'The changes were merged into', wait: 30)
end
- def ready_to_merge?
- # The merge button is disabled on load
- wait_until do
- has_element?(:merge_button)
- end
+ # Check if the MR is able to be merged
+ # Waits up 10 seconds and returns false if the MR can't be merged
+ def mergeable?
+ # The merge button is enabled via JS, but `has_element?` calls
+ # `wait_for_requests`, which should ensure the disabled/enabled
+ # state of the element is reliable
+ has_element?(:merge_button, disabled: false)
+ end
+
+ # Waits up 60 seconds and raises an error if unable to merge
+ def wait_until_ready_to_merge
+ has_element?(:merge_button)
# The merge button is enabled via JS
wait_until(reload: false) do
@@ -198,7 +205,9 @@ module QA
end
def try_to_merge!
- click_element :merge_button if ready_to_merge?
+ wait_until_ready_to_merge
+
+ click_element(:merge_button)
end
def view_email_patches
diff --git a/qa/qa/page/project/settings/advanced.rb b/qa/qa/page/project/settings/advanced.rb
index 3bb5181a31c..d6e004e827e 100644
--- a/qa/qa/page/project/settings/advanced.rb
+++ b/qa/qa/page/project/settings/advanced.rb
@@ -43,7 +43,9 @@ module QA
def transfer_project!(project_name, namespace)
expand_select_list
- select_transfer_option(namespace)
+ # Workaround for a failure to search when there are no spaces around the /
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/218965
+ select_transfer_option(namespace.gsub(/([^\s])\/([^\s])/, '\1 / \2'))
click_element(:transfer_button)
fill_confirmation_text(project_name)
click_confirm_button
diff --git a/qa/qa/page/project/settings/main.rb b/qa/qa/page/project/settings/main.rb
index efae497b6ba..880711770c0 100644
--- a/qa/qa/page/project/settings/main.rb
+++ b/qa/qa/page/project/settings/main.rb
@@ -58,3 +58,5 @@ module QA
end
end
end
+
+QA::Page::Project::Settings::Main.prepend_if_ee("QA::EE::Page::Project::Settings::Main")
diff --git a/qa/qa/page/project/web_ide/edit.rb b/qa/qa/page/project/web_ide/edit.rb
index 7809f9246ec..29f431d81df 100644
--- a/qa/qa/page/project/web_ide/edit.rb
+++ b/qa/qa/page/project/web_ide/edit.rb
@@ -20,12 +20,6 @@ module QA
element :file_list
end
- view 'app/assets/javascripts/ide/components/new_dropdown/modal.vue' do
- element :full_file_path
- element :new_file_modal
- element :template_list
- end
-
view 'app/assets/javascripts/ide/components/file_templates/bar.vue' do
element :file_templates_bar
element :file_template_dropdown
@@ -52,6 +46,10 @@ module QA
element :editor_container
end
+ view 'app/assets/javascripts/ide/components/ide.vue' do
+ element :first_file_button
+ end
+
def has_file?(file_name)
within_element(:file_list) do
page.has_content? file_name
@@ -59,10 +57,7 @@ module QA
end
def create_new_file_from_template(file_name, template)
- click_element :new_file
-
- # Wait for the modal animation to complete before clicking on the file name
- wait_for_animated_element(:new_file_modal)
+ click_element(:new_file, Page::Component::WebIDE::Modal::CreateNewFile)
within_element(:template_list) do
click_on file_name
@@ -130,6 +125,13 @@ module QA
find('.modified textarea.inputarea')
end
end
+
+ def create_first_file(file_name)
+ finished_loading?
+ click_element(:first_file_button, Page::Component::WebIDE::Modal::CreateNewFile)
+ fill_element(:file_name_field, file_name)
+ click_button('Create file')
+ end
end
end
end
diff --git a/qa/qa/resource/group.rb b/qa/qa/resource/group.rb
index a30bb8cbc77..850d6205305 100644
--- a/qa/qa/resource/group.rb
+++ b/qa/qa/resource/group.rb
@@ -14,6 +14,7 @@ module QA
end
end
+ attribute :full_path
attribute :id
attribute :name
attribute :runners_token
@@ -74,10 +75,6 @@ module QA
def api_delete_path
"/groups/#{id}"
end
-
- def full_path
- sandbox.path + ' / ' + path
- end
end
end
end
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index 76da7ad7d9c..6424807be74 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -30,6 +30,8 @@ module QA
"#{sandbox_path}#{group.path}/#{name}" if group
end
+ alias_method :full_path, :path_with_namespace
+
def sandbox_path
group.respond_to?('sandbox') ? "#{group.sandbox.path}/" : ''
end
diff --git a/qa/qa/resource/protected_branch.rb b/qa/qa/resource/protected_branch.rb
index 9c65e0e5a31..9b728fc4c24 100644
--- a/qa/qa/resource/protected_branch.rb
+++ b/qa/qa/resource/protected_branch.rb
@@ -5,7 +5,12 @@ require 'securerandom'
module QA
module Resource
class ProtectedBranch < Base
- attr_accessor :branch_name, :allowed_to_push, :allowed_to_merge, :protected
+ attr_accessor :branch_name,
+ :allowed_to_push,
+ :allowed_to_merge,
+ :protected,
+ :new_branch,
+ :require_code_owner_approval
attribute :project do
Project.fabricate_via_api! do |resource|
@@ -21,11 +26,12 @@ module QA
project_push.commit_message = 'Add new file'
project_push.branch_name = branch_name
project_push.new_branch = true
- project_push.remote_branch = @branch_name
+ project_push.remote_branch = branch_name
end
end
def initialize
+ @new_branch = true
@branch_name = 'test/branch'
@allowed_to_push = {
roles: Resource::ProtectedBranch::Roles::DEVS_AND_MAINTAINERS
@@ -34,22 +40,29 @@ module QA
roles: Resource::ProtectedBranch::Roles::DEVS_AND_MAINTAINERS
}
@protected = false
+ @require_code_owner_approval = true
end
def fabricate!
- populate(:branch)
+ if new_branch
+ populate(:branch)
- project.wait_for_push_new_branch @branch_name
+ project.wait_for_push_new_branch branch_name
+ end
project.visit!
Page::Project::Menu.perform(&:go_to_repository_settings)
Page::Project::Settings::Repository.perform do |setting|
setting.expand_protected_branches do |page|
- page.select_branch(branch_name)
- page.select_allowed_to_merge(allowed_to_merge)
- page.select_allowed_to_push(allowed_to_push)
- page.protect_branch
+ if new_branch
+ page.select_branch(branch_name)
+ page.select_allowed_to_merge(allowed_to_merge)
+ page.select_allowed_to_push(allowed_to_push)
+ page.protect_branch
+ else
+ page.require_code_owner_approval(branch_name) if require_code_owner_approval
+ end
end
end
end
@@ -59,11 +72,11 @@ module QA
end
def api_get_path
- "/projects/#{@project.api_resource[:id]}/protected_branches/#{@branch_name}"
+ "/projects/#{project.id}/protected_branches/#{branch_name}"
end
def api_delete_path
- "/projects/#{@project.api_resource[:id]}/protected_branches/#{@branch_name}"
+ "/projects/#{project.id}/protected_branches/#{branch_name}"
end
class Roles
diff --git a/qa/qa/resource/sandbox.rb b/qa/qa/resource/sandbox.rb
index 7b427af6b74..032ff65c58b 100644
--- a/qa/qa/resource/sandbox.rb
+++ b/qa/qa/resource/sandbox.rb
@@ -13,6 +13,7 @@ module QA
attribute :id
attribute :runners_token
+ attribute :name
def initialize
@path = Runtime::Namespace.sandbox_name
diff --git a/qa/qa/runtime/feature.rb b/qa/qa/runtime/feature.rb
index 5e948b5b850..579c2293c51 100644
--- a/qa/qa/runtime/feature.rb
+++ b/qa/qa/runtime/feature.rb
@@ -28,19 +28,11 @@ module QA
end
def enable_and_verify(key)
- Support::Retrier.retry_on_exception(sleep_interval: 2) do
- enable(key)
-
- is_enabled = false
-
- QA::Support::Waiter.wait_until(sleep_interval: 1) do
- is_enabled = enabled?(key)
- end
-
- raise SetFeatureError, "#{key} was not enabled!" unless is_enabled
+ set_and_verify(key, enable: true)
+ end
- QA::Runtime::Logger.info("Successfully enabled and verified feature flag: #{key}")
- end
+ def disable_and_verify(key)
+ set_and_verify(key, enable: false)
end
def enabled?(key)
@@ -75,6 +67,27 @@ module QA
end
end
+ # Change a feature flag and verify that the change was successful
+ # Arguments:
+ # key: The feature flag to set (as a string)
+ # enable: `true` to enable the flag, `false` to disable it
+ def set_and_verify(key, enable:)
+ Support::Retrier.retry_on_exception(sleep_interval: 2) do
+ enable ? enable(key) : disable(key)
+
+ is_enabled = nil
+
+ QA::Support::Waiter.wait_until(sleep_interval: 1) do
+ is_enabled = enabled?(key)
+ is_enabled == enable
+ end
+
+ raise SetFeatureError, "#{key} was not #{enable ? 'enabled' : 'disabled'}!" unless is_enabled == enable
+
+ QA::Runtime::Logger.info("Successfully #{enable ? 'enabled' : 'disabled'} and verified feature flag: #{key}")
+ end
+ end
+
def set_feature(key, value)
request = Runtime::API::Request.new(api_client, "/features/#{key}")
response = post(request.url, { value: value })
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb
new file mode 100644
index 00000000000..3bf6e156967
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module QA
+ context 'Create' do
+ describe 'First file using Web IDE' do
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'empty-project'
+ project.initialize_with_readme = false
+ end
+ end
+
+ let(:web_ide_url) { current_url + '-/ide/project/' + project.path_with_namespace }
+ let(:file_name) { 'the very first file.txt' }
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ it "creates the first file in an empty project via Web IDE" do
+ # In the first iteration, the test opens Web IDE by modifying the URL to address past regressions.
+ # Once the Web IDE button is introduced for empty projects, the test will be modified to go through UI.
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/27915 and https://gitlab.com/gitlab-org/gitlab/-/issues/27535.
+ page.visit(web_ide_url)
+
+ Page::Project::WebIDE::Edit.perform do |ide|
+ ide.create_first_file(file_name)
+ ide.commit_changes
+ end
+
+ project.visit!
+
+ Page::Project::Show.perform do |project|
+ expect(project).to have_file(file_name)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/spec/runtime/feature_spec.rb b/qa/spec/runtime/feature_spec.rb
index 94638d99b01..db3c2f65963 100644
--- a/qa/spec/runtime/feature_spec.rb
+++ b/qa/spec/runtime/feature_spec.rb
@@ -25,6 +25,21 @@ describe QA::Runtime::Feature do
end
end
+ describe '.enable_and_verify' do
+ it 'enables a feature flag' do
+ allow(described_class).to receive(:get).and_return(response_get)
+
+ expect(QA::Runtime::API::Request).to receive(:new)
+ .with(api_client, "/features/a-flag").and_return(request)
+ expect(described_class).to receive(:post)
+ .with(request.url, { value: true }).and_return(response_post)
+ expect(QA::Runtime::API::Request).to receive(:new)
+ .with(api_client, "/features").and_return(request)
+
+ subject.enable_and_verify('a-flag')
+ end
+ end
+
describe '.disable' do
it 'disables a feature flag' do
expect(QA::Runtime::API::Request)
@@ -40,6 +55,22 @@ describe QA::Runtime::Feature do
end
end
+ describe '.disable_and_verify' do
+ it 'disables a feature flag' do
+ allow(described_class).to receive(:get)
+ .and_return(Struct.new(:code, :body).new(200, '[{ "name": "a-flag", "state": "off" }]'))
+
+ expect(QA::Runtime::API::Request).to receive(:new)
+ .with(api_client, "/features/a-flag").and_return(request)
+ expect(described_class).to receive(:post)
+ .with(request.url, { value: false }).and_return(response_post)
+ expect(QA::Runtime::API::Request).to receive(:new)
+ .with(api_client, "/features").and_return(request)
+
+ subject.disable_and_verify('a-flag')
+ end
+ end
+
describe '.enabled?' do
it 'returns a feature flag state' do
expect(QA::Runtime::API::Request)
diff --git a/qa/spec/support/shared_examples/merge_with_code_owner_shared_examples.rb b/qa/spec/support/shared_examples/merge_with_code_owner_shared_examples.rb
new file mode 100644
index 00000000000..feaeb78815d
--- /dev/null
+++ b/qa/spec/support/shared_examples/merge_with_code_owner_shared_examples.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+module QA
+ shared_examples 'code owner merge request' do
+ let(:branch_name) { 'new-branch' }
+
+ it 'is approved and merged' do
+ # Require one approval from any eligible user on any branch
+ # This will confirm that this type of unrestricted approval is
+ # also satisfied when a code owner grants approval
+ Page::Project::Menu.perform(&:go_to_general_settings)
+ Page::Project::Settings::Main.perform do |main|
+ main.expand_merge_request_approvals_settings do |settings|
+ settings.set_default_number_of_approvals_required(1)
+ end
+ end
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add CODEOWNERS'
+ commit.add_files(
+ [
+ {
+ file_path: 'CODEOWNERS',
+ content: <<~CONTENT
+ README.md @#{codeowner}
+ CONTENT
+ }
+ ]
+ )
+ end
+
+ # Require approval from code owners on master
+ Resource::ProtectedBranch.fabricate! do |protected_branch|
+ protected_branch.project = project
+ protected_branch.branch_name = 'master'
+ protected_branch.new_branch = false
+ protected_branch.require_code_owner_approval = true
+ end
+
+ # Push a change to the file with a CODEOWNERS rule
+ Resource::Repository::Push.fabricate! do |push|
+ push.repository_http_uri = project.repository_http_location.uri
+ push.branch_name = branch_name
+ push.file_name = 'README.md'
+ push.file_content = 'Updated'
+ end
+
+ merge_request = Resource::MergeRequest.fabricate! do |merge_request|
+ merge_request.project = project
+ merge_request.target_new_branch = false
+ merge_request.source_branch = branch_name
+ merge_request.no_preparation = true
+ end
+
+ Flow::Login.while_signed_in(as: approver) do
+ merge_request.visit!
+
+ Page::MergeRequest::Show.perform do |merge_request|
+ expect(merge_request.approvals_required_from).to include('Code Owners')
+ expect(merge_request).not_to be_mergeable
+
+ merge_request.click_approve
+ merge_request.merge!
+
+ expect(merge_request).to be_merged
+ end
+ end
+ end
+ end
+end