diff options
-rw-r--r-- | app/views/projects/commits/_commit.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/protected_branches/_create_protected_branch.html.haml | 4 | ||||
-rw-r--r-- | app/views/projects/protected_branches/_update_protected_branch.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/protected_branches/shared/_branches_list.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/protected_branches/shared/_dropdown.html.haml | 4 | ||||
-rw-r--r-- | app/views/projects/protected_branches/shared/_index.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/protected_branches/shared/_protected_branch.html.haml | 2 | ||||
-rw-r--r-- | app/views/shared/_ref_switcher.html.haml | 4 | ||||
-rw-r--r-- | qa/qa.rb | 2 | ||||
-rw-r--r-- | qa/qa/factory/resource/branch.rb | 73 | ||||
-rw-r--r-- | qa/qa/git/repository.rb | 6 | ||||
-rw-r--r-- | qa/qa/page/project/settings/protected_branches.rb | 69 | ||||
-rw-r--r-- | qa/qa/page/project/settings/repository.rb | 6 | ||||
-rw-r--r-- | qa/qa/page/project/show.rb | 17 | ||||
-rw-r--r-- | qa/qa/specs/features/repository/protected_branches_spec.rb | 63 |
15 files changed, 246 insertions, 12 deletions
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index 289bfdd69bc..3fd0fa348b3 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -22,7 +22,7 @@ = author_avatar(commit, size: 36) .commit-detail.flex-list - .commit-content + .commit-content.qa-commit-content - if view_details && merge_request = link_to commit.title, project_commit_path(project, commit.id, merge_request_iid: merge_request.iid), class: "commit-row-message item-title" - else diff --git a/app/views/projects/protected_branches/_create_protected_branch.html.haml b/app/views/projects/protected_branches/_create_protected_branch.html.haml index 98d56a3e5c5..12ccae10260 100644 --- a/app/views/projects/protected_branches/_create_protected_branch.html.haml +++ b/app/views/projects/protected_branches/_create_protected_branch.html.haml @@ -7,8 +7,8 @@ - content_for :push_access_levels do .push_access_levels-container = dropdown_tag('Select', - options: { toggle_class: 'js-allowed-to-push wide', - dropdown_class: 'dropdown-menu-selectable capitalize-header', + options: { toggle_class: 'js-allowed-to-push qa-allowed-to-push-select wide', + dropdown_class: 'dropdown-menu-selectable qa-allowed-to-push-dropdown capitalize-header', data: { field_name: 'protected_branch[push_access_levels_attributes][0][access_level]', input_id: 'push_access_levels_attributes' }}) = render 'projects/protected_branches/shared/create_protected_branch' diff --git a/app/views/projects/protected_branches/_update_protected_branch.html.haml b/app/views/projects/protected_branches/_update_protected_branch.html.haml index c61b2951e1e..98363f2018a 100644 --- a/app/views/projects/protected_branches/_update_protected_branch.html.haml +++ b/app/views/projects/protected_branches/_update_protected_branch.html.haml @@ -6,5 +6,5 @@ %td = hidden_field_tag "allowed_to_push_#{protected_branch.id}", protected_branch.push_access_levels.first.access_level = dropdown_tag( (protected_branch.push_access_levels.first.humanize || 'Select') , - options: { toggle_class: 'js-allowed-to-push', dropdown_class: 'dropdown-menu-selectable js-allowed-to-push-container capitalize-header', + options: { toggle_class: 'js-allowed-to-push qa-allowed-to-push', dropdown_class: 'dropdown-menu-selectable js-allowed-to-push-container capitalize-header', data: { field_name: "allowed_to_push_#{protected_branch.id}", access_level_id: protected_branch.push_access_levels.first.id }}) diff --git a/app/views/projects/protected_branches/shared/_branches_list.html.haml b/app/views/projects/protected_branches/shared/_branches_list.html.haml index 300055a4207..d1ed438eb21 100644 --- a/app/views/projects/protected_branches/shared/_branches_list.html.haml +++ b/app/views/projects/protected_branches/shared/_branches_list.html.haml @@ -1,4 +1,4 @@ -.protected-branches-list.js-protected-branches-list +.protected-branches-list.js-protected-branches-list.qa-protected-branches-list - if @protected_branches.empty? .panel-heading %h3.panel-title diff --git a/app/views/projects/protected_branches/shared/_dropdown.html.haml b/app/views/projects/protected_branches/shared/_dropdown.html.haml index 74435236808..b3d6068039a 100644 --- a/app/views/projects/protected_branches/shared/_dropdown.html.haml +++ b/app/views/projects/protected_branches/shared/_dropdown.html.haml @@ -1,8 +1,8 @@ = f.hidden_field(:name) = dropdown_tag('Select branch or create wildcard', - options: { toggle_class: 'js-protected-branch-select js-filter-submit wide git-revision-dropdown-toggle', - filter: true, dropdown_class: "dropdown-menu-selectable git-revision-dropdown", placeholder: "Search protected branches", + options: { toggle_class: 'js-protected-branch-select js-filter-submit wide git-revision-dropdown-toggle qa-protected-branch-select', + filter: true, dropdown_class: "dropdown-menu-selectable git-revision-dropdown qa-protected-branch-dropdown", placeholder: "Search protected branches", footer_content: true, data: { show_no: true, show_any: true, show_upcoming: true, selected: params[:protected_branch_name], diff --git a/app/views/projects/protected_branches/shared/_index.html.haml b/app/views/projects/protected_branches/shared/_index.html.haml index 55d87c35a80..fd5c1aa342a 100644 --- a/app/views/projects/protected_branches/shared/_index.html.haml +++ b/app/views/projects/protected_branches/shared/_index.html.haml @@ -4,7 +4,7 @@ .settings-header %h4 Protected Branches - %button.btn.js-settings-toggle{ type: 'button' } + %button.btn.js-settings-toggle.qa-expand-protected-branches{ type: 'button' } = expanded ? 'Collapse' : 'Expand' %p Keep stable branches secure and force developers to use merge requests. diff --git a/app/views/projects/protected_branches/shared/_protected_branch.html.haml b/app/views/projects/protected_branches/shared/_protected_branch.html.haml index 10b81e42572..f5b21f0e887 100644 --- a/app/views/projects/protected_branches/shared/_protected_branch.html.haml +++ b/app/views/projects/protected_branches/shared/_protected_branch.html.haml @@ -2,7 +2,7 @@ %tr.js-protected-branch-edit-form{ data: { url: namespace_project_protected_branch_path(@project.namespace, @project, protected_branch) } } %td - %span.ref-name= protected_branch.name + %span.ref-name.qa-protected-branch-name= protected_branch.name - if @project.root_ref?(protected_branch.name) %span.label.label-info.prepend-left-5 default diff --git a/app/views/shared/_ref_switcher.html.haml b/app/views/shared/_ref_switcher.html.haml index 4c8c92d722a..f1c39b9e923 100644 --- a/app/views/shared/_ref_switcher.html.haml +++ b/app/views/shared/_ref_switcher.html.haml @@ -8,8 +8,8 @@ - @options && @options.each do |key, value| = hidden_field_tag key, value, id: nil .dropdown - = dropdown_toggle dropdown_toggle_text, { toggle: "dropdown", selected: dropdown_toggle_text, ref: @ref, refs_url: refs_project_path(@project, sort: 'updated_desc'), field_name: 'ref', submit_form_on_click: true, visit: true }, { toggle_class: "js-project-refs-dropdown" } - .dropdown-menu.dropdown-menu-selectable.git-revision-dropdown.dropdown-menu-paging{ class: ("dropdown-menu-align-right" if local_assigns[:align_right]) } + = dropdown_toggle dropdown_toggle_text, { toggle: "dropdown", selected: dropdown_toggle_text, ref: @ref, refs_url: refs_project_path(@project, sort: 'updated_desc'), field_name: 'ref', submit_form_on_click: true, visit: true }, { toggle_class: "js-project-refs-dropdown qa-branches-select" } + .dropdown-menu.dropdown-menu-selectable.git-revision-dropdown.dropdown-menu-paging.qa-branches-dropdown{ class: ("dropdown-menu-align-right" if local_assigns[:align_right]) } .dropdown-page-one = dropdown_title _("Switch branch/tag") = dropdown_filter _("Search branches and tags") @@ -31,6 +31,7 @@ module QA autoload :Project, 'qa/factory/resource/project' autoload :MergeRequest, 'qa/factory/resource/merge_request' autoload :DeployKey, 'qa/factory/resource/deploy_key' + autoload :Branch, 'qa/factory/resource/branch' autoload :SecretVariable, 'qa/factory/resource/secret_variable' autoload :Runner, 'qa/factory/resource/runner' autoload :PersonalAccessToken, 'qa/factory/resource/personal_access_token' @@ -132,6 +133,7 @@ module QA autoload :Repository, 'qa/page/project/settings/repository' autoload :CICD, 'qa/page/project/settings/ci_cd' autoload :DeployKeys, 'qa/page/project/settings/deploy_keys' + autoload :ProtectedBranches, 'qa/page/project/settings/protected_branches' autoload :SecretVariables, 'qa/page/project/settings/secret_variables' autoload :Runners, 'qa/page/project/settings/runners' autoload :MergeRequest, 'qa/page/project/settings/merge_request' diff --git a/qa/qa/factory/resource/branch.rb b/qa/qa/factory/resource/branch.rb new file mode 100644 index 00000000000..d0ef142e90d --- /dev/null +++ b/qa/qa/factory/resource/branch.rb @@ -0,0 +1,73 @@ +module QA + module Factory + module Resource + class Branch < Factory::Base + attr_accessor :project, :branch_name, :allow_to_push, :protected + + dependency Factory::Resource::Project, as: :project do |project| + project.name = 'protected-branch-project' + end + + product :name do + Page::Project::Settings::Repository.act do + expand_protected_branches(&:last_branch_name) + end + end + + product :push_allowance do + Page::Project::Settings::Repository.act do + expand_protected_branches(&:last_push_allowance) + end + end + + def initialize + @branch_name = 'test/branch' + @allow_to_push = true + @protected = false + end + + def fabricate! + project.visit! + + Factory::Repository::Push.fabricate! do |resource| + resource.project = project + resource.file_name = 'kick-off.txt' + resource.commit_message = 'First commit' + end + + branch = Factory::Repository::Push.fabricate! do |resource| + resource.project = project + resource.file_name = 'README.md' + resource.commit_message = 'Add readme' + resource.branch_name = "master:#{@branch_name}" + end + + Page::Project::Show.act { wait_for_push } + + # The upcoming process will make it access the Protected Branches page, + # select the already created branch and protect it according + # to `allow_to_push` variable. + return branch unless @protected + + Page::Menu::Side.act do + click_repository_settings + end + + Page::Project::Settings::Repository.perform do |setting| + setting.expand_protected_branches do |page| + page.select_branch(branch_name) + + if allow_to_push + page.allow_devs_and_masters_to_push + else + page.allow_no_one_to_push + end + + page.protect_branch + end + end + end + end + end + end +end diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb index b3150e8f3fa..2f9f06ba277 100644 --- a/qa/qa/git/repository.rb +++ b/qa/qa/git/repository.rb @@ -1,11 +1,14 @@ require 'cgi' require 'uri' +require 'open3' module QA module Git class Repository include Scenario::Actable + attr_reader :push_error + def self.perform(*args) Dir.mktmpdir do |dir| Dir.chdir(dir) { super } @@ -65,7 +68,8 @@ module QA end def push_changes(branch = 'master') - `git push #{@uri.to_s} #{branch} #{suppress_output}` + # capture3 returns stdout, stderr and status. + _, @push_error, _ = Open3.capture3("git push #{@uri} #{branch} #{suppress_output}") end def commits diff --git a/qa/qa/page/project/settings/protected_branches.rb b/qa/qa/page/project/settings/protected_branches.rb new file mode 100644 index 00000000000..f3563401124 --- /dev/null +++ b/qa/qa/page/project/settings/protected_branches.rb @@ -0,0 +1,69 @@ +module QA + module Page + module Project + module Settings + class ProtectedBranches < Page::Base + view 'app/views/projects/protected_branches/shared/_dropdown.html.haml' do + element :protected_branch_select + element :protected_branch_dropdown + end + + view 'app/views/projects/protected_branches/_create_protected_branch.html.haml' do + element :allowed_to_push_select + element :allowed_to_push_dropdown + end + + view 'app/views/projects/protected_branches/shared/_branches_list.html.haml' do + element :protected_branches_list + end + + view 'app/views/projects/protected_branches/shared/_protected_branch.html.haml' do + element :protected_branch_name + end + + def select_branch(branch_name) + click_element :protected_branch_select + + within_element(:protected_branch_dropdown) do + click_on branch_name + end + end + + def allow_no_one_to_push + allow_to_push('No one') + end + + def allow_devs_and_masters_to_push + allow_to_push('Developers + Masters') + end + + def protect_branch + click_on 'Protect' + end + + def last_branch_name + within_element(:protected_branches_list) do + all('.qa-protected-branch-name').last + end + end + + def last_push_allowance + within_element(:protected_branches_list) do + all('.qa-allowed-to-push').last + end + end + + private + + def allow_to_push(text) + click_element :allowed_to_push_select + + within_element(:allowed_to_push_dropdown) do + click_on text + end + end + end + end + end + end +end diff --git a/qa/qa/page/project/settings/repository.rb b/qa/qa/page/project/settings/repository.rb index 22362164a1a..30900e74e90 100644 --- a/qa/qa/page/project/settings/repository.rb +++ b/qa/qa/page/project/settings/repository.rb @@ -14,6 +14,12 @@ module QA DeployKeys.perform(&block) end end + + def expand_protected_branches(&block) + expand_section('Protected Branches') do + ProtectedBranches.perform(&block) + end + end end end end diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb index 0c7ad46d36b..c7e7ece792d 100644 --- a/qa/qa/page/project/show.rb +++ b/qa/qa/page/project/show.rb @@ -21,6 +21,11 @@ module QA element :new_issue_link, "link_to 'New issue', new_project_issue_path(@project)" end + view 'app/views/shared/_ref_switcher.html.haml' do + element :branches_select + element :branches_dropdown + end + def choose_repository_clone_http choose_repository_clone('HTTP', 'http') end @@ -44,6 +49,18 @@ module QA find('.qa-project-name').text end + def switch_to_branch(branch_name) + find_element(:branches_select).click + + within_element(:branches_dropdown) do + click_on branch_name + end + end + + def last_commit_content + find_element(:commit_content).text + end + def new_merge_request wait(reload: true) do has_css?(element_selector_css(:create_merge_request)) diff --git a/qa/qa/specs/features/repository/protected_branches_spec.rb b/qa/qa/specs/features/repository/protected_branches_spec.rb new file mode 100644 index 00000000000..88fa4994e32 --- /dev/null +++ b/qa/qa/specs/features/repository/protected_branches_spec.rb @@ -0,0 +1,63 @@ +module QA + feature 'branch protection support', :core do + given(:branch_name) { 'protected-branch' } + given(:commit_message) { 'Protected push commit message' } + given(:project) do + Factory::Resource::Project.fabricate! do |resource| + resource.name = 'protected-branch-project' + end + end + given(:location) do + Page::Project::Show.act do + choose_repository_clone_http + repository_location + end + end + + before do + Runtime::Browser.visit(:gitlab, Page::Main::Login) + Page::Main::Login.act { sign_in_using_credentials } + end + + scenario 'user is able to protect a branch' do + protected_branch = Factory::Resource::Branch.fabricate! do |resource| + resource.branch_name = branch_name + resource.project = project + resource.allow_to_push = true + resource.protected = true + end + + expect(protected_branch.name).to have_content(branch_name) + expect(protected_branch.push_allowance).to have_content('Developers + Masters') + end + + scenario 'users without authorization cannot push to protected branch' do + Factory::Resource::Branch.fabricate! do |resource| + resource.branch_name = branch_name + resource.project = project + resource.allow_to_push = false + resource.protected = true + end + + project.visit! + + Git::Repository.perform do |repository| + repository.location = location + repository.use_default_credentials + + repository.act do + clone + configure_identity('GitLab QA', 'root@gitlab.com') + checkout('protected-branch') + commit_file('README.md', 'readme content', 'Add a readme') + push_changes('protected-branch') + end + + expect(repository.push_error) + .to match(/remote\: GitLab\: You are not allowed to push code to protected branches on this project/) + expect(repository.push_error) + .to match(/\[remote rejected\] #{branch_name} -> #{branch_name} \(pre-receive hook declined\)/) + end + end + end +end |