diff options
34 files changed, 354 insertions, 68 deletions
diff --git a/Gemfile.lock b/Gemfile.lock index 0de8746109e..2f9d3bfc8ab 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -595,8 +595,8 @@ GEM premailer-rails (1.9.7) actionmailer (>= 3, < 6) premailer (~> 1.7, >= 1.7.9) - prometheus-client-mmap (0.7.0.beta5) - mmap2 (~> 2.2.6) + prometheus-client-mmap (0.7.0.beta8) + mmap2 (~> 2.2, >= 2.2.7) pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js index 386102032cb..6249521a3ab 100644 --- a/app/assets/javascripts/boards/components/board_sidebar.js +++ b/app/assets/javascripts/boards/components/board_sidebar.js @@ -37,7 +37,10 @@ gl.issueBoards.BoardSidebar = Vue.extend({ }, milestoneTitle() { return this.issue.milestone ? this.issue.milestone.title : 'No Milestone'; - } + }, + canRemove() { + return !this.list.preset; + }, }, watch: { detail: { diff --git a/app/assets/javascripts/boards/components/sidebar/remove_issue.js b/app/assets/javascripts/boards/components/sidebar/remove_issue.js index 5597f128b80..6a900d4abd0 100644 --- a/app/assets/javascripts/boards/components/sidebar/remove_issue.js +++ b/app/assets/javascripts/boards/components/sidebar/remove_issue.js @@ -46,8 +46,7 @@ gl.issueBoards.RemoveIssueBtn = Vue.extend({ }, template: ` <div - class="block list" - v-if="list.type !== 'closed'"> + class="block list"> <button class="btn btn-default btn-block" type="button" diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index e0a30d2648a..9b68584492d 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -340,6 +340,10 @@ const normalizeNewlines = function(str) { if (!noteEntity.valid) { if (noteEntity.errors.commands_only) { + if (noteEntity.commands_changes && + Object.keys(noteEntity.commands_changes).length > 0) { + $notesList.find('.system-note.being-posted').remove(); + } this.addFlash(noteEntity.errors.commands_only, 'notice', this.parentTimeline); this.refresh(); } diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index b58922626fa..b7ff63edb51 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -20,8 +20,6 @@ } .diff-content { - overflow: auto; - overflow-y: hidden; background: $white-light; color: $gl-text-color; border-radius: 0 0 3px 3px; diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb index 63d02b76f6b..ee108f010a6 100644 --- a/app/models/concerns/routable.rb +++ b/app/models/concerns/routable.rb @@ -103,8 +103,20 @@ module Routable def full_path return uncached_full_path unless RequestStore.active? - key = "routable/full_path/#{self.class.name}/#{self.id}" - RequestStore[key] ||= uncached_full_path + RequestStore[full_path_key] ||= uncached_full_path + end + + def expires_full_path_cache + RequestStore.delete(full_path_key) if RequestStore.active? + @full_path = nil + end + + def build_full_path + if parent && path + parent.full_path + '/' + path + else + path + end end private @@ -127,6 +139,10 @@ module Routable path_changed? || parent_changed? end + def full_path_key + @full_path_key ||= "routable/full_path/#{self.class.name}/#{self.id}" + end + def build_full_name if parent && name parent.human_name + ' / ' + name @@ -135,14 +151,6 @@ module Routable end end - def build_full_path - if parent && path - parent.full_path + '/' + path - else - path - end - end - def update_route prepare_route route.save diff --git a/app/models/project.rb b/app/models/project.rb index cf6515b9fa3..aa83cbffb52 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -964,6 +964,7 @@ class Project < ActiveRecord::Base begin gitlab_shell.mv_repository(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki") send_move_instructions(old_path_with_namespace) + expires_full_path_cache @old_path_with_namespace = old_path_with_namespace @@ -1074,16 +1075,16 @@ class Project < ActiveRecord::Base merge_requests.where(source_project_id: self.id) end - def create_repository + def create_repository(force: false) # Forked import is handled asynchronously - unless forked? - if gitlab_shell.add_repository(repository_storage_path, path_with_namespace) - repository.after_create - true - else - errors.add(:base, 'Failed to create repository via gitlab-shell') - false - end + return if forked? && !force + + if gitlab_shell.add_repository(repository_storage_path, path_with_namespace) + repository.after_create + true + else + errors.add(:base, 'Failed to create repository via gitlab-shell') + false end end diff --git a/app/services/delete_merged_branches_service.rb b/app/services/delete_merged_branches_service.rb index 3b611588466..5c9e2a16c71 100644 --- a/app/services/delete_merged_branches_service.rb +++ b/app/services/delete_merged_branches_service.rb @@ -10,6 +10,8 @@ class DeleteMergedBranchesService < BaseService branches = branches.select { |branch| project.repository.merged_to_root_ref?(branch) } # Prevent deletion of branches relevant to open merge requests branches -= merge_request_branch_names + # Prevent deletion of protected branches + branches -= project.protected_branches.pluck(:name) branches.each do |branch| DeleteBranchService.new(project, current_user).execute(branch) diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index fac3ac7a4c7..bc846e07f24 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -61,8 +61,12 @@ module MergeRequests MergeRequests::PostMergeService.new(project, current_user).execute(merge_request) if params[:should_remove_source_branch].present? || @merge_request.force_remove_source_branch? - DeleteBranchService.new(@merge_request.source_project, branch_deletion_user). - execute(merge_request.source_branch) + # Verify again that the source branch can be removed, since branch may be protected, + # or the source branch may have been updated. + if @merge_request.can_remove_source_branch?(branch_deletion_user) + DeleteBranchService.new(@merge_request.source_project, branch_deletion_user) + .execute(merge_request.source_branch) + end end end diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 1c24b27a870..fa4cbad3259 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -70,6 +70,7 @@ module Projects Gitlab::PagesTransfer.new.move_project(project.path, old_namespace.full_path, new_namespace.full_path) project.old_path_with_namespace = old_path + project.expires_full_path_cache SystemHooksService.new.execute_hooks_for(project, :transfer) end diff --git a/app/validators/dynamic_path_validator.rb b/app/validators/dynamic_path_validator.rb index 27ac60637fd..4688aabc2a8 100644 --- a/app/validators/dynamic_path_validator.rb +++ b/app/validators/dynamic_path_validator.rb @@ -26,7 +26,7 @@ class DynamicPathValidator < ActiveModel::EachValidator end def path_valid_for_record?(record, value) - full_path = record.respond_to?(:full_path) ? record.full_path : value + full_path = record.respond_to?(:build_full_path) ? record.build_full_path : value return true unless full_path diff --git a/app/views/projects/boards/components/_sidebar.html.haml b/app/views/projects/boards/components/_sidebar.html.haml index 24d76da6f06..09d70f658a3 100644 --- a/app/views/projects/boards/components/_sidebar.html.haml +++ b/app/views/projects/boards/components/_sidebar.html.haml @@ -23,4 +23,5 @@ = render "projects/boards/components/sidebar/labels" = render "projects/boards/components/sidebar/notifications" %remove-btn{ ":issue" => "issue", - ":list" => "list" } + ":list" => "list", + "v-if" => "canRemove" } diff --git a/app/views/shared/issuable/form/_merge_params.html.haml b/app/views/shared/issuable/form/_merge_params.html.haml index 271150ed318..03309722326 100644 --- a/app/views/shared/issuable/form/_merge_params.html.haml +++ b/app/views/shared/issuable/form/_merge_params.html.haml @@ -10,8 +10,7 @@ .col-sm-10.col-sm-offset-2 - if issuable.can_remove_source_branch?(current_user) .checkbox - - initial_checkbox_value = issuable.merge_params.key?('force_remove_source_branch') ? issuable.force_remove_source_branch? : true = label_tag 'merge_request[force_remove_source_branch]' do = hidden_field_tag 'merge_request[force_remove_source_branch]', '0', id: nil - = check_box_tag 'merge_request[force_remove_source_branch]', '1', initial_checkbox_value + = check_box_tag 'merge_request[force_remove_source_branch]', '1', issuable.force_remove_source_branch? Remove source branch when merge request is accepted. diff --git a/changelogs/unreleased/32885-unintentionally-removing-branch-when-merging-merge-request.yml b/changelogs/unreleased/32885-unintentionally-removing-branch-when-merging-merge-request.yml new file mode 100644 index 00000000000..313aeab91b5 --- /dev/null +++ b/changelogs/unreleased/32885-unintentionally-removing-branch-when-merging-merge-request.yml @@ -0,0 +1,4 @@ +--- +title: Set default for Remove source branch to false. +merge_request: !12576 +author: diff --git a/changelogs/unreleased/34097-issue-board-remove-from-board-button-when-viewing-an-issue-gives-js-error-and-fails.yml b/changelogs/unreleased/34097-issue-board-remove-from-board-button-when-viewing-an-issue-gives-js-error-and-fails.yml new file mode 100644 index 00000000000..c0ea75adfa0 --- /dev/null +++ b/changelogs/unreleased/34097-issue-board-remove-from-board-button-when-viewing-an-issue-gives-js-error-and-fails.yml @@ -0,0 +1,4 @@ +--- +title: Remove "Remove from board" button from backlog and closed list +merge_request: 12430 +author: diff --git a/changelogs/unreleased/dm-always-verify-source-branch-can-be-deleted.yml b/changelogs/unreleased/dm-always-verify-source-branch-can-be-deleted.yml new file mode 100644 index 00000000000..f2e1f412502 --- /dev/null +++ b/changelogs/unreleased/dm-always-verify-source-branch-can-be-deleted.yml @@ -0,0 +1,5 @@ +--- +title: Prevent accidental deletion of protected MR source branch by repeating checks + before actual deletion +merge_request: +author: diff --git a/changelogs/unreleased/fix-2801.yml b/changelogs/unreleased/fix-2801.yml new file mode 100644 index 00000000000..4f0aa06b6ba --- /dev/null +++ b/changelogs/unreleased/fix-2801.yml @@ -0,0 +1,4 @@ +--- +title: Expires full_path cache after a repository is renamed/transferred +merge_request: +author: diff --git a/changelogs/unreleased/tc-no-delete-protected-merged-branches.yml b/changelogs/unreleased/tc-no-delete-protected-merged-branches.yml new file mode 100644 index 00000000000..663a0349bac --- /dev/null +++ b/changelogs/unreleased/tc-no-delete-protected-merged-branches.yml @@ -0,0 +1,4 @@ +--- +title: Do not delete protected branches when deleting all merged branches +merge_request: 12624 +author: diff --git a/doc/install/database_mysql.md b/doc/install/database_mysql.md index 9a171d34671..37e9b3101ca 100644 --- a/doc/install/database_mysql.md +++ b/doc/install/database_mysql.md @@ -43,7 +43,7 @@ mysql> SET GLOBAL innodb_file_per_table=1, innodb_file_format=Barracuda, innodb_ mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_general_ci`; # Grant the GitLab user necessary permissions on the database -mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, CREATE TEMPORARY TABLES, DROP, INDEX, ALTER, LOCK TABLES, REFERENCES ON `gitlabhq_production`.* TO 'git'@'localhost'; +mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, CREATE TEMPORARY TABLES, DROP, INDEX, ALTER, LOCK TABLES, REFERENCES, TRIGGER ON `gitlabhq_production`.* TO 'git'@'localhost'; # Quit the database session mysql> \q diff --git a/doc/update/8.9-to-8.10.md b/doc/update/8.9-to-8.10.md index d6b2f11d49a..42132f690d8 100644 --- a/doc/update/8.9-to-8.10.md +++ b/doc/update/8.9-to-8.10.md @@ -156,7 +156,7 @@ See [smtp_settings.rb.sample] as an example. Ensure you're still up-to-date with the latest init script changes: sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab - + For Ubuntu 16.04.1 LTS: sudo systemctl daemon-reload diff --git a/doc/update/9.1-to-9.2.md b/doc/update/9.1-to-9.2.md index 19db6e5763e..225a4dcc924 100644 --- a/doc/update/9.1-to-9.2.md +++ b/doc/update/9.1-to-9.2.md @@ -70,7 +70,27 @@ curl --location https://yarnpkg.com/install.sh | bash - More information can be found on the [yarn website](https://yarnpkg.com/en/docs/install). -### 5. Get latest code +### 5. Update Go + +NOTE: GitLab 9.2 and higher only supports Go 1.8.3 and dropped support for Go +1.5.x through 1.7.x. Be sure to upgrade your installation if necessary. + +You can check which version you are running with `go version`. + +Download and install Go: + +```bash +# Remove former Go installation folder +sudo rm -rf /usr/local/go + +curl --remote-name --progress https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz +echo '1862f4c3d3907e59b04a757cfda0ea7aa9ef39274af99a784f5be843c80c6772 go1.8.3.linux-amd64.tar.gz' | shasum -a256 -c - && \ + sudo tar -C /usr/local -xzf go1.8.3.linux-amd64.tar.gz +sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/ +rm go1.8.3.linux-amd64.tar.gz +``` + +### 6. Get latest code ```bash cd /home/git/gitlab @@ -97,7 +117,7 @@ cd /home/git/gitlab sudo -u git -H git checkout 9-2-stable-ee ``` -### 6. Update gitlab-shell +### 7. Update gitlab-shell ```bash cd /home/git/gitlab-shell @@ -107,11 +127,10 @@ sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_SHELL_VERSION) sudo -u git -H bin/compile ``` -### 7. Update gitlab-workhorse +### 8. Update gitlab-workhorse -Install and compile gitlab-workhorse. This requires -[Go 1.5](https://golang.org/dl) which should already be on your system from -GitLab 8.1. GitLab-Workhorse uses [GNU Make](https://www.gnu.org/software/make/). +Install and compile gitlab-workhorse. GitLab-Workhorse uses +[GNU Make](https://www.gnu.org/software/make/). If you are not using Linux you may have to run `gmake` instead of `make` below. @@ -123,7 +142,7 @@ sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_WORKHORSE_VERSION) sudo -u git -H make ``` -### 8. Update configuration files +### 9. Update configuration files #### New configuration options for `gitlab.yml` @@ -197,7 +216,7 @@ For Ubuntu 16.04.1 LTS: sudo systemctl daemon-reload ``` -### 9. Install libs, migrations, etc. +### 10. Install libs, migrations, etc. ```bash cd /home/git/gitlab @@ -223,7 +242,7 @@ sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production **MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md). -### 10. Optional: install Gitaly +### 11. Optional: install Gitaly Gitaly is still an optional component of GitLab. If you want to save time during your 9.2 upgrade **you can skip this step**. @@ -240,14 +259,14 @@ sudo -u git -H git checkout v$(</home/git/gitlab/GITALY_SERVER_VERSION) sudo -u git -H make ``` -### 11. Start application +### 12. Start application ```bash sudo service gitlab start sudo service nginx restart ``` -### 12. Check application status +### 13. Check application status Check if GitLab and its environment are configured correctly: diff --git a/doc/update/9.2-to-9.3.md b/doc/update/9.2-to-9.3.md index 8fbcc892fd5..097b996ec31 100644 --- a/doc/update/9.2-to-9.3.md +++ b/doc/update/9.2-to-9.3.md @@ -72,8 +72,8 @@ More information can be found on the [yarn website](https://yarnpkg.com/en/docs/ ### 5. Update Go -NOTE: GitLab 9.3 and higher only supports Go 1.8.3 and dropped support for Go 1.5.x through 1.7.x. Be -sure to upgrade your installation if necessary +NOTE: GitLab 9.2 and higher only supports Go 1.8.3 and dropped support for Go +1.5.x through 1.7.x. Be sure to upgrade your installation if necessary. You can check which version you are running with `go version`. @@ -129,9 +129,8 @@ sudo -u git -H bin/compile ### 8. Update gitlab-workhorse -Install and compile gitlab-workhorse. This requires -[Go 1.5](https://golang.org/dl) which should already be on your system from -GitLab 8.1. GitLab-Workhorse uses [GNU Make](https://www.gnu.org/software/make/). +Install and compile gitlab-workhorse. GitLab-Workhorse uses +[GNU Make](https://www.gnu.org/software/make/). If you are not using Linux you may have to run `gmake` instead of `make` below. @@ -157,7 +156,16 @@ sudo -u git -H git checkout v$(</home/git/gitlab/GITALY_SERVER_VERSION) sudo -u git -H make ``` -### 10. Update configuration files +### 10. Update MySQL permissions + +If you are using MySQL you need to grant the GitLab user the necessary +permissions on the database: + +```bash +mysql -u root -p -e "GRANT TRIGGER ON \`gitlabhq_production\`.* TO 'git'@'localhost';" +``` + +### 11. Update configuration files #### New configuration options for `gitlab.yml` @@ -231,7 +239,7 @@ For Ubuntu 16.04.1 LTS: sudo systemctl daemon-reload ``` -### 11. Install libs, migrations, etc. +### 12. Install libs, migrations, etc. ```bash cd /home/git/gitlab @@ -257,14 +265,14 @@ sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production **MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md). -### 12. Start application +### 13. Start application ```bash sudo service gitlab start sudo service nginx restart ``` -### 13. Check application status +### 14. Check application status Check if GitLab and its environment are configured correctly: diff --git a/lib/gitlab/gitaly_client/ref.rb b/lib/gitlab/gitaly_client/ref.rb index 4ab7def12a8..0d18ad3af02 100644 --- a/lib/gitlab/gitaly_client/ref.rb +++ b/lib/gitlab/gitaly_client/ref.rb @@ -60,6 +60,8 @@ module Gitlab end def sort_by_param(sort_by) + sort_by = 'name' if sort_by == 'name_asc' + enum_value = Gitaly::FindLocalBranchesRequest::SortBy.resolve(sort_by.upcase.to_sym) raise ArgumentError, "Invalid sort_by key `#{sort_by}`" unless enum_value enum_value diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index 235e4899707..eeafa95acd5 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -79,6 +79,22 @@ describe 'Issue Boards', feature: true, js: true do end end + it 'does not show remove button for backlog or closed issues' do + create(:issue, project: project) + create(:issue, :closed, project: project) + + visit namespace_project_board_path(project.namespace, project, board) + wait_for_requests + + click_card(find('.board:nth-child(1)').first('.card')) + + expect(find('.issue-boards-sidebar')).not_to have_button 'Remove from board' + + click_card(find('.board:nth-child(3)').first('.card')) + + expect(find('.issue-boards-sidebar')).not_to have_button 'Remove from board' + end + context 'assignee' do it 'updates the issues assignee' do click_card(card) diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb index 7668ce5f8be..20e3d41c655 100644 --- a/spec/features/projects/branches_spec.rb +++ b/spec/features/projects/branches_spec.rb @@ -20,10 +20,48 @@ describe 'Branches', feature: true do it 'shows all the branches' do visit namespace_project_branches_path(project.namespace, project) - repository.branches { |branch| expect(page).to have_content("#{branch.name}") } + repository.branches_sorted_by(:name).first(20).each do |branch| + expect(page).to have_content("#{branch.name}") + end expect(page).to have_content("Protected branches can be managed in project settings") end + it 'sorts the branches by name' do + visit namespace_project_branches_path(project.namespace, project) + + click_button "Name" # Open sorting dropdown + click_link "Name" + + sorted = repository.branches_sorted_by(:name).first(20).map do |branch| + Regexp.escape(branch.name) + end + expect(page).to have_content(/#{sorted.join(".*")}/) + end + + it 'sorts the branches by last updated' do + visit namespace_project_branches_path(project.namespace, project) + + click_button "Name" # Open sorting dropdown + click_link "Last updated" + + sorted = repository.branches_sorted_by(:updated_desc).first(20).map do |branch| + Regexp.escape(branch.name) + end + expect(page).to have_content(/#{sorted.join(".*")}/) + end + + it 'sorts the branches by oldest updated' do + visit namespace_project_branches_path(project.namespace, project) + + click_button "Name" # Open sorting dropdown + click_link "Oldest updated" + + sorted = repository.branches_sorted_by(:updated_asc).first(20).map do |branch| + Regexp.escape(branch.name) + end + expect(page).to have_content(/#{sorted.join(".*")}/) + end + it 'avoids a N+1 query in branches index' do control_count = ActiveRecord::QueryRecorder.new { visit namespace_project_branches_path(project.namespace, project) }.count diff --git a/spec/javascripts/datetime_utility_spec.js b/spec/javascripts/datetime_utility_spec.js index c82ad0bea48..864237b4527 100644 --- a/spec/javascripts/datetime_utility_spec.js +++ b/spec/javascripts/datetime_utility_spec.js @@ -16,6 +16,10 @@ import '~/lib/utils/datetime_utility'; const date = new Date(); date.setFullYear(date.getFullYear() + 1); + // Add a day to prevent a transient error. If date is even 1 second + // short of a full year, timeFor will return '11 months remaining' + date.setDate(date.getDate() + 1); + expect( gl.utils.timeFor(date), ).toBe('1 year remaining'); diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index 0ae0b2fd103..470193b50f7 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -523,6 +523,51 @@ import '~/notes'; }); }); + describe('postComment with Slash commands', () => { + const sampleComment = '/assign @root\n/award :100:'; + const note = { + commands_changes: { + assignee_id: 1, + emoji_award: '100' + }, + errors: { + commands_only: ['Commands applied'] + }, + valid: false + }; + let $form; + let $notesContainer; + + beforeEach(() => { + this.notes = new Notes('', []); + window.gon.current_username = 'root'; + window.gon.current_user_fullname = 'Administrator'; + gl.awardsHandler = { + addAwardToEmojiBar: () => {}, + scrollToAwards: () => {} + }; + gl.GfmAutoComplete = { + dataSources: { + commands: '/root/test-project/autocomplete_sources/commands' + } + }; + $form = $('form.js-main-target-form'); + $notesContainer = $('ul.main-notes-list'); + $form.find('textarea.js-note-text').val(sampleComment); + }); + + it('should remove slash command placeholder when comment with slash commands is done posting', () => { + const deferred = $.Deferred(); + spyOn($, 'ajax').and.returnValue(deferred.promise()); + spyOn(gl.awardsHandler, 'addAwardToEmojiBar').and.callThrough(); + $('.js-comment-button').click(); + + expect($notesContainer.find('.system-note.being-posted').length).toEqual(1); // Placeholder shown + deferred.resolve(note); + expect($notesContainer.find('.system-note.being-posted').length).toEqual(0); // Placeholder removed + }); + }); + describe('update comment with script tags', () => { const sampleComment = '<script></script>'; const updatedComment = '<script></script>'; diff --git a/spec/lib/gitlab/gitaly_client/ref_spec.rb b/spec/lib/gitlab/gitaly_client/ref_spec.rb index d8cd2dcbd2a..8dd2e812719 100644 --- a/spec/lib/gitlab/gitaly_client/ref_spec.rb +++ b/spec/lib/gitlab/gitaly_client/ref_spec.rb @@ -64,6 +64,15 @@ describe Gitlab::GitalyClient::Ref do client.local_branches(sort_by: 'updated_desc') end + it 'translates known mismatches on sort param values' do + expect_any_instance_of(Gitaly::Ref::Stub) + .to receive(:find_local_branches) + .with(gitaly_request_with_params(sort_by: :NAME)) + .and_return([]) + + client.local_branches(sort_by: 'name_asc') + end + it 'raises an argument error if an invalid sort_by parameter is passed' do expect { client.local_branches(sort_by: 'invalid_sort') }.to raise_error(ArgumentError) end diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb index 0e10d91836d..6bdd9daca0f 100644 --- a/spec/models/concerns/routable_spec.rb +++ b/spec/models/concerns/routable_spec.rb @@ -141,6 +141,19 @@ describe Group, 'Routable' do end end + describe '#expires_full_path_cache' do + context 'with RequestStore active', :request_store do + it 'expires the full_path cache' do + expect(group.full_path).to eq('foo') + + group.route.update(path: 'bar', name: 'bar') + group.expires_full_path_cache + + expect(group.full_path).to eq('bar') + end + end + end + describe '#full_name' do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index d97866d695d..96b98e4bb8b 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1209,6 +1209,8 @@ describe Project, models: true do expect(project).to receive(:expire_caches_before_rename) + expect(project).to receive(:expires_full_path_cache) + project.rename_repo end @@ -1312,12 +1314,25 @@ describe Project, models: true do end context 'using a forked repository' do - it 'does nothing' do - expect(project).to receive(:forked?).and_return(true) + before do + allow(project).to receive(:forked?).and_return(true) + end + + it 'does not create the repository if the force flag is false' do expect(shell).not_to receive(:add_repository) project.create_repository end + + it 'creates the repository if the force flag is true' do + expect(shell).to receive(:add_repository). + with(project.repository_storage_path, project.path_with_namespace). + and_return(true) + + expect(project.repository).to receive(:after_create) + + expect(project.create_repository(force: true)).to eq(true) + end end end diff --git a/spec/services/delete_merged_branches_service_spec.rb b/spec/services/delete_merged_branches_service_spec.rb index cae74df9c90..fe21ca0b3cb 100644 --- a/spec/services/delete_merged_branches_service_spec.rb +++ b/spec/services/delete_merged_branches_service_spec.rb @@ -24,6 +24,14 @@ describe DeleteMergedBranchesService, services: true do expect(project.repository.branch_names).to include('master') end + it 'keeps protected branches' do + create(:protected_branch, project: project, name: 'improve/awesome') + + service.execute + + expect(project.repository.branch_names).to include('improve/awesome') + end + context 'user without rights' do let(:user) { create(:user) } diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index d96f819e66a..b33a0ca3a32 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe MergeRequests::MergeService, services: true do let(:user) { create(:user) } let(:user2) { create(:user) } - let(:merge_request) { create(:merge_request, assignee: user2) } + let(:merge_request) { create(:merge_request, :simple, author: user2, assignee: user2) } let(:project) { merge_request.project } before do @@ -131,18 +131,65 @@ describe MergeRequests::MergeService, services: true do it { expect(todo).to be_done } end - context 'remove source branch by author' do - let(:service) do - merge_request.merge_params['force_remove_source_branch'] = '1' - merge_request.save! - MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') + context 'source branch removal' do + context 'when the source branch is protected' do + let(:service) do + MergeRequests::MergeService.new(project, user, should_remove_source_branch: '1') + end + + before do + create(:protected_branch, project: project, name: merge_request.source_branch) + end + + it 'does not delete the source branch' do + expect(DeleteBranchService).not_to receive(:new) + service.execute(merge_request) + end end - it 'removes the source branch' do - expect(DeleteBranchService).to receive(:new). - with(merge_request.source_project, merge_request.author). - and_call_original - service.execute(merge_request) + context 'when the source branch is the default branch' do + let(:service) do + MergeRequests::MergeService.new(project, user, should_remove_source_branch: '1') + end + + before do + allow(project).to receive(:root_ref?).with(merge_request.source_branch).and_return(true) + end + + it 'does not delete the source branch' do + expect(DeleteBranchService).not_to receive(:new) + service.execute(merge_request) + end + end + + context 'when the source branch can be removed' do + context 'when MR author set the source branch to be removed' do + let(:service) do + merge_request.merge_params['force_remove_source_branch'] = '1' + merge_request.save! + MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') + end + + it 'removes the source branch using the author user' do + expect(DeleteBranchService).to receive(:new) + .with(merge_request.source_project, merge_request.author) + .and_call_original + service.execute(merge_request) + end + end + + context 'when MR merger set the source branch to be removed' do + let(:service) do + MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message', should_remove_source_branch: '1') + end + + it 'removes the source branch using the current user' do + expect(DeleteBranchService).to receive(:new) + .with(merge_request.source_project, user) + .and_call_original + service.execute(merge_request) + end + end end end diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index b957517c715..47161b2b2b1 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -19,6 +19,18 @@ describe Projects::TransferService, services: true do it { expect(project.namespace).to eq(group) } end + context 'when transfer succeeds' do + before do + group.add_owner(user) + end + + it 'expires full_path cache' do + expect(project).to receive(:expires_full_path_cache) + + transfer_project(project, user, group) + end + end + context 'namespace -> no namespace' do before do @result = transfer_project(project, user, nil) diff --git a/spec/validators/dynamic_path_validator_spec.rb b/spec/validators/dynamic_path_validator_spec.rb index 8dbf3eecd23..8bd5306ff98 100644 --- a/spec/validators/dynamic_path_validator_spec.rb +++ b/spec/validators/dynamic_path_validator_spec.rb @@ -84,5 +84,14 @@ describe DynamicPathValidator do expect(group.errors[:path]).to include('users is a reserved name') end + + it 'updating to an invalid path is not allowed' do + project = create(:empty_project) + project.path = 'update' + + validator.validate_each(project, :path, 'update') + + expect(project.errors[:path]).to include('update is a reserved name') + end end end |