2016-07-07 12:19:21 -04:00
|
|
|
require 'spec_helper'
|
|
|
|
|
2017-06-29 00:13:10 -04:00
|
|
|
describe 'Branches' do
|
2017-06-19 22:06:13 -04:00
|
|
|
let(:user) { create(:user) }
|
2017-07-24 18:51:14 -04:00
|
|
|
let(:project) { create(:project, :public, :repository) }
|
2016-07-07 12:19:21 -04:00
|
|
|
let(:repository) { project.repository }
|
|
|
|
|
2017-05-08 03:41:58 -04:00
|
|
|
context 'logged in as developer' do
|
2016-09-02 09:33:24 -04:00
|
|
|
before do
|
2017-06-19 22:06:13 -04:00
|
|
|
sign_in(user)
|
2017-12-22 03:18:28 -05:00
|
|
|
project.add_developer(user)
|
2016-09-02 09:33:24 -04:00
|
|
|
end
|
2016-07-07 12:19:21 -04:00
|
|
|
|
2017-11-15 09:56:36 -05:00
|
|
|
context 'on the projects with 6 active branches and 4 stale branches' do
|
|
|
|
let(:project) { create(:project, :public, :empty_repo) }
|
|
|
|
let(:repository) { project.repository }
|
|
|
|
let(:threshold) { Gitlab::Git::Branch::STALE_BRANCH_THRESHOLD }
|
|
|
|
|
|
|
|
before do
|
|
|
|
# Add 4 stale branches
|
|
|
|
(1..4).reverse_each do |i|
|
|
|
|
Timecop.freeze((threshold + i).ago) { create_file(message: "a commit in stale-#{i}", branch_name: "stale-#{i}") }
|
|
|
|
end
|
|
|
|
# Add 6 active branches
|
|
|
|
(1..6).each do |i|
|
|
|
|
Timecop.freeze((threshold - i).ago) { create_file(message: "a commit in active-#{i}", branch_name: "active-#{i}") }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'Overview page of the branches' do
|
|
|
|
it 'shows the first 5 active branches and the first 4 stale branches sorted by last updated' do
|
|
|
|
visit project_branches_path(project)
|
|
|
|
|
|
|
|
expect(page).to have_content(sorted_branches(repository, count: 5, sort_by: :updated_desc, state: 'active'))
|
|
|
|
expect(page).to have_content(sorted_branches(repository, count: 4, sort_by: :updated_desc, state: 'stale'))
|
|
|
|
|
|
|
|
expect(page).to have_link('Show more active branches', href: project_branches_filtered_path(project, state: 'active'))
|
|
|
|
expect(page).not_to have_content('Show more stale branches')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'Active branches page' do
|
|
|
|
it 'shows 6 active branches sorted by last updated' do
|
|
|
|
visit project_branches_filtered_path(project, state: 'active')
|
|
|
|
|
|
|
|
expect(page).to have_content(sorted_branches(repository, count: 6, sort_by: :updated_desc, state: 'active'))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'Stale branches page' do
|
|
|
|
it 'shows 4 active branches sorted by last updated' do
|
|
|
|
visit project_branches_filtered_path(project, state: 'stale')
|
|
|
|
|
|
|
|
expect(page).to have_content(sorted_branches(repository, count: 4, sort_by: :updated_desc, state: 'stale'))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'All branches page' do
|
|
|
|
it 'shows 10 branches sorted by last updated' do
|
|
|
|
visit project_branches_filtered_path(project, state: 'all')
|
|
|
|
|
|
|
|
expect(page).to have_content(sorted_branches(repository, count: 10, sort_by: :updated_desc))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with branches over more than one page' do
|
|
|
|
before do
|
|
|
|
allow(Kaminari.config).to receive(:default_per_page).and_return(5)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'shows only default_per_page active branches sorted by last updated' do
|
|
|
|
visit project_branches_filtered_path(project, state: 'active')
|
|
|
|
|
|
|
|
expect(page).to have_content(sorted_branches(repository, count: Kaminari.config.default_per_page, sort_by: :updated_desc, state: 'active'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'shows only default_per_page branches sorted by last updated on All branches' do
|
|
|
|
visit project_branches_filtered_path(project, state: 'all')
|
|
|
|
|
|
|
|
expect(page).to have_content(sorted_branches(repository, count: Kaminari.config.default_per_page, sort_by: :updated_desc))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'Find branches' do
|
|
|
|
it 'shows filtered branches', :js do
|
2017-06-29 13:06:35 -04:00
|
|
|
visit project_branches_path(project)
|
2016-07-07 12:19:21 -04:00
|
|
|
|
2017-11-15 09:56:36 -05:00
|
|
|
fill_in 'branch-search', with: 'fix'
|
|
|
|
find('#branch-search').native.send_keys(:enter)
|
|
|
|
|
|
|
|
expect(page).to have_content('fix')
|
|
|
|
expect(find('.all-branches')).to have_selector('li', count: 1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'Delete unprotected branch on Overview' do
|
|
|
|
it 'removes branch after confirmation', :js do
|
|
|
|
visit project_branches_filtered_path(project, state: 'all')
|
|
|
|
|
|
|
|
expect(all('.all-branches').last).to have_selector('li', count: 20)
|
|
|
|
accept_confirm { find('.js-branch-add-pdf-text-binary .btn-remove').click }
|
|
|
|
|
|
|
|
expect(all('.all-branches').last).to have_selector('li', count: 19)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'All branches page' do
|
|
|
|
it 'shows all the branches sorted by last updated by default' do
|
|
|
|
visit project_branches_filtered_path(project, state: 'all')
|
|
|
|
|
2017-09-15 07:25:12 -04:00
|
|
|
expect(page).to have_content(sorted_branches(repository, count: 20, sort_by: :updated_desc))
|
2016-09-02 09:33:24 -04:00
|
|
|
end
|
2017-03-13 12:00:07 -04:00
|
|
|
|
2017-06-28 15:38:00 -04:00
|
|
|
it 'sorts the branches by name' do
|
2017-11-15 09:56:36 -05:00
|
|
|
visit project_branches_filtered_path(project, state: 'all')
|
2017-06-28 15:38:00 -04:00
|
|
|
|
2017-07-28 12:52:40 -04:00
|
|
|
click_button "Last updated" # Open sorting dropdown
|
2017-06-28 15:38:00 -04:00
|
|
|
click_link "Name"
|
|
|
|
|
2017-09-15 07:25:12 -04:00
|
|
|
expect(page).to have_content(sorted_branches(repository, count: 20, sort_by: :name))
|
2017-06-28 15:38:00 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'sorts the branches by oldest updated' do
|
2017-11-15 09:56:36 -05:00
|
|
|
visit project_branches_filtered_path(project, state: 'all')
|
2017-06-28 15:38:00 -04:00
|
|
|
|
2017-07-28 12:52:40 -04:00
|
|
|
click_button "Last updated" # Open sorting dropdown
|
2017-06-28 15:38:00 -04:00
|
|
|
click_link "Oldest updated"
|
|
|
|
|
2017-09-15 07:25:12 -04:00
|
|
|
expect(page).to have_content(sorted_branches(repository, count: 20, sort_by: :updated_asc))
|
2016-09-02 09:33:24 -04:00
|
|
|
end
|
2017-03-13 12:00:07 -04:00
|
|
|
|
|
|
|
it 'avoids a N+1 query in branches index' do
|
2017-06-29 13:06:35 -04:00
|
|
|
control_count = ActiveRecord::QueryRecorder.new { visit project_branches_path(project) }.count
|
2017-03-13 12:00:07 -04:00
|
|
|
|
2017-06-19 22:06:13 -04:00
|
|
|
%w(one two three four five).each { |ref| repository.add_branch(user, ref, 'master') }
|
2017-03-13 12:00:07 -04:00
|
|
|
|
2017-11-15 09:56:36 -05:00
|
|
|
expect { visit project_branches_filtered_path(project, state: 'all') }.not_to exceed_query_limit(control_count)
|
2017-03-13 12:00:07 -04:00
|
|
|
end
|
2016-09-02 09:33:24 -04:00
|
|
|
end
|
|
|
|
|
2017-11-15 09:56:36 -05:00
|
|
|
describe 'Find branches on All branches' do
|
2017-10-03 04:35:01 -04:00
|
|
|
it 'shows filtered branches', :js do
|
2017-11-15 09:56:36 -05:00
|
|
|
visit project_branches_filtered_path(project, state: 'all')
|
2016-09-02 09:33:24 -04:00
|
|
|
|
|
|
|
fill_in 'branch-search', with: 'fix'
|
|
|
|
find('#branch-search').native.send_keys(:enter)
|
|
|
|
|
|
|
|
expect(page).to have_content('fix')
|
|
|
|
expect(find('.all-branches')).to have_selector('li', count: 1)
|
|
|
|
end
|
2016-07-07 12:19:21 -04:00
|
|
|
end
|
2017-05-08 03:41:58 -04:00
|
|
|
|
2017-11-15 09:56:36 -05:00
|
|
|
describe 'Delete unprotected branch on All branches' do
|
2017-10-03 04:35:01 -04:00
|
|
|
it 'removes branch after confirmation', :js do
|
2017-11-15 09:56:36 -05:00
|
|
|
visit project_branches_filtered_path(project, state: 'all')
|
2017-05-08 03:41:58 -04:00
|
|
|
|
|
|
|
fill_in 'branch-search', with: 'fix'
|
|
|
|
|
|
|
|
find('#branch-search').native.send_keys(:enter)
|
|
|
|
|
|
|
|
expect(page).to have_content('fix')
|
|
|
|
expect(find('.all-branches')).to have_selector('li', count: 1)
|
2017-11-02 15:04:27 -04:00
|
|
|
accept_confirm { find('.js-branch-fix .btn-remove').click }
|
2017-05-08 03:41:58 -04:00
|
|
|
|
|
|
|
expect(page).not_to have_content('fix')
|
|
|
|
expect(find('.all-branches')).to have_selector('li', count: 0)
|
|
|
|
end
|
|
|
|
end
|
2017-11-15 09:56:36 -05:00
|
|
|
|
|
|
|
context 'on project with 0 branch' do
|
|
|
|
let(:project) { create(:project, :public, :empty_repo) }
|
|
|
|
let(:repository) { project.repository }
|
|
|
|
|
|
|
|
describe '0 branches on Overview' do
|
|
|
|
it 'shows warning' do
|
|
|
|
visit project_branches_path(project)
|
|
|
|
|
|
|
|
expect(page).not_to have_selector('.all-branches')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-05-08 03:41:58 -04:00
|
|
|
end
|
|
|
|
|
2018-07-11 10:36:08 -04:00
|
|
|
context 'logged in as maintainer' do
|
2017-05-08 03:41:58 -04:00
|
|
|
before do
|
2017-06-19 22:06:13 -04:00
|
|
|
sign_in(user)
|
2018-07-11 10:36:08 -04:00
|
|
|
project.add_maintainer(user)
|
2017-05-08 03:41:58 -04:00
|
|
|
end
|
|
|
|
|
2017-07-18 12:55:48 -04:00
|
|
|
describe 'Initial branches page' do
|
|
|
|
it 'shows description for admin' do
|
2017-11-15 09:56:36 -05:00
|
|
|
visit project_branches_filtered_path(project, state: 'all')
|
2017-07-18 12:55:48 -04:00
|
|
|
|
|
|
|
expect(page).to have_content("Protected branches can be managed in project settings")
|
|
|
|
end
|
|
|
|
end
|
2018-04-06 12:27:12 -04:00
|
|
|
|
|
|
|
it 'shows the merge request button' do
|
|
|
|
visit project_branches_path(project)
|
|
|
|
|
|
|
|
page.within first('.all-branches li') do
|
|
|
|
expect(page).to have_content 'Merge request'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the project is archived' do
|
2018-04-11 17:14:02 -04:00
|
|
|
let(:project) { create(:project, :public, :repository, :archived) }
|
2018-04-06 12:27:12 -04:00
|
|
|
|
|
|
|
it 'does not show the merge request button when the project is archived' do
|
|
|
|
visit project_branches_path(project)
|
|
|
|
|
|
|
|
page.within first('.all-branches li') do
|
|
|
|
expect(page).not_to have_content 'Merge request'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-07-07 12:19:21 -04:00
|
|
|
end
|
|
|
|
|
2016-09-02 09:33:24 -04:00
|
|
|
context 'logged out' do
|
|
|
|
before do
|
2017-06-29 13:06:35 -04:00
|
|
|
visit project_branches_path(project)
|
2016-09-02 09:33:24 -04:00
|
|
|
end
|
2016-07-07 12:19:21 -04:00
|
|
|
|
2016-09-02 09:33:24 -04:00
|
|
|
it 'does not show merge request button' do
|
|
|
|
page.within first('.all-branches li') do
|
2018-04-06 12:27:12 -04:00
|
|
|
expect(page).not_to have_content 'Merge request'
|
2016-09-02 09:33:24 -04:00
|
|
|
end
|
2016-07-07 12:19:21 -04:00
|
|
|
end
|
|
|
|
end
|
2017-09-15 07:25:12 -04:00
|
|
|
|
2017-11-15 09:56:36 -05:00
|
|
|
def sorted_branches(repository, count:, sort_by:, state: nil)
|
|
|
|
branches = repository.branches_sorted_by(sort_by)
|
|
|
|
branches = branches.select { |b| state == 'active' ? b.active? : b.stale? } if state
|
2017-09-15 07:25:12 -04:00
|
|
|
sorted_branches =
|
2017-11-15 09:56:36 -05:00
|
|
|
branches.first(count).map do |branch|
|
2017-09-15 07:25:12 -04:00
|
|
|
Regexp.escape(branch.name)
|
|
|
|
end
|
|
|
|
|
|
|
|
Regexp.new(sorted_branches.join('.*'))
|
|
|
|
end
|
2017-11-15 09:56:36 -05:00
|
|
|
|
|
|
|
def create_file(message: 'message', branch_name:)
|
|
|
|
repository.create_file(user, generate(:branch), 'content', message: message, branch_name: branch_name)
|
|
|
|
end
|
2016-07-07 12:19:21 -04:00
|
|
|
end
|