From 54c514f24ee00d885ec633a137a78a4cc71c6781 Mon Sep 17 00:00:00 2001 From: Patricio Cano Date: Wed, 29 Jun 2016 11:55:23 -0500 Subject: [PATCH 001/335] Add 2FA check to the OAuth authentication mechanism --- app/controllers/omniauth_callbacks_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index f35d631df0c..619a76ebfd9 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -107,6 +107,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController # Only allow properly saved users to login. if @user.persisted? && @user.valid? log_audit_event(@user, with: oauth['provider']) + prompt_for_two_factor(@user) and return if @user.two_factor_enabled? sign_in_and_redirect(@user) else error_message = @user.errors.full_messages.to_sentence From e8c787bb24be3a169b165066ccedf709bee85414 Mon Sep 17 00:00:00 2001 From: Max Raab Date: Thu, 30 Jun 2016 18:29:55 +0200 Subject: [PATCH 002/335] Remove not released status --- doc/ci/yaml/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index d2d1b04f893..cb32920a6df 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -133,7 +133,7 @@ builds, including deploy builds. This can be an array or a multi-line string. ### after_script >**Note:** -Introduced in GitLab 8.7 and requires Gitlab Runner v1.2 (not yet released) +Introduced in GitLab 8.7 and requires Gitlab Runner v1.2 `after_script` is used to define the command that will be run after for all builds. This has to be an array or a multi-line string. From 2886ebfb135e00ce9cc77914155d5974e14fed18 Mon Sep 17 00:00:00 2001 From: winniehell Date: Tue, 21 Jun 2016 23:10:24 +0200 Subject: [PATCH 003/335] Remove `pinTo` from `Flash` and make inline flash messages look nicer (!4854) --- CHANGELOG | 1 + app/assets/javascripts/flash.js.coffee | 30 +++++++++++-------- app/assets/javascripts/notes.js.coffee | 8 ++--- app/assets/stylesheets/framework/flash.scss | 22 ++++++++++++-- app/views/layouts/_flash.html.haml | 2 +- .../projects/notes/_notes_with_form.html.haml | 2 ++ .../fixtures/issues_show.html.haml | 2 +- 7 files changed, 46 insertions(+), 21 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4b754c2aba3..6974b388804 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ v 8.10.0 (unreleased) - Replace Haml with Hamlit to make view rendering faster. !3666 - Refactor repository paths handling to allow multiple git mount points - Add Application Setting to configure default Repository Path for new projects + - Remove pinTo from Flash and make inline flash messages look nicer !4854 (winniehell) - Wrap code blocks on Activies and Todos page. !4783 (winniehell) - Align flash messages with left side of page content !4959 (winniehell) - Display last commit of deleted branch in push events !4699 (winniehell) diff --git a/app/assets/javascripts/flash.js.coffee b/app/assets/javascripts/flash.js.coffee index b76d214790a..5a493041538 100644 --- a/app/assets/javascripts/flash.js.coffee +++ b/app/assets/javascripts/flash.js.coffee @@ -1,24 +1,28 @@ class @Flash - constructor: (message, type = 'alert')-> - @flash = $(".flash-container") - @flash.html("") + hideFlash = -> $(@).fadeOut() - innerDiv = $('
', + constructor: (message, type = 'alert', parent = null)-> + if parent + @flashContainer = parent.find('.flash-container') + else + @flashContainer = $('.flash-container-page') + + @flashContainer.html('') + + flash = $('
', class: "flash-#{type}" ) - innerDiv.appendTo(".flash-container") + flash.on 'click', hideFlash - textDiv = $("
", - class: "flash-text", + textDiv = $('
', + class: 'flash-text', text: message ) - textDiv.appendTo(innerDiv) + textDiv.appendTo(flash) - if @flash.parent().hasClass('content-wrapper') + if @flashContainer.parent().hasClass('content-wrapper') textDiv.addClass('container-fluid container-limited') - @flash.click -> $(@).fadeOut() - @flash.show() + flash.appendTo(@flashContainer) + @flashContainer.show() - pinTo: (selector) -> - @flash.detach().appendTo(selector) diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index 17f7e180127..ccfed498f2d 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -167,8 +167,7 @@ class @Notes renderNote: (note) -> unless note.valid if note.award - flash = new Flash('You have already awarded this emoji!', 'alert') - flash.pinTo('.header-content') + new Flash('You have already awarded this emoji!', 'alert') return if note.award @@ -293,6 +292,8 @@ class @Notes form.find("#note_line_code").remove() form.find("#note_type").remove() + @parentTimeline = form.parents('.timeline') + ### General note form setup. @@ -323,8 +324,7 @@ class @Notes @renderNote(note) addNoteError: (xhr, note, status) => - flash = new Flash('Your comment could not be submitted! Please check your network connection and try again.', 'alert') - flash.pinTo('.md-area') + new Flash('Your comment could not be submitted! Please check your network connection and try again.', 'alert', @parentTimeline) ### Called in response to the new note form being submitted diff --git a/app/assets/stylesheets/framework/flash.scss b/app/assets/stylesheets/framework/flash.scss index a951a2b97fe..0c21d0240b3 100644 --- a/app/assets/stylesheets/framework/flash.scss +++ b/app/assets/stylesheets/framework/flash.scss @@ -1,8 +1,8 @@ .flash-container { cursor: pointer; margin: 0; + margin-bottom: $gl-padding; font-size: 14px; - width: 100%; z-index: 100; .flash-notice { @@ -18,9 +18,27 @@ } .flash-notice, .flash-alert { - .container-fluid.flash-text { + border-radius: $border-radius-default; + + .container-fluid.container-limited.flash-text { background: transparent; } } + + &.flash-container-page { + margin-bottom: 0; + + .flash-notice, .flash-alert { + border-radius: 0; + } + } +} + +@media (max-width: $screen-md-min) { + ul.notes { + .flash-container.timeline-content { + margin-left: 0; + } + } } diff --git a/app/views/layouts/_flash.html.haml b/app/views/layouts/_flash.html.haml index cc8ea066cb9..3612f1ce5c6 100644 --- a/app/views/layouts/_flash.html.haml +++ b/app/views/layouts/_flash.html.haml @@ -1,4 +1,4 @@ -.flash-container +.flash-container.flash-container-page - if alert .flash-alert = alert diff --git a/app/views/projects/notes/_notes_with_form.html.haml b/app/views/projects/notes/_notes_with_form.html.haml index 1c39ce897a3..56d302fab82 100644 --- a/app/views/projects/notes/_notes_with_form.html.haml +++ b/app/views/projects/notes/_notes_with_form.html.haml @@ -2,6 +2,8 @@ = render "projects/notes/notes" %ul.notes.notes-form.timeline %li.timeline-entry + .flash-container.timeline-content + - if can? current_user, :create_note, @project .timeline-icon.hidden-xs.hidden-sm %a.author_link{ href: user_path(current_user) } diff --git a/spec/javascripts/fixtures/issues_show.html.haml b/spec/javascripts/fixtures/issues_show.html.haml index 470cabeafbb..06c2ab1e823 100644 --- a/spec/javascripts/fixtures/issues_show.html.haml +++ b/spec/javascripts/fixtures/issues_show.html.haml @@ -1,7 +1,7 @@ :css .hidden { display: none !important; } -.flash-container +.flash-container.flash-container-page .flash-alert .flash-notice From de1578185ecc0a439d877dbe1bc39a15e653c04b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Jul 2016 18:09:17 +0200 Subject: [PATCH 004/335] Remove icons from some buttons which already has text Signed-off-by: Dmitriy Zaporozhets --- app/views/groups/milestones/index.html.haml | 1 - app/views/groups/projects.html.haml | 1 - app/views/shared/milestones/_summary.html.haml | 1 - 3 files changed, 3 deletions(-) diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml index 121a7de3ad7..a8fdbd8c426 100644 --- a/app/views/groups/milestones/index.html.haml +++ b/app/views/groups/milestones/index.html.haml @@ -6,7 +6,6 @@ .nav-controls - if can?(current_user, :admin_milestones, @group) = link_to new_group_milestone_path(@group), class: "btn btn-new" do - = icon('plus') New Milestone .row-content-block diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml index c2f2d9912f7..33fee334d93 100644 --- a/app/views/groups/projects.html.haml +++ b/app/views/groups/projects.html.haml @@ -7,7 +7,6 @@ - if can? current_user, :admin_group, @group .controls = link_to new_project_path(namespace_id: @group.id), class: "btn btn-sm btn-success" do - = icon('plus') New Project %ul.well-list - @projects.each do |project| diff --git a/app/views/shared/milestones/_summary.html.haml b/app/views/shared/milestones/_summary.html.haml index 975c74f4ea6..dee2472fa79 100644 --- a/app/views/shared/milestones/_summary.html.haml +++ b/app/views/shared/milestones/_summary.html.haml @@ -26,7 +26,6 @@ %span.pull-right.tab-issues-buttons - if project && can?(current_user, :create_issue, project) = link_to new_namespace_project_issue_path(project.namespace, project, issue: { milestone_id: milestone.id }), class: "btn btn-grouped", title: "New Issue" do - %i.fa.fa-plus New Issue = link_to 'Browse Issues', milestones_browse_issuables_path(milestone, type: :issues), class: "btn btn-grouped" %span.pull-right.tab-merge-requests-buttons.hidden From c674c119ee463a2bfd89dfe30e6b745dfd1ae11f Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 1 Jul 2016 09:27:34 +0100 Subject: [PATCH 005/335] Correctly shows close button on merge requests Closes #19403 --- app/helpers/issues_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 72bd1fbbd81..46334f939d2 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -102,7 +102,7 @@ module IssuesHelper end def issue_button_visibility(issue, closed) - return 'hidden' if issue.closed? == closed + return 'hidden' if issue.closed? == closed || (issue.try(:merged?) == closed && !issue.closed?) end def merge_requests_sentence(merge_requests) From a445630ff353bdd9c5be24ccfd3380c71d3901d1 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 4 Jul 2016 12:38:01 +0100 Subject: [PATCH 006/335] Added day name to contributions calendar Closes #19367 --- CHANGELOG | 1 + app/assets/javascripts/lib/utils/datetime_utility.js.coffee | 4 ++++ app/assets/javascripts/users/calendar.js.coffee | 5 +++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5f593336895..1bd22e4c96f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,7 @@ v 8.10.0 (unreleased) - Apply the trusted_proxies config to the rack request object for use with rack_attack - Add Sidekiq queue duration to transaction metrics. - Let Workhorse serve format-patch diffs + - Added day name to contribution calendar tooltips - Make images fit to the size of the viewport !4810 - Fix check for New Branch button on Issue page !4630 (winniehell) - Fix MR-auto-close text added to description. !4836 diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js.coffee b/app/assets/javascripts/lib/utils/datetime_utility.js.coffee index 948d6dbf07e..178963fe0aa 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js.coffee +++ b/app/assets/javascripts/lib/utils/datetime_utility.js.coffee @@ -2,10 +2,14 @@ w.gl ?= {} w.gl.utils ?= {} + w.gl.utils.days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] w.gl.utils.formatDate = (datetime) -> dateFormat(datetime, 'mmm d, yyyy h:MMtt Z') + w.gl.utils.getDayName = (date) -> + this.days[date.getDay()] + w.gl.utils.localTimeAgo = ($timeagoEls, setTimeago = true) -> $timeagoEls.each( -> $el = $(@) diff --git a/app/assets/javascripts/users/calendar.js.coffee b/app/assets/javascripts/users/calendar.js.coffee index c081f023b04..c49ba5186f2 100644 --- a/app/assets/javascripts/users/calendar.js.coffee +++ b/app/assets/javascripts/users/calendar.js.coffee @@ -87,14 +87,15 @@ class @Calendar .attr 'width', @daySize .attr 'height', @daySize .attr 'title', (stamp) => + date = new Date(stamp.date) contribText = 'No contributions' if stamp.count > 0 contribText = "#{stamp.count} contribution#{if stamp.count > 1 then 's' else ''}" - date = dateFormat(stamp.date, 'mmm d, yyyy') + dateText = dateFormat(date, 'mmm d, yyyy') - "#{contribText}
#{date}" + "#{contribText}
#{gl.utils.getDayName(date)} #{dateText}" .attr 'class', 'user-contrib-cell js-tooltip' .attr 'fill', (stamp) => if stamp.count isnt 0 From 5467260528018774c8baec65f3cbf692bb3d93b7 Mon Sep 17 00:00:00 2001 From: Patricio Cano Date: Thu, 30 Jun 2016 14:54:07 -0500 Subject: [PATCH 007/335] Added tests for 2FA check on OAuth request --- .../omniauth_callbacks_controller.rb | 7 +++-- spec/features/login_spec.rb | 26 +++++++++++++++---- spec/spec_helper.rb | 2 ++ spec/support/login_helpers.rb | 25 ++++++++++++++++++ 4 files changed, 53 insertions(+), 7 deletions(-) diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 619a76ebfd9..f54c79c2e37 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -107,8 +107,11 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController # Only allow properly saved users to login. if @user.persisted? && @user.valid? log_audit_event(@user, with: oauth['provider']) - prompt_for_two_factor(@user) and return if @user.two_factor_enabled? - sign_in_and_redirect(@user) + if @user.two_factor_enabled? + prompt_for_two_factor(@user) + else + sign_in_and_redirect(@user) + end else error_message = @user.errors.full_messages.to_sentence diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb index 72b5ff231f7..c3dfe343052 100644 --- a/spec/features/login_spec.rb +++ b/spec/features/login_spec.rb @@ -28,6 +28,11 @@ feature 'Login', feature: true do end describe 'with two-factor authentication' do + def enter_code(code) + fill_in 'Two-Factor Authentication code', with: code + click_button 'Verify code' + end + context 'with valid username/password' do let(:user) { create(:user, :two_factor) } @@ -36,11 +41,6 @@ feature 'Login', feature: true do expect(page).to have_content('Two-Factor Authentication') end - def enter_code(code) - fill_in 'Two-Factor Authentication code', with: code - click_button 'Verify code' - end - it 'does not show a "You are already signed in." error message' do enter_code(user.current_otp) expect(page).not_to have_content('You are already signed in.') @@ -108,6 +108,22 @@ feature 'Login', feature: true do end end end + + context 'logging in via OAuth' do + def stub_omniauth_config(messages) + allow(Gitlab.config.omniauth).to receive_messages(messages) + end + + it 'should show 2FA prompt after OAuth login' do + user = create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: 'saml') + stub_omniauth_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [OpenStruct.new(name: 'saml', label: 'saml', args: {})]) + login_via('saml', user, 'my-uid') + + expect(page).to have_content('Two-Factor Authentication') + enter_code(user.current_otp) + expect(current_path).to eq root_path + end + end end describe 'without two-factor authentication' do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b43f38ef202..537aa46a2fd 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -57,3 +57,5 @@ FactoryGirl::SyntaxRunner.class_eval do end ActiveRecord::Migration.maintain_test_schema! + +OmniAuth.config.test_mode = true diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index 7a0f078c72b..75a8846c0da 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -37,6 +37,31 @@ module LoginHelpers Thread.current[:current_user] = user end + def login_via(provider, user, uid) + mock_auth_hash(provider, uid, user.email) + visit new_user_session_path + #page.find('.oauth-image-link').click + click_link provider + end + + def mock_auth_hash(provider, uid, email) + # The mock_auth configuration allows you to set per-provider (or default) + # authentication hashes to return during integration testing. + OmniAuth.config.mock_auth[provider.to_sym] = OmniAuth::AuthHash.new({ + provider: provider, + uid: uid, + info: { + name: 'mockuser', + email: email, + image: 'mock_user_thumbnail_url' + }, + credentials: { + token: 'mock_token', + secret: 'mock_secret' + } + }) + end + # Requires Javascript driver. def logout find(:css, ".fa.fa-sign-out").click From 40e16b22f9a4ecb7dd7a25c4a0355809bed70ebe Mon Sep 17 00:00:00 2001 From: Patricio Cano Date: Mon, 4 Jul 2016 11:50:11 -0500 Subject: [PATCH 008/335] Change order of stubbing to fix tests --- spec/features/login_spec.rb | 2 +- spec/support/login_helpers.rb | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb index c3dfe343052..39968db5b58 100644 --- a/spec/features/login_spec.rb +++ b/spec/features/login_spec.rb @@ -115,8 +115,8 @@ feature 'Login', feature: true do end it 'should show 2FA prompt after OAuth login' do - user = create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: 'saml') stub_omniauth_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [OpenStruct.new(name: 'saml', label: 'saml', args: {})]) + user = create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: 'saml') login_via('saml', user, 'my-uid') expect(page).to have_content('Two-Factor Authentication') diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index 75a8846c0da..f9ce929000c 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -40,7 +40,6 @@ module LoginHelpers def login_via(provider, user, uid) mock_auth_hash(provider, uid, user.email) visit new_user_session_path - #page.find('.oauth-image-link').click click_link provider end From 511c79f094a1c2f366fb43d7d05f746b8adccd62 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Tue, 5 Jul 2016 14:21:14 +0200 Subject: [PATCH 009/335] Remove hound config --- .hound.yml | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 .hound.yml diff --git a/.hound.yml b/.hound.yml deleted file mode 100644 index 3bde29fb2bf..00000000000 --- a/.hound.yml +++ /dev/null @@ -1,4 +0,0 @@ -# Prefer single quotes -StringLiterals: - EnforcedStyle: single_quotes - Enabled: true From 28e324ae67821e19159d66a554065ae11fcfb42c Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 5 Jul 2016 22:58:38 +0800 Subject: [PATCH 010/335] Use Gitlab-Workhorse-Send-Data to send entry: Closes #19224, Closes #19128 Also requires this MR to work: https://gitlab.com/gitlab-org/gitlab-workhorse/merge_requests/53 --- app/controllers/projects/artifacts_controller.rb | 3 +-- app/helpers/workhorse_helper.rb | 6 ++++++ lib/gitlab/workhorse.rb | 12 ++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb index f11c8321464..c6363999670 100644 --- a/app/controllers/projects/artifacts_controller.rb +++ b/app/controllers/projects/artifacts_controller.rb @@ -23,8 +23,7 @@ class Projects::ArtifactsController < Projects::ApplicationController entry = build.artifacts_metadata_entry(params[:path]) if entry.exists? - render json: { archive: build.artifacts_file.path, - entry: Base64.encode64(entry.path) } + send_artifacts_entry(build, entry) else render json: {}, status: 404 end diff --git a/app/helpers/workhorse_helper.rb b/app/helpers/workhorse_helper.rb index 2bd0dbfd095..c582f16eb01 100644 --- a/app/helpers/workhorse_helper.rb +++ b/app/helpers/workhorse_helper.rb @@ -21,4 +21,10 @@ module WorkhorseHelper headers.store(*Gitlab::Workhorse.send_git_archive(repository, ref: ref, format: format)) head :ok end + + # Send an entry from artifacts through Workhorse + def send_artifacts_entry(build, entry) + headers.store(*Gitlab::Workhorse.send_artifacts_entry(build, entry)) + head :ok + end end diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index ef1241f8600..ed1c5da0b3c 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -65,6 +65,18 @@ module Gitlab ] end + def send_artifacts_entry(build, entry) + params = { + 'Archive' => build.artifacts_file.path, + 'Entry' => Base64.encode64(entry.path) + } + + [ + SEND_DATA_HEADER, + "artifacts-entry:#{encode(params)}" + ] + end + protected def encode(hash) From a0c8bd33a924cc38f435c733a9306f39f9c8cce7 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Tue, 5 Jul 2016 19:35:34 +0200 Subject: [PATCH 011/335] Remove teatro config --- .teatro.yml | 8 ---- config/gitlab.teatro.yml | 87 ---------------------------------------- 2 files changed, 95 deletions(-) delete mode 100644 .teatro.yml delete mode 100644 config/gitlab.teatro.yml diff --git a/.teatro.yml b/.teatro.yml deleted file mode 100644 index 30054361981..00000000000 --- a/.teatro.yml +++ /dev/null @@ -1,8 +0,0 @@ -stage: - before: - - cp config/gitlab.teatro.yml config/gitlab.yml - - mkdir /apps/gitlab-satellites - - mkdir /apps/repositories - - database: - - RAILS_ENV=development force=yes bundle exec rake db:create gitlab:setup \ No newline at end of file diff --git a/config/gitlab.teatro.yml b/config/gitlab.teatro.yml deleted file mode 100644 index 75b79b837e0..00000000000 --- a/config/gitlab.teatro.yml +++ /dev/null @@ -1,87 +0,0 @@ - -production: &base - gitlab: - host: localhost - port: 80 - https: false - - user: root - - email_from: example@example.com - - support_email: support@example.com - - default_projects_features: - issues: true - merge_requests: true - wiki: true - snippets: false - visibility_level: "private" # can be "private" | "internal" | "public" - - issues_tracker: - - gravatar: - enabled: true # Use user avatar image from Gravatar.com (default: true) - - ldap: - enabled: false - host: '_your_ldap_server' - port: 636 - uid: 'sAMAccountName' - method: 'ssl' # "tls" or "ssl" or "plain" - bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' - password: '_the_password_of_the_bind_user' - allow_username_or_email_login: true - - base: '' - - user_filter: '' - - omniauth: - enabled: false - - satellites: - # Relative paths are relative to Rails.root (default: tmp/repo_satellites/) - path: /apps/gitlab-satellites/ - - backup: - path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/) - - repositories: - storages: # REPO PATHS MUST NOT BE A SYMLINK!!! - default: /apps/repositories/ - - gitlab_shell: - path: /apps/gitlab-shell/ - - hooks_path: /apps/gitlab-shell/hooks/ - - upload_pack: true - receive_pack: true - - git: - bin_path: /usr/bin/git - max_size: 5242880 # 5.megabytes - timeout: 10 - - extra: - -development: - <<: *base - -test: - <<: *base - gravatar: - enabled: true - gitlab: - host: localhost - port: 80 - issues_tracker: - redmine: - title: "Redmine" - project_url: "http://redmine/projects/:issues_tracker_id" - issues_url: "http://redmine/:project_id/:issues_tracker_id/:id" - new_issue_url: "http://redmine/projects/:issues_tracker_id/issues/new" - -staging: - <<: *base From e065f4848b257256141752e6498398cd68fa7786 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Sat, 18 Jun 2016 11:19:57 -0400 Subject: [PATCH 012/335] Diffs will create button/diff form on demand no on server side --- CHANGELOG | 1 + app/assets/javascripts/diff.js.coffee | 4 +- .../files_comment_button.js.coffee | 82 +++++++++++++++++++ .../javascripts/merge_request_tabs.js.coffee | 1 - .../projects/compare_controller.rb | 1 + .../projects/merge_requests_controller.rb | 1 + app/helpers/notes_helper.rb | 20 +---- app/mailers/emails/projects.rb | 1 + app/views/projects/diffs/_diffs.html.haml | 2 +- app/views/projects/diffs/_line.html.haml | 15 ++-- .../diffs/_match_line_parallel.html.haml | 4 +- .../projects/diffs/_parallel_view.html.haml | 26 +++--- app/views/projects/show.html.haml | 2 +- .../project/commits/diff_comments.feature | 4 - features/steps/shared/diff_note.rb | 14 ++-- spec/features/notes_on_merge_requests_spec.rb | 3 +- 16 files changed, 121 insertions(+), 60 deletions(-) create mode 100644 app/assets/javascripts/files_comment_button.js.coffee diff --git a/CHANGELOG b/CHANGELOG index 8ef934bf80d..15344fc6886 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,6 +24,7 @@ v 8.10.0 (unreleased) - Allow importing from Github using Personal Access Tokens. (Eric K Idema) - API: Todos !3188 (Robert Schilling) - Add "Enabled Git access protocols" to Application Settings + - Diffs will create button/diff form on demand no on server side - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - PipelinesFinder uses git cache data - Check for conflicts with existing Project's wiki path when creating a new project. diff --git a/app/assets/javascripts/diff.js.coffee b/app/assets/javascripts/diff.js.coffee index 6d9b364cb8d..ddb43f02dec 100644 --- a/app/assets/javascripts/diff.js.coffee +++ b/app/assets/javascripts/diff.js.coffee @@ -1,6 +1,8 @@ class @Diff UNFOLD_COUNT = 20 constructor: -> + @filesCommentButton = new FilesCommentButton($('.files')) + $(document).off('click', '.js-unfold') $(document).on('click', '.js-unfold', (event) => target = $(event.target) @@ -36,7 +38,7 @@ class @Diff # see https://gitlab.com/gitlab-org/gitlab-ce/issues/707 indent: 1 - $.get(link, params, (response) => + $.get(link, params, (response) -> target.parent().replaceWith(response) ) ) diff --git a/app/assets/javascripts/files_comment_button.js.coffee b/app/assets/javascripts/files_comment_button.js.coffee new file mode 100644 index 00000000000..56768991dd8 --- /dev/null +++ b/app/assets/javascripts/files_comment_button.js.coffee @@ -0,0 +1,82 @@ +class @FilesCommentButton + constructor: (@filesContainerElement) -> + return if not @filesContainerElement and not @filesContainerElement.data 'can-create-note' + + @COMMENT_BUTTON_CLASS = '.add-diff-note' + @COMMENT_BUTTON_TEMPLATE = _.template("") + + @LINE_HOLDER_CLASS = '.line_holder' + @LINE_NUMBER_CLASS = 'diff-line-num' + @LINE_CONTENT_CLASS = 'line_content' + @LINE_COLUMN_CLASSES = ".#{@LINE_NUMBER_CLASS}, .line_content" + + @DEBOUNCE_TIMEOUT_DURATION = 150 + + $(document) + .on 'mouseover', @LINE_COLUMN_CLASSES, @debounceRender + .on 'mouseleave', @LINE_COLUMN_CLASSES, @destroy + + debounceRender: (e) => + clearTimeout @debounceTimeout if @debounceTimeout + @debounceTimeout = setTimeout => + @render e + , @DEBOUNCE_TIMEOUT_DURATION + return + + render: (e) -> + lineHolderElement = @getLineHolder($(e.currentTarget)) + lineContentElement = @getLineContent($(e.currentTarget)) + lineNumElement = @getLineNum($(e.currentTarget)) + buttonParentElement = lineNumElement + + return if not @shouldRender e, buttonParentElement + + buttonParentElement.append @buildButton + id: + noteable: lineHolderElement.attr 'data-noteable-id' + commit: lineHolderElement.attr 'data-commit-id' + discussion: lineContentElement.attr('data-discussion-id') || lineHolderElement.attr('data-discussion-id') + type: + noteable: lineHolderElement.attr 'data-noteable-type' + note: lineHolderElement.attr 'data-note-type' + line: lineContentElement.attr 'data-line-type' + code: + line: lineContentElement.attr('data-line-code') || lineHolderElement.attr('id') + return + + destroy: (e) => + return if @isMovingToSameType e + $(@COMMENT_BUTTON_CLASS, @getLineNum $(e.currentTarget)).remove() + return + + buildButton: (buttonAttributes) -> + $(@COMMENT_BUTTON_TEMPLATE COMMENT_BUTTON_CLASS: @COMMENT_BUTTON_CLASS.substr 1).attr + 'data-noteable-id': buttonAttributes.id.noteable + 'data-commit-id': buttonAttributes.id.commit + 'data-discussion-id': buttonAttributes.id.discussion + 'data-noteable-type': buttonAttributes.type.noteable + 'data-line-type': buttonAttributes.type.line + 'data-note-type': buttonAttributes.type.note + 'data-line-code': buttonAttributes.code.line + + getLineHolder: (hoveredElement) -> + return hoveredElement if hoveredElement.hasClass @LINE_HOLDER_CLASS + $(hoveredElement.parent()) + + getLineNum: (hoveredElement) -> + return hoveredElement if hoveredElement.hasClass @LINE_NUMBER_CLASS + + $(hoveredElement).prev('.' + @LINE_NUMBER_CLASS) + + getLineContent: (hoveredElement) -> + return hoveredElement if hoveredElement.hasClass @LINE_CONTENT_CLASS + + $(hoveredElement).next('.' + @LINE_CONTENT_CLASS) + + isMovingToSameType: (e) -> + newLineNum = @getLineNum($(e.toElement)) + return false unless newLineNum + (newLineNum).is @getLineNum($(e.currentTarget)) + + shouldRender: (e, buttonParentElement) -> + (!buttonParentElement.hasClass('empty-cell') and $(@COMMENT_BUTTON_CLASS, buttonParentElement).length is 0) diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee index 894f80586f1..7b0ebfb4490 100644 --- a/app/assets/javascripts/merge_request_tabs.js.coffee +++ b/app/assets/javascripts/merge_request_tabs.js.coffee @@ -153,7 +153,6 @@ class @MergeRequestTabs loadDiff: (source) -> return if @diffsLoaded - @_get url: "#{source}.json" + @_location.search success: (data) => diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index af0b69a2442..57725944d68 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -24,6 +24,7 @@ class Projects::CompareController < Projects::ApplicationController @diff_refs = [@base_commit, @commit] @diff_notes_disabled = true @grouped_diff_notes = {} + @comments_target = {} end end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index dd86b940a08..99630bc1099 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -138,6 +138,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @base_commit = @merge_request.diff_base_commit @diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare @diff_notes_disabled = true + @comments_target = {} @pipeline = @merge_request.pipeline @statuses = @pipeline.statuses if @pipeline diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index e85ba76887d..42419aa908e 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -24,28 +24,12 @@ module NotesHelper }.to_json end - def link_to_new_diff_note(line_code, line_type = nil) - discussion_id = LegacyDiffNote.build_discussion_id( + def discussion_id(line_code) + LegacyDiffNote.build_discussion_id( @comments_target[:noteable_type], @comments_target[:noteable_id] || @comments_target[:commit_id], line_code ) - - data = { - noteable_type: @comments_target[:noteable_type], - noteable_id: @comments_target[:noteable_id], - commit_id: @comments_target[:commit_id], - line_type: line_type, - line_code: line_code, - note_type: LegacyDiffNote.name, - discussion_id: discussion_id - } - - button_tag(class: 'btn add-diff-note js-add-diff-note-button', - data: data, - title: 'Add a comment to this line') do - icon('comment-o') - end end def link_to_reply_discussion(note, line_type = nil) diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index e0af7081411..1a6900b3293 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -30,6 +30,7 @@ module Emails @target_url = @message.target_url @project = Project.find(project_id) @diff_notes_disabled = true + @comments_target = {} add_project_headers headers['X-GitLab-Author'] = @message.author_username diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index f18bc8c41b3..fea294628fe 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -21,7 +21,7 @@ - if diff_files.overflow? = render 'projects/diffs/warning', diff_files: diff_files -.files +.files{data: {can_create_note: (!@diff_notes_disabled && can?(current_user, :create_note, @project)).to_s}} - diff_files.each_with_index do |diff_file, index| - diff_commit = commit_for_diff(diff_file) - blob = project.repository.blob_for_diff(diff_commit, diff_file) diff --git a/app/views/projects/diffs/_line.html.haml b/app/views/projects/diffs/_line.html.haml index f1577e8a47b..31e8378c9dc 100644 --- a/app/views/projects/diffs/_line.html.haml +++ b/app/views/projects/diffs/_line.html.haml @@ -1,5 +1,6 @@ - type = line.type -%tr.line_holder{ id: line_code, class: type } +- holder_data = @comments_target.any? ? { data: { noteable_id: @comments_target[:noteable_id], noteable_type: @comments_target[:noteable_type], commit_id: @comments_target[:commit_id], discussion_id: discussion_id(line_code), note_type: LegacyDiffNote.name } } : {} +%tr.line_holder{ holder_data, id: line_code, class: type } - case type - when 'match' = render "projects/diffs/match_line", { line: line.text, @@ -10,17 +11,15 @@ %td.line_content.match= line.text - else %td.old_line.diff-line-num{ class: type, data: { linenumber: line.new_pos } } - - link_text = type == "new" ? " ".html_safe : line.old_pos + - link_text = type == "new" ? " " : line.old_pos - if defined?(plain) && plain = link_text - else - = link_to "", "##{line_code}", id: line_code, data: { linenumber: link_text } - - if !@diff_notes_disabled && can?(current_user, :create_note, @project) - = link_to_new_diff_note(line_code) + %a{href: "##{line_code}", data: { linenumber: link_text }}= " " %td.new_line.diff-line-num{ class: type, data: { linenumber: line.new_pos } } - - link_text = type == "old" ? " ".html_safe : line.new_pos + - link_text = type == "old" ? " " : line.new_pos - if defined?(plain) && plain = link_text - else - = link_to "", "##{line_code}", id: line_code, data: { linenumber: link_text } - %td.line_content{ class: ['noteable_line', type, line_code], data: { line_code: line_code } }= diff_line_content(line.text, type) + %a{href: "##{line_code}", data: { linenumber: link_text }}= "" + %td.line_content{ class: ['noteable_line', type], data: { line_code: line_code, line_type: type } }= diff_line_content(line.text, type) diff --git a/app/views/projects/diffs/_match_line_parallel.html.haml b/app/views/projects/diffs/_match_line_parallel.html.haml index 0cd888876e0..b9c0d9dcdfd 100644 --- a/app/views/projects/diffs/_match_line_parallel.html.haml +++ b/app/views/projects/diffs/_match_line_parallel.html.haml @@ -1,4 +1,4 @@ -%td.old_line.diff-line-num +%td.old_line.diff-line-num.empty-cell %td.line_content.parallel.match= line -%td.new_line.diff-line-num +%td.new_line.diff-line-num.empty-cell %td.line_content.parallel.match= line diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index 4ecc9528bd2..089ddf23240 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -4,21 +4,19 @@ - diff_file.parallel_diff_lines.each do |line| - left = line[:left] - right = line[:right] - %tr.line_holder.parallel + - holder_data = @comments_target.any? ? { data: { noteable_id: @comments_target[:noteable_id], noteable_type: @comments_target[:noteable_type], commit_id: @comments_target[:commit_id], note_type: LegacyDiffNote.name } } : {} + %tr.line_holder.parallel{ holder_data } - if left[:type] == 'match' - = render "projects/diffs/match_line_parallel", { line: left[:text], - line_old: left[:number], line_new: right[:number] } + = render "projects/diffs/match_line_parallel", { line: left[:text] } - elsif left[:type] == 'nonewline' - %td.old_line.diff-line-num + %td.old_line.diff-line-num.empty-cell %td.line_content.parallel.match= left[:text] - %td.new_line.diff-line-num + %td.new_line.diff-line-num.empty-cell %td.line_content.parallel.match= left[:text] - else - %td.old_line.diff-line-num{id: left[:line_code], class: "#{left[:type]} #{'empty-cell' if !left[:number]}"} - = link_to raw(left[:number]), "##{left[:line_code]}", id: left[:line_code] - - if !@diff_notes_disabled && can?(current_user, :create_note, @project) - = link_to_new_diff_note(left[:line_code], 'old') - %td.line_content{class: "parallel noteable_line #{left[:type]} #{left[:line_code]} #{'empty-cell' if left[:text].empty?}", data: { line_code: left[:line_code] }}= diff_line_content(left[:text]) + %td.old_line.diff-line-num{id: left[:line_code], class: "#{left[:type]} #{'empty-cell' if !left[:number]}", data: { linenumber: left[:number] }} + %a{href: "##{left[:line_code]}" }= raw(left[:number]) + %td.line_content{class: "parallel noteable_line #{left[:type]} #{'empty-cell' if left[:text].empty?}", data: { discussion_id: discussion_id(left[:line_code]), line_type: left[:type], line_code: left[:line_code] }}= diff_line_content(left[:text]) - if right[:type] == 'new' - new_line_class = 'new' @@ -27,11 +25,9 @@ - new_line_class = nil - new_line_code = left[:line_code] - %td.new_line.diff-line-num{id: new_line_code, class: "#{new_line_class} #{'empty-cell' if !right[:number]}", data: { linenumber: right[:number] }} - = link_to raw(right[:number]), "##{new_line_code}", id: new_line_code - - if !@diff_notes_disabled && can?(current_user, :create_note, @project) - = link_to_new_diff_note(new_line_code, 'new') - %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code} #{'empty-cell' if right[:text].empty?}", data: { line_code: new_line_code }}= diff_line_content(right[:text]) + %td.new_line.diff-line-num{id: new_line_code, class: "#{new_line_class} #{'empty-cell' if !right[:number]}", data: { linenumber: right[:number] } } + %a{href: "##{new_line_code}" }= raw(right[:number]) + %td.line_content.parallel{class: "noteable_line #{new_line_class} #{'empty-cell' if right[:text].empty?}", data: { discussion_id: discussion_id(new_line_code), line_type: new_line_class, line_code: new_line_code }}= diff_line_content(right[:text]) - unless @diff_notes_disabled - notes_left, notes_right = organize_comments(left, right) diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 58d8e068754..dd1cf680cfa 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -82,4 +82,4 @@ Archived project! Repository is read-only %div{class: "project-show-#{default_project_view}"} - = render default_project_view + = render default_project_view \ No newline at end of file diff --git a/features/project/commits/diff_comments.feature b/features/project/commits/diff_comments.feature index 2bde4c8a99b..35687aac9ea 100644 --- a/features/project/commits/diff_comments.feature +++ b/features/project/commits/diff_comments.feature @@ -5,10 +5,6 @@ Feature: Project Commits Diff Comments And I own project "Shop" And I visit project commit page - @javascript - Scenario: I can access add diff comment buttons - Then I should see add a diff comment button - @javascript Scenario: I can comment on a commit diff Given I leave a diff comment like "Typo, please fix" diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb index e8b1e4b4879..8dc461bdd95 100644 --- a/features/steps/shared/diff_note.rb +++ b/features/steps/shared/diff_note.rb @@ -32,8 +32,8 @@ module SharedDiffNote end step 'I leave a diff comment in a parallel view on the left side like "Old comment"' do - click_parallel_diff_line(sample_commit.line_code, 'old') - page.within("#{diff_file_selector} form[id$='#{sample_commit.line_code}-true']") do + click_parallel_diff_line(sample_commit.del_line_code, 'old') + page.within("#{diff_file_selector} form[id$='#{sample_commit.del_line_code}-true']") do fill_in "note[note]", with: "Old comment" find(".js-comment-button").trigger("click") end @@ -165,10 +165,6 @@ module SharedDiffNote end end - step 'I should see add a diff comment button' do - expect(page).to have_css('.js-add-diff-note-button') - end - step 'I should see an empty diff comment form' do page.within(diff_file_selector) do expect(page).to have_field("note[note]", with: "") @@ -227,10 +223,12 @@ module SharedDiffNote end def click_diff_line(code) - find("button[data-line-code='#{code}']").trigger('click') + find(".line_holder[id='#{code}'] td:nth-of-type(1)").hover + find(".line_holder[id='#{code}'] button").trigger('click') end def click_parallel_diff_line(code, line_type) - find("button[data-line-code='#{code}'][data-line-type='#{line_type}']").trigger('click') + find(".line_content.parallel.#{line_type}[data-line-code='#{code}']").trigger('mouseover') + find(".line_holder.parallel button[data-line-code='#{code}']").trigger('click') end end diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index 737efcef45d..bb53475bf6c 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -229,6 +229,7 @@ describe 'Comments', feature: true do end def click_diff_line(data = line_code) - execute_script("$('button[data-line-code=\"#{data}\"]').click()") + find(".line_holder[id='#{data}'] td:nth-of-type(1)").hover + find(".line_holder[id='#{data}'] button").trigger('click') end end From 914bb05d282bca9c4509d56c1be409a5889e57b8 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Fri, 1 Jul 2016 07:09:56 +0200 Subject: [PATCH 013/335] Moving up common html data attributes --- .../files_comment_button.js.coffee | 20 ++++++++++++------- app/views/projects/diffs/_line.html.haml | 4 ++-- .../projects/diffs/_parallel_view.html.haml | 6 +++--- app/views/projects/diffs/_text_file.html.haml | 3 ++- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/files_comment_button.js.coffee b/app/assets/javascripts/files_comment_button.js.coffee index 56768991dd8..d2613847f69 100644 --- a/app/assets/javascripts/files_comment_button.js.coffee +++ b/app/assets/javascripts/files_comment_button.js.coffee @@ -9,6 +9,7 @@ class @FilesCommentButton @LINE_NUMBER_CLASS = 'diff-line-num' @LINE_CONTENT_CLASS = 'line_content' @LINE_COLUMN_CLASSES = ".#{@LINE_NUMBER_CLASS}, .line_content" + @TEXT_FILE_SELECTOR = '.text-file' @DEBOUNCE_TIMEOUT_DURATION = 150 @@ -24,21 +25,23 @@ class @FilesCommentButton return render: (e) -> - lineHolderElement = @getLineHolder($(e.currentTarget)) - lineContentElement = @getLineContent($(e.currentTarget)) - lineNumElement = @getLineNum($(e.currentTarget)) + currentTarget = $(e.currentTarget) + textFileElement = @getTextFileElement(currentTarget) + lineHolderElement = @getLineHolder(currentTarget) + lineContentElement = @getLineContent(currentTarget) + lineNumElement = @getLineNum(currentTarget) buttonParentElement = lineNumElement return if not @shouldRender e, buttonParentElement buttonParentElement.append @buildButton id: - noteable: lineHolderElement.attr 'data-noteable-id' - commit: lineHolderElement.attr 'data-commit-id' + noteable: textFileElement.attr 'data-noteable-id' + commit: textFileElement.attr 'data-commit-id' discussion: lineContentElement.attr('data-discussion-id') || lineHolderElement.attr('data-discussion-id') type: - noteable: lineHolderElement.attr 'data-noteable-type' - note: lineHolderElement.attr 'data-note-type' + noteable: textFileElement.attr 'data-noteable-type' + note: textFileElement.attr 'data-note-type' line: lineContentElement.attr 'data-line-type' code: line: lineContentElement.attr('data-line-code') || lineHolderElement.attr('id') @@ -59,6 +62,9 @@ class @FilesCommentButton 'data-note-type': buttonAttributes.type.note 'data-line-code': buttonAttributes.code.line + getTextFileElement: (hoveredElement) -> + $(hoveredElement.closest(@TEXT_FILE_SELECTOR)) + getLineHolder: (hoveredElement) -> return hoveredElement if hoveredElement.hasClass @LINE_HOLDER_CLASS $(hoveredElement.parent()) diff --git a/app/views/projects/diffs/_line.html.haml b/app/views/projects/diffs/_line.html.haml index 31e8378c9dc..da1c81bfc15 100644 --- a/app/views/projects/diffs/_line.html.haml +++ b/app/views/projects/diffs/_line.html.haml @@ -1,6 +1,6 @@ - type = line.type -- holder_data = @comments_target.any? ? { data: { noteable_id: @comments_target[:noteable_id], noteable_type: @comments_target[:noteable_type], commit_id: @comments_target[:commit_id], discussion_id: discussion_id(line_code), note_type: LegacyDiffNote.name } } : {} -%tr.line_holder{ holder_data, id: line_code, class: type } +- line_data = @comments_target.any? ? { data: { discussion_id: discussion_id(line_code) } } : {} +%tr.line_holder{ line_data, id: line_code, class: type } - case type - when 'match' = render "projects/diffs/match_line", { line: line.text, diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index 089ddf23240..e205686ceea 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -1,11 +1,11 @@ / Side-by-side diff view -%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight +- text_file_data = @comments_target.any? ? { data: { noteable_id: @comments_target[:noteable_id], noteable_type: @comments_target[:noteable_type], commit_id: @comments_target[:commit_id], note_type: LegacyDiffNote.name } } : {} +%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight{ text_file_data } %table - diff_file.parallel_diff_lines.each do |line| - left = line[:left] - right = line[:right] - - holder_data = @comments_target.any? ? { data: { noteable_id: @comments_target[:noteable_id], noteable_type: @comments_target[:noteable_type], commit_id: @comments_target[:commit_id], note_type: LegacyDiffNote.name } } : {} - %tr.line_holder.parallel{ holder_data } + %tr.line_holder.parallel - if left[:type] == 'match' = render "projects/diffs/match_line_parallel", { line: left[:text] } - elsif left[:type] == 'nonewline' diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index 068593a7dd1..a1c3bf74b0a 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -3,7 +3,8 @@ .suppressed-container %a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show. -%table.text-file.code.js-syntax-highlight{ class: too_big ? 'hide' : '' } +- text_file_data = @comments_target.any? ? { data: { noteable_id: @comments_target[:noteable_id], noteable_type: @comments_target[:noteable_type], commit_id: @comments_target[:commit_id], note_type: LegacyDiffNote.name } } : {} +%table.text-file.code.js-syntax-highlight{ text_file_data, class: too_big ? 'hide' : '' } - last_line = 0 - diff_file.highlighted_diff_lines.each_with_index do |line, index| From 50dfdf0296ae307d0b22ae8bbd1b52dca9fbaea9 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Sun, 3 Jul 2016 21:01:36 +0100 Subject: [PATCH 014/335] fix up tests Added more exceptions Added handling inline view type --- .../files_comment_button.js.coffee | 24 +++++++++++++------ app/helpers/diff_helper.rb | 2 +- features/steps/shared/diff_note.rb | 17 +++++++------ spec/helpers/diff_helper_spec.rb | 2 +- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/app/assets/javascripts/files_comment_button.js.coffee b/app/assets/javascripts/files_comment_button.js.coffee index d2613847f69..681592f246a 100644 --- a/app/assets/javascripts/files_comment_button.js.coffee +++ b/app/assets/javascripts/files_comment_button.js.coffee @@ -8,11 +8,16 @@ class @FilesCommentButton @LINE_HOLDER_CLASS = '.line_holder' @LINE_NUMBER_CLASS = 'diff-line-num' @LINE_CONTENT_CLASS = 'line_content' + @UNFOLDABLE_LINE_CLASS = 'js-unfold' + @EMPTY_CELL_CLASS = 'empty-cell' + @OLD_LINE_CLASS = 'old_line' @LINE_COLUMN_CLASSES = ".#{@LINE_NUMBER_CLASS}, .line_content" @TEXT_FILE_SELECTOR = '.text-file' @DEBOUNCE_TIMEOUT_DURATION = 150 + @VIEW_TYPE = $('input#view[type=hidden]').val() + $(document) .on 'mouseover', @LINE_COLUMN_CLASSES, @debounceRender .on 'mouseleave', @LINE_COLUMN_CLASSES, @destroy @@ -38,13 +43,13 @@ class @FilesCommentButton id: noteable: textFileElement.attr 'data-noteable-id' commit: textFileElement.attr 'data-commit-id' - discussion: lineContentElement.attr('data-discussion-id') || lineHolderElement.attr('data-discussion-id') + discussion: lineContentElement.attr('data-discussion-id') or lineHolderElement.attr('data-discussion-id') type: noteable: textFileElement.attr 'data-noteable-type' note: textFileElement.attr 'data-note-type' line: lineContentElement.attr 'data-line-type' code: - line: lineContentElement.attr('data-line-code') || lineHolderElement.attr('id') + line: lineContentElement.attr('data-line-code') or lineHolderElement.attr('id') return destroy: (e) => @@ -70,14 +75,17 @@ class @FilesCommentButton $(hoveredElement.parent()) getLineNum: (hoveredElement) -> - return hoveredElement if hoveredElement.hasClass @LINE_NUMBER_CLASS - - $(hoveredElement).prev('.' + @LINE_NUMBER_CLASS) + if @VIEW_TYPE is 'inline' and hoveredElement.hasClass @OLD_LINE_CLASS + $(hoveredElement).next ".#{@LINE_NUMBER_CLASS}" + else if hoveredElement.hasClass @LINE_NUMBER_CLASS + hoveredElement + else + $(hoveredElement).prev ".#{@LINE_NUMBER_CLASS}" getLineContent: (hoveredElement) -> return hoveredElement if hoveredElement.hasClass @LINE_CONTENT_CLASS - $(hoveredElement).next('.' + @LINE_CONTENT_CLASS) + $(hoveredElement).next ".#{@LINE_CONTENT_CLASS}" isMovingToSameType: (e) -> newLineNum = @getLineNum($(e.toElement)) @@ -85,4 +93,6 @@ class @FilesCommentButton (newLineNum).is @getLineNum($(e.currentTarget)) shouldRender: (e, buttonParentElement) -> - (!buttonParentElement.hasClass('empty-cell') and $(@COMMENT_BUTTON_CLASS, buttonParentElement).length is 0) + (!buttonParentElement.hasClass(@EMPTY_CELL_CLASS) and \ + !buttonParentElement.hasClass(@UNFOLDABLE_LINE_CLASS) and \ + $(@COMMENT_BUTTON_CLASS, buttonParentElement).length is 0) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index e22dce59d0f..a282a67020f 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -39,7 +39,7 @@ module DiffHelper end def unfold_bottom_class(bottom) - bottom ? 'js-unfold-bottom' : '' + bottom ? 'js-unfold js-unfold-bottom' : '' end def unfold_class(unfold) diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb index 8dc461bdd95..146cbcfad5e 100644 --- a/features/steps/shared/diff_note.rb +++ b/features/steps/shared/diff_note.rb @@ -25,8 +25,7 @@ module SharedDiffNote page.within("form[id$='#{sample_commit.line_code}-true']") do fill_in "note[note]", with: "Typo, please fix" - find(".js-comment-button").trigger("click") - sleep 0.05 + find(".js-comment-button").click end end end @@ -35,7 +34,7 @@ module SharedDiffNote click_parallel_diff_line(sample_commit.del_line_code, 'old') page.within("#{diff_file_selector} form[id$='#{sample_commit.del_line_code}-true']") do fill_in "note[note]", with: "Old comment" - find(".js-comment-button").trigger("click") + find(".js-comment-button").click end end @@ -43,7 +42,7 @@ module SharedDiffNote click_parallel_diff_line(sample_commit.line_code, 'new') page.within("#{diff_file_selector} form[id$='#{sample_commit.line_code}-true']") do fill_in "note[note]", with: "New comment" - find(".js-comment-button").trigger("click") + find(".js-comment-button").click end end @@ -211,7 +210,7 @@ module SharedDiffNote end step 'I click side-by-side diff button' do - find('#parallel-diff-btn').trigger('click') + find('#parallel-diff-btn').click end step 'I see side-by-side diff button' do @@ -223,12 +222,12 @@ module SharedDiffNote end def click_diff_line(code) - find(".line_holder[id='#{code}'] td:nth-of-type(1)").hover - find(".line_holder[id='#{code}'] button").trigger('click') + find(".line_holder[id='#{code}'] td:nth-of-type(1)").trigger 'mouseover' + find(".line_holder[id='#{code}'] button").trigger 'click' end def click_parallel_diff_line(code, line_type) - find(".line_content.parallel.#{line_type}[data-line-code='#{code}']").trigger('mouseover') - find(".line_holder.parallel button[data-line-code='#{code}']").trigger('click') + find(".line_content.parallel.#{line_type}[data-line-code='#{code}']").trigger 'mouseover' + find(".line_holder.parallel button[data-line-code='#{code}']").trigger 'click' end end diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index 52764f41e0d..a71dd53e6ed 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -59,7 +59,7 @@ describe DiffHelper do end it 'should return js class when bottom lines should be unfolded' do - expect(unfold_bottom_class(true)).to eq('js-unfold-bottom') + expect(unfold_bottom_class(true)).to include('js-unfold-bottom') end end From fa981c9794de7a76bf225dc243e20d2799b55e53 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Wed, 6 Jul 2016 06:58:56 +0200 Subject: [PATCH 015/335] More informative CHANGELING entry --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 15344fc6886..16f181b68a1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -25,6 +25,7 @@ v 8.10.0 (unreleased) - API: Todos !3188 (Robert Schilling) - Add "Enabled Git access protocols" to Application Settings - Diffs will create button/diff form on demand no on server side + - Reduce size of HTML used by diff comment forms - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - PipelinesFinder uses git cache data - Check for conflicts with existing Project's wiki path when creating a new project. From 39b6e678da8c431020370dfc26c761255bc3ddf8 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Wed, 6 Jul 2016 06:59:18 +0200 Subject: [PATCH 016/335] Simplify HAML code using unless condition and nesting Extract diff line data attributes to helper methods --- .../projects/compare_controller.rb | 1 - .../projects/merge_requests_controller.rb | 1 - app/helpers/notes_helper.rb | 21 +++++++++++++++++++ app/mailers/emails/projects.rb | 1 - app/views/projects/diffs/_line.html.haml | 6 +++--- .../projects/diffs/_parallel_view.html.haml | 11 +++++----- app/views/projects/diffs/_text_file.html.haml | 3 +-- 7 files changed, 30 insertions(+), 14 deletions(-) diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index 57725944d68..af0b69a2442 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -24,7 +24,6 @@ class Projects::CompareController < Projects::ApplicationController @diff_refs = [@base_commit, @commit] @diff_notes_disabled = true @grouped_diff_notes = {} - @comments_target = {} end end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 99630bc1099..dd86b940a08 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -138,7 +138,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController @base_commit = @merge_request.diff_base_commit @diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare @diff_notes_disabled = true - @comments_target = {} @pipeline = @merge_request.pipeline @statuses = @pipeline.statuses if @pipeline diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 42419aa908e..e1c8152885a 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -24,6 +24,27 @@ module NotesHelper }.to_json end + def note_text_file_data + return {} unless defined?(@comments_target) && @comments_target.any? + + @comments_target.slice(:noteable_id, :noteable_type, :commit_id).merge(note_type: LegacyDiffNote.name) + end + + def note_line_parallel_data(line_code, line_type) + data = { + line_code: line_code, + line_type: line_type, + } + + unless @diff_notes_disabled + data.merge!( + discussion_id: discussion_id(line_code) + ) + end + + data + end + def discussion_id(line_code) LegacyDiffNote.build_discussion_id( @comments_target[:noteable_type], diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 1a6900b3293..e0af7081411 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -30,7 +30,6 @@ module Emails @target_url = @message.target_url @project = Project.find(project_id) @diff_notes_disabled = true - @comments_target = {} add_project_headers headers['X-GitLab-Author'] = @message.author_username diff --git a/app/views/projects/diffs/_line.html.haml b/app/views/projects/diffs/_line.html.haml index da1c81bfc15..1953720b79e 100644 --- a/app/views/projects/diffs/_line.html.haml +++ b/app/views/projects/diffs/_line.html.haml @@ -1,5 +1,5 @@ - type = line.type -- line_data = @comments_target.any? ? { data: { discussion_id: discussion_id(line_code) } } : {} +- line_data = @diff_notes_disabled ? {} : { data: { discussion_id: discussion_id(line_code) } } %tr.line_holder{ line_data, id: line_code, class: type } - case type - when 'match' @@ -15,11 +15,11 @@ - if defined?(plain) && plain = link_text - else - %a{href: "##{line_code}", data: { linenumber: link_text }}= " " + %a{href: "##{line_code}", data: { linenumber: link_text }} %td.new_line.diff-line-num{ class: type, data: { linenumber: line.new_pos } } - link_text = type == "old" ? " " : line.new_pos - if defined?(plain) && plain = link_text - else - %a{href: "##{line_code}", data: { linenumber: link_text }}= "" + %a{href: "##{line_code}", data: { linenumber: link_text }} %td.line_content{ class: ['noteable_line', type], data: { line_code: line_code, line_type: type } }= diff_line_content(line.text, type) diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index e205686ceea..a234f778190 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -1,6 +1,5 @@ / Side-by-side diff view -- text_file_data = @comments_target.any? ? { data: { noteable_id: @comments_target[:noteable_id], noteable_type: @comments_target[:noteable_type], commit_id: @comments_target[:commit_id], note_type: LegacyDiffNote.name } } : {} -%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight{ text_file_data } +%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight{ data: note_text_file_data } %table - diff_file.parallel_diff_lines.each do |line| - left = line[:left] @@ -14,9 +13,9 @@ %td.new_line.diff-line-num.empty-cell %td.line_content.parallel.match= left[:text] - else - %td.old_line.diff-line-num{id: left[:line_code], class: "#{left[:type]} #{'empty-cell' if !left[:number]}", data: { linenumber: left[:number] }} + %td.old_line.diff-line-num{id: left[:line_code], class: "#{left[:type]} #{'empty-cell' unless left[:number]}", data: { linenumber: left[:number] }} %a{href: "##{left[:line_code]}" }= raw(left[:number]) - %td.line_content{class: "parallel noteable_line #{left[:type]} #{'empty-cell' if left[:text].empty?}", data: { discussion_id: discussion_id(left[:line_code]), line_type: left[:type], line_code: left[:line_code] }}= diff_line_content(left[:text]) + %td.line_content{class: "parallel noteable_line #{left[:type]} #{'empty-cell' if left[:text].empty?}", data: note_line_parallel_data(left[:line_code], left[:type]) }= diff_line_content(left[:text]) - if right[:type] == 'new' - new_line_class = 'new' @@ -25,9 +24,9 @@ - new_line_class = nil - new_line_code = left[:line_code] - %td.new_line.diff-line-num{id: new_line_code, class: "#{new_line_class} #{'empty-cell' if !right[:number]}", data: { linenumber: right[:number] } } + %td.new_line.diff-line-num{id: new_line_code, class: "#{new_line_class} #{'empty-cell' unless right[:number]}", data: { linenumber: right[:number] } } %a{href: "##{new_line_code}" }= raw(right[:number]) - %td.line_content.parallel{class: "noteable_line #{new_line_class} #{'empty-cell' if right[:text].empty?}", data: { discussion_id: discussion_id(new_line_code), line_type: new_line_class, line_code: new_line_code }}= diff_line_content(right[:text]) + %td.line_content.parallel{class: "noteable_line #{new_line_class} #{'empty-cell' if right[:text].empty?}", data: note_line_parallel_data(new_line_code, new_line_class) }= diff_line_content(right[:text]) - unless @diff_notes_disabled - notes_left, notes_right = organize_comments(left, right) diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index a1c3bf74b0a..3a3aff4d054 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -3,8 +3,7 @@ .suppressed-container %a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show. -- text_file_data = @comments_target.any? ? { data: { noteable_id: @comments_target[:noteable_id], noteable_type: @comments_target[:noteable_type], commit_id: @comments_target[:commit_id], note_type: LegacyDiffNote.name } } : {} -%table.text-file.code.js-syntax-highlight{ text_file_data, class: too_big ? 'hide' : '' } +%table.text-file.code.js-syntax-highlight{ data: note_text_file_data, class: too_big ? 'hide' : '' } - last_line = 0 - diff_file.highlighted_diff_lines.each_with_index do |line, index| From 0cf7a920db1e0c67555a2e96b94e0f2c3aa52afe Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Wed, 6 Jul 2016 07:39:44 +0200 Subject: [PATCH 017/335] Compare view cannot show the note button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit data-can-create-note == “false” --- app/assets/javascripts/files_comment_button.js.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/files_comment_button.js.coffee b/app/assets/javascripts/files_comment_button.js.coffee index 681592f246a..3cb6a28ad94 100644 --- a/app/assets/javascripts/files_comment_button.js.coffee +++ b/app/assets/javascripts/files_comment_button.js.coffee @@ -1,6 +1,7 @@ class @FilesCommentButton constructor: (@filesContainerElement) -> - return if not @filesContainerElement and not @filesContainerElement.data 'can-create-note' + return if not @filesContainerElement + return if not @filesContainerElement.data 'can-create-note' @COMMENT_BUTTON_CLASS = '.add-diff-note' @COMMENT_BUTTON_TEMPLATE = _.template("") From 40398d56c926503831bf14646053809c22e65fd0 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Wed, 6 Jul 2016 09:03:31 +0200 Subject: [PATCH 018/335] Apply filesCommentButton to loaded Diffs through AJAX --- app/assets/javascripts/merge_request_tabs.js.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee index 7b0ebfb4490..cf54aa92520 100644 --- a/app/assets/javascripts/merge_request_tabs.js.coffee +++ b/app/assets/javascripts/merge_request_tabs.js.coffee @@ -163,6 +163,7 @@ class @MergeRequestTabs @diffsLoaded = true @scrollToElement("#diffs") @highlighSelectedLine() + @filesCommentButton = new FilesCommentButton($('.files')) $(document) .off 'click', '.diff-line-num a' From c6abeffea1b6adbee017feadae13bb5ffc966d10 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Wed, 6 Jul 2016 09:19:34 +0200 Subject: [PATCH 019/335] Add the comment diff button where it should be --- .../files_comment_button.js.coffee | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/files_comment_button.js.coffee b/app/assets/javascripts/files_comment_button.js.coffee index 3cb6a28ad94..2cc051b9e12 100644 --- a/app/assets/javascripts/files_comment_button.js.coffee +++ b/app/assets/javascripts/files_comment_button.js.coffee @@ -35,8 +35,7 @@ class @FilesCommentButton textFileElement = @getTextFileElement(currentTarget) lineHolderElement = @getLineHolder(currentTarget) lineContentElement = @getLineContent(currentTarget) - lineNumElement = @getLineNum(currentTarget) - buttonParentElement = lineNumElement + buttonParentElement = @getButtonParent(currentTarget) return if not @shouldRender e, buttonParentElement @@ -55,7 +54,7 @@ class @FilesCommentButton destroy: (e) => return if @isMovingToSameType e - $(@COMMENT_BUTTON_CLASS, @getLineNum $(e.currentTarget)).remove() + $(@COMMENT_BUTTON_CLASS, @getButtonParent $(e.currentTarget)).remove() return buildButton: (buttonAttributes) -> @@ -75,23 +74,25 @@ class @FilesCommentButton return hoveredElement if hoveredElement.hasClass @LINE_HOLDER_CLASS $(hoveredElement.parent()) - getLineNum: (hoveredElement) -> - if @VIEW_TYPE is 'inline' and hoveredElement.hasClass @OLD_LINE_CLASS - $(hoveredElement).next ".#{@LINE_NUMBER_CLASS}" - else if hoveredElement.hasClass @LINE_NUMBER_CLASS - hoveredElement - else - $(hoveredElement).prev ".#{@LINE_NUMBER_CLASS}" - getLineContent: (hoveredElement) -> return hoveredElement if hoveredElement.hasClass @LINE_CONTENT_CLASS $(hoveredElement).next ".#{@LINE_CONTENT_CLASS}" + getButtonParent: (hoveredElement) -> + if @VIEW_TYPE is 'inline' + return hoveredElement if hoveredElement.hasClass @OLD_LINE_CLASS + + $(hoveredElement).parent().find ".#{@OLD_LINE_CLASS}" + else + return hoveredElement if hoveredElement.hasClass @LINE_NUMBER_CLASS + + $(hoveredElement).prev ".#{@LINE_NUMBER_CLASS}" + isMovingToSameType: (e) -> - newLineNum = @getLineNum($(e.toElement)) - return false unless newLineNum - (newLineNum).is @getLineNum($(e.currentTarget)) + newButtonParent = @getButtonParent($(e.toElement)) + return false unless newButtonParent + (newButtonParent).is @getButtonParent($(e.currentTarget)) shouldRender: (e, buttonParentElement) -> (!buttonParentElement.hasClass(@EMPTY_CELL_CLASS) and \ From 4b9f76cede975106e1e34af787e46720e3c3bb2e Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 6 Jul 2016 15:45:43 +0800 Subject: [PATCH 020/335] Fix one of the failing tests. Test against the headers --- features/steps/project/builds/artifacts.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/features/steps/project/builds/artifacts.rb b/features/steps/project/builds/artifacts.rb index 2876e8812e9..4bc74688132 100644 --- a/features/steps/project/builds/artifacts.rb +++ b/features/steps/project/builds/artifacts.rb @@ -68,10 +68,15 @@ class Spinach::Features::ProjectBuildsArtifacts < Spinach::FeatureSteps end step 'download of a file extracted from build artifacts should start' do - # this will be accelerated by Workhorse - response_json = JSON.parse(page.body, symbolize_names: true) - expect(response_json[:archive]).to end_with('build_artifacts.zip') - expect(response_json[:entry]).to eq Base64.encode64('ci_artifacts.txt') + send_data = response_headers[Gitlab::Workhorse::SEND_DATA_HEADER] + + expect(send_data).to start_with('artifacts-entry:') + + params = JSON.parse(Base64.urlsafe_decode64(send_data[/(?<=:)(.+)/])) + + expect(params.keys).to eq(['Archive', 'Entry']) + expect(params['Archive']).to end_with('build_artifacts.zip') + expect(params['Entry']).to eq(Base64.encode64('ci_artifacts.txt')) end step 'I click a first row within build artifacts table' do From 34d11a319807481ad9a336914aef86b07f1ba055 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Wed, 6 Jul 2016 10:15:41 +0100 Subject: [PATCH 021/335] implements filter_params --- lib/api/entities.rb | 2 ++ lib/api/helpers.rb | 17 +++++++++++++++++ lib/api/projects.rb | 2 ++ 3 files changed, 21 insertions(+) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 8cc4368b5c2..757896fd59b 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -331,7 +331,9 @@ module API class ProjectWithAccess < Project expose :permissions do expose :project_access, using: Entities::ProjectAccess do |project, options| + project = Project.find_by(project[:id]) project.project_members.find_by(user_id: options[:user].id) + ] end expose :group_access, using: Entities::GroupAccess do |project, options| diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 77e407b54c5..3a1837effd8 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -287,6 +287,23 @@ module API # Projects helpers + def filter_params(projects) + project_entries = [] + + # Removes the redundant information of the object + projects.each do |project| + entry = { + id: project.id, + http_url_to_repo: project.http_url_to_repo, + name_with_namespace: project.name_with_namespace + } + + project_entries << entry + end + + project_entries + end + def filter_projects(projects) # If the archived parameter is passed, limit results accordingly if params[:archived].present? diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 0cc1edd65c8..deade7cad90 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -25,6 +25,8 @@ module API @projects = current_user.authorized_projects @projects = filter_projects(@projects) @projects = paginate @projects + @projects = filter_params(@projects) + puts present @projects, with: Entities::ProjectWithAccess, user: current_user present @projects, with: Entities::ProjectWithAccess, user: current_user end From 54a234b94062d3fb669fcbdd76ed4460a39eb3ca Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Wed, 6 Jul 2016 17:53:40 +0100 Subject: [PATCH 022/335] adds basic functionality to the new endpoint of the api --- lib/api/entities.rb | 16 ++++++++++++++-- lib/api/helpers.rb | 17 ----------------- lib/api/projects.rb | 13 +++++++++++-- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 757896fd59b..0f26a1f00a2 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -79,6 +79,12 @@ module API expose :public_builds end + class SimpleProject < Grape::Entity + expose :id + expose :name, :name_with_namespace + expose :http_url_to_repo + end + class ProjectMember < UserBasic expose :access_level do |user, options| options[:project].project_members.find_by(user_id: user.id).access_level @@ -328,12 +334,18 @@ module API end end + class SimpleProjectWithAccess < SimpleProject + expose :permissions do + expose :project_access, using: Entities::ProjectAccess do |project, options| + project.project_members.find_by(user_id: options[:user].id) + end + end + end + class ProjectWithAccess < Project expose :permissions do expose :project_access, using: Entities::ProjectAccess do |project, options| - project = Project.find_by(project[:id]) project.project_members.find_by(user_id: options[:user].id) - ] end expose :group_access, using: Entities::GroupAccess do |project, options| diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 3a1837effd8..77e407b54c5 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -287,23 +287,6 @@ module API # Projects helpers - def filter_params(projects) - project_entries = [] - - # Removes the redundant information of the object - projects.each do |project| - entry = { - id: project.id, - http_url_to_repo: project.http_url_to_repo, - name_with_namespace: project.name_with_namespace - } - - project_entries << entry - end - - project_entries - end - def filter_projects(projects) # If the archived parameter is passed, limit results accordingly if params[:archived].present? diff --git a/lib/api/projects.rb b/lib/api/projects.rb index deade7cad90..c1e66b239aa 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -25,11 +25,20 @@ module API @projects = current_user.authorized_projects @projects = filter_projects(@projects) @projects = paginate @projects - @projects = filter_params(@projects) - puts present @projects, with: Entities::ProjectWithAccess, user: current_user present @projects, with: Entities::ProjectWithAccess, user: current_user end + # Get a simplified project list for authenticated user + # + # Example Request: + # GET /projects/simple + get '/simple' do + @projects = current_user.authorized_projects + @projects = filter_projects(@projects) + @projects = paginate @projects + present @projects, with: Entities::SimpleProjectWithAccess, user: current_user + end + # Get an owned projects list for authenticated user # # Example Request: From c8407dd9cfa970de698ac50a0af636b1fa8df0b0 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Wed, 6 Jul 2016 12:15:28 -0500 Subject: [PATCH 023/335] Change new pipeline to run pipeline --- app/views/projects/pipelines/index.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml index 28b475d5c2f..a1b8454ecda 100644 --- a/app/views/projects/pipelines/index.html.haml +++ b/app/views/projects/pipelines/index.html.haml @@ -28,7 +28,7 @@ .nav-controls - if can? current_user, :create_pipeline, @project = link_to new_namespace_project_pipeline_path(@project.namespace, @project), class: 'btn btn-create' do - New pipeline + Run pipeline - unless @repository.gitlab_ci_yml = link_to 'Get started with Pipelines', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info' From 5ab95ba69a46ad23c41f395aea16d8a7a425eb41 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Wed, 6 Jul 2016 20:33:28 +0100 Subject: [PATCH 024/335] review changes --- .../javascripts/files_comment_button.js.coffee | 12 +++++++----- app/views/projects/diffs/_diffs.html.haml | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/files_comment_button.js.coffee b/app/assets/javascripts/files_comment_button.js.coffee index 2cc051b9e12..3941e181875 100644 --- a/app/assets/javascripts/files_comment_button.js.coffee +++ b/app/assets/javascripts/files_comment_button.js.coffee @@ -1,10 +1,10 @@ class @FilesCommentButton constructor: (@filesContainerElement) -> - return if not @filesContainerElement - return if not @filesContainerElement.data 'can-create-note' + return unless @filesContainerElement + return if _.isUndefined @filesContainerElement.data 'can-create-note' @COMMENT_BUTTON_CLASS = '.add-diff-note' - @COMMENT_BUTTON_TEMPLATE = _.template("") + @COMMENT_BUTTON_TEMPLATE = _.template '' @LINE_HOLDER_CLASS = '.line_holder' @LINE_NUMBER_CLASS = 'diff-line-num' @@ -37,7 +37,7 @@ class @FilesCommentButton lineContentElement = @getLineContent(currentTarget) buttonParentElement = @getButtonParent(currentTarget) - return if not @shouldRender e, buttonParentElement + return unless @shouldRender e, buttonParentElement buttonParentElement.append @buildButton id: @@ -58,7 +58,9 @@ class @FilesCommentButton return buildButton: (buttonAttributes) -> - $(@COMMENT_BUTTON_TEMPLATE COMMENT_BUTTON_CLASS: @COMMENT_BUTTON_CLASS.substr 1).attr + initializedButtonTemplate = @COMMENT_BUTTON_TEMPLATE + COMMENT_BUTTON_CLASS: @COMMENT_BUTTON_CLASS.substr 1 + $(initializedButtonTemplate).attr 'data-noteable-id': buttonAttributes.id.noteable 'data-commit-id': buttonAttributes.id.commit 'data-discussion-id': buttonAttributes.id.discussion diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index fea294628fe..94f765a097c 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -21,7 +21,7 @@ - if diff_files.overflow? = render 'projects/diffs/warning', diff_files: diff_files -.files{data: {can_create_note: (!@diff_notes_disabled && can?(current_user, :create_note, @project)).to_s}} +.files{data: {can_create_note: (!@diff_notes_disabled && can?(current_user, :create_note, @project))}} - diff_files.each_with_index do |diff_file, index| - diff_commit = commit_for_diff(diff_file) - blob = project.repository.blob_for_diff(diff_commit, diff_file) From d925aea9f388f8ca5c858e825e5303232fa16c1d Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Thu, 7 Jul 2016 02:12:15 +0100 Subject: [PATCH 025/335] flattened button attributes obj set to build comment button --- .../files_comment_button.js.coffee | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/app/assets/javascripts/files_comment_button.js.coffee b/app/assets/javascripts/files_comment_button.js.coffee index 3941e181875..171778e5347 100644 --- a/app/assets/javascripts/files_comment_button.js.coffee +++ b/app/assets/javascripts/files_comment_button.js.coffee @@ -40,16 +40,13 @@ class @FilesCommentButton return unless @shouldRender e, buttonParentElement buttonParentElement.append @buildButton - id: - noteable: textFileElement.attr 'data-noteable-id' - commit: textFileElement.attr 'data-commit-id' - discussion: lineContentElement.attr('data-discussion-id') or lineHolderElement.attr('data-discussion-id') - type: - noteable: textFileElement.attr 'data-noteable-type' - note: textFileElement.attr 'data-note-type' - line: lineContentElement.attr 'data-line-type' - code: - line: lineContentElement.attr('data-line-code') or lineHolderElement.attr('id') + commit_id: textFileElement.attr 'data-commit-id' + discussion_id: lineContentElement.attr('data-discussion-id') or lineHolderElement.attr('data-discussion-id') + line_code: lineContentElement.attr('data-line-code') or lineHolderElement.attr('id') + line_type: lineContentElement.attr 'data-line-type' + note_type: textFileElement.attr 'data-note-type' + noteable_id: textFileElement.attr 'data-noteable-id' + noteable_type: textFileElement.attr 'data-noteable-type' return destroy: (e) => @@ -61,13 +58,13 @@ class @FilesCommentButton initializedButtonTemplate = @COMMENT_BUTTON_TEMPLATE COMMENT_BUTTON_CLASS: @COMMENT_BUTTON_CLASS.substr 1 $(initializedButtonTemplate).attr - 'data-noteable-id': buttonAttributes.id.noteable - 'data-commit-id': buttonAttributes.id.commit - 'data-discussion-id': buttonAttributes.id.discussion - 'data-noteable-type': buttonAttributes.type.noteable - 'data-line-type': buttonAttributes.type.line - 'data-note-type': buttonAttributes.type.note - 'data-line-code': buttonAttributes.code.line + 'data-noteable-id': buttonAttributes.noteable_id + 'data-commit-id': buttonAttributes.commit_id + 'data-discussion-id': buttonAttributes.discussion_id + 'data-noteable-type': buttonAttributes.noteable_type + 'data-line-type': buttonAttributes.line_type + 'data-note-type': buttonAttributes.note_type + 'data-line-code': buttonAttributes.line_code getTextFileElement: (hoveredElement) -> $(hoveredElement.closest(@TEXT_FILE_SELECTOR)) From 22be862892797af68a84240004765d3db657ab20 Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Sun, 26 Jun 2016 17:10:55 +0900 Subject: [PATCH 026/335] Clean up coffeescript files imported from GitLab CI --- app/assets/javascripts/application.js.coffee | 1 - app/assets/javascripts/{ci => }/build.coffee | 0 app/assets/javascripts/ci/application.js.coffee | 12 ------------ app/assets/javascripts/ci/projects.js.coffee | 3 --- 4 files changed, 16 deletions(-) rename app/assets/javascripts/{ci => }/build.coffee (100%) delete mode 100644 app/assets/javascripts/ci/application.js.coffee delete mode 100644 app/assets/javascripts/ci/projects.js.coffee diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index 20fe5a5cc27..6c3f3da0f94 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -47,7 +47,6 @@ #= require date.format #= require_directory ./behaviors #= require_directory ./blob -#= require_directory ./ci #= require_directory ./commit #= require_directory ./extensions #= require_directory ./lib/utils diff --git a/app/assets/javascripts/ci/build.coffee b/app/assets/javascripts/build.coffee similarity index 100% rename from app/assets/javascripts/ci/build.coffee rename to app/assets/javascripts/build.coffee diff --git a/app/assets/javascripts/ci/application.js.coffee b/app/assets/javascripts/ci/application.js.coffee deleted file mode 100644 index ca24c1d759f..00000000000 --- a/app/assets/javascripts/ci/application.js.coffee +++ /dev/null @@ -1,12 +0,0 @@ -#= require pager -#= require jquery_nested_form -#= require_tree . - -$(document).on 'click', '.assign-all-runner', -> - $(this).replaceWith(' Assign in progress..') - -window.unbindEvents = -> - $(document).unbind('scroll') - $(document).off('scroll') - -document.addEventListener("page:fetch", unbindEvents) diff --git a/app/assets/javascripts/ci/projects.js.coffee b/app/assets/javascripts/ci/projects.js.coffee deleted file mode 100644 index e6406011d11..00000000000 --- a/app/assets/javascripts/ci/projects.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -$(document).on 'click', '.badge-codes-toggle', -> - $('.badge-codes-block').toggleClass("hide") - return false From 1569dfd6cdf004a7d195dc0b8cd92396019dd54e Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Sun, 26 Jun 2016 17:13:54 +0900 Subject: [PATCH 027/335] Rename CiBuild as Build --- app/assets/javascripts/build.coffee | 6 +++--- app/views/projects/builds/show.html.haml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/build.coffee b/app/assets/javascripts/build.coffee index 74691b2c1b5..cf203ea43a0 100644 --- a/app/assets/javascripts/build.coffee +++ b/app/assets/javascripts/build.coffee @@ -1,9 +1,9 @@ -class @CiBuild +class @Build @interval: null @state: null constructor: (@page_url, @build_url, @build_status, @state) -> - clearInterval(CiBuild.interval) + clearInterval(Build.interval) # Init breakpoint checker @bp = Breakpoints.get() @@ -40,7 +40,7 @@ class @CiBuild # Check for new build output if user still watching build page # Only valid for runnig build when output changes during time # - CiBuild.interval = setInterval => + Build.interval = setInterval => if window.location.href.split("#").first() is @page_url @getBuildTrace() , 4000 diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml index 4e801cc72fe..4421f3b9562 100644 --- a/app/views/projects/builds/show.html.haml +++ b/app/views/projects/builds/show.html.haml @@ -67,4 +67,4 @@ = render "sidebar" :javascript - new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build)}", "#{namespace_project_build_url(@project.namespace, @project, @build, :json)}", "#{@build.status}", "#{trace_with_state[:state]}") + new Build("#{namespace_project_build_url(@project.namespace, @project, @build)}", "#{namespace_project_build_url(@project.namespace, @project, @build, :json)}", "#{@build.status}", "#{trace_with_state[:state]}") From bf40aab4db26c378a83455c464c1b98bb4fa154e Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 28 Jun 2016 16:12:04 +0100 Subject: [PATCH 028/335] GL dropdowns in issuable form This allows labels to be created on whilst creating/editing an issuable Closes #12574 --- app/assets/javascripts/dispatcher.js.coffee | 2 ++ .../javascripts/labels_select.js.coffee | 31 ++++++++++------ .../javascripts/milestone_select.js.coffee | 2 +- app/assets/javascripts/users_select.js.coffee | 8 +++-- .../stylesheets/pages/merge_requests.scss | 4 +++ app/views/shared/issuable/_filter.html.haml | 4 +-- app/views/shared/issuable/_form.html.haml | 35 ++++++------------- .../shared/issuable/_label_dropdown.html.haml | 14 ++++---- .../issuable/_milestone_dropdown.html.haml | 8 ++--- 9 files changed, 58 insertions(+), 50 deletions(-) diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index 9493a575801..31b88308915 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -39,6 +39,8 @@ class Dispatcher shortcut_handler = new ShortcutsNavigation() new GLForm($('.issue-form')) new IssuableForm($('.issue-form')) + new LabelsSelect() + new MilestoneSelect() when 'projects:merge_requests:new', 'projects:merge_requests:edit' new Diff() shortcut_handler = new ShortcutsNavigation() diff --git a/app/assets/javascripts/labels_select.js.coffee b/app/assets/javascripts/labels_select.js.coffee index 7688609b301..1a802b81452 100644 --- a/app/assets/javascripts/labels_select.js.coffee +++ b/app/assets/javascripts/labels_select.js.coffee @@ -184,20 +184,22 @@ class @LabelsSelect .value() if $dropdown.hasClass 'js-extra-options' - if showNo - data.unshift( - id: 0 - title: 'No Label' - ) - + extraData = [] if showAny - data.unshift( + extraData.push( isAny: true title: 'Any Label' ) - if data.length > 2 - data.splice 2, 0, 'divider' + if showNo + extraData.push( + id: 0 + title: 'No Label' + ) + + if extraData.length + extraData.push 'divider' + data = extraData.concat(data) callback data @@ -287,6 +289,12 @@ class @LabelsSelect defaultLabel fieldName: $dropdown.data('field-name') id: (label) -> + if $dropdown.hasClass('js-issuable-form-dropdown') + if label.id is 0 + return + else + return label.id + if $dropdown.hasClass("js-filter-submit") and not label.isAny? label.title else @@ -300,6 +308,9 @@ class @LabelsSelect $selectbox.hide() # display:block overrides the hide-collapse rule $value.removeAttr('style') + + return if $dropdown.hasClass('js-issuable-form-dropdown') + if $dropdown.hasClass 'js-multiselect' if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex) selectedLabels = $dropdown @@ -321,7 +332,7 @@ class @LabelsSelect clicked: (label) -> _this.enableBulkLabelDropdown() - if $dropdown.hasClass('js-filter-bulk-update') + if $dropdown.hasClass('js-filter-bulk-update') or $dropdown.hasClass('js-issuable-form-dropdown') return page = $('body').data 'page' diff --git a/app/assets/javascripts/milestone_select.js.coffee b/app/assets/javascripts/milestone_select.js.coffee index 8ab03ed93ee..3a036569317 100644 --- a/app/assets/javascripts/milestone_select.js.coffee +++ b/app/assets/javascripts/milestone_select.js.coffee @@ -62,7 +62,7 @@ class @MilestoneSelect title: 'Upcoming' ) - if extraOptions.length > 2 + if extraOptions.length > 0 extraOptions.push 'divider' callback(extraOptions.concat(data)) diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index 4e032ab1ff1..95daa1c442f 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -151,11 +151,13 @@ class @UsersSelect # display:block overrides the hide-collapse rule $value.css('display', '') - clicked: (user) -> + clicked: (user, $el, e) -> page = $('body').data 'page' isIssueIndex = page is 'projects:issues:index' isMRIndex = page is page is 'projects:merge_requests:index' if $dropdown.hasClass('js-filter-bulk-update') + e.preventDefault() + selectedId = user.id return if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex) @@ -168,7 +170,9 @@ class @UsersSelect .closest('.selectbox') .find("input[name='#{$dropdown.data('field-name')}']").val() assignTo(selected) - + id: (user) -> + return if user.id is 0 + user.id renderRow: (user) -> username = if user.username then "@#{user.username}" else "" avatar = if user.avatar_url then user.avatar_url else false diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index d9756b66af0..ad1c0116a3e 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -321,6 +321,10 @@ .issuable-form-select-holder { display: inline-block; width: 250px; + + .dropdown-menu-toggle { + width: 100%; + } } .table-holder { diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index 094d6636c66..d5199bd86dd 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -21,10 +21,10 @@ placeholder: "Search assignee", data: { any_user: "Any Assignee", first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: params[:assignee_id], field_name: "assignee_id", default_label: "Assignee" } }) .filter-item.inline.milestone-filter - = render "shared/issuable/milestone_dropdown" + = render "shared/issuable/milestone_dropdown", selected: params[:milestone_title], name: :milestone_title, show_any: true, show_upcoming: true .filter-item.inline.labels-filter - = render "shared/issuable/label_dropdown" + = render "shared/issuable/label_dropdown", selected: params[:label_name], data_options: { field_name: "label_name[]" } .pull-right = render 'shared/sort_dropdown' diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index c30bdb0ae91..78c42e6895e 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -52,38 +52,23 @@ = f.label :assignee_id, "Assignee", class: "control-label #{"col-lg-4" if has_due_date}" .col-sm-10{ class: ("col-lg-8" if has_due_date) } .issuable-form-select-holder - = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]", - placeholder: 'Select assignee', class: 'custom-form-control', null_user: true, - selected: issuable.assignee_id, project: @target_project || @project, - first_user: true, current_user: true, include_blank: true) - %div - = link_to 'Assign to me', '#', class: 'assign-to-me-link prepend-top-5 inline' + - if issuable.assignee_id + = hidden_field_tag("#{issuable.class.model_name.param_key}[assignee_id]", issuable.assignee_id) + = dropdown_tag(user_dropdown_label(issuable.assignee_id, "Assignee"), options: { toggle_class: "js-user-search js-filter-bulk-update js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit", + placeholder: "Search assignee", data: { first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: issuable.assignee_id, field_name: "#{issuable.class.model_name.param_key}[assignee_id]", default_label: "Assignee" } }) .form-group.issue-milestone = f.label :milestone_id, "Milestone", class: "control-label #{"col-lg-4" if has_due_date}" .col-sm-10{ class: ("col-lg-8" if has_due_date) } - - if milestone_options(issuable).present? - .issuable-form-select-holder - = f.select(:milestone_id, milestone_options(issuable), - { include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } }) - - else - .prepend-top-10 - %span.light No open milestones available. - - if can? current_user, :admin_milestone, issuable.project - %div - = link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline" + .issuable-form-select-holder + = render "shared/issuable/milestone_dropdown", selected: issuable.milestone_id, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false .form-group - has_labels = issuable.project.labels.any? + - selected_labels = issuable.label_ids.any? ? issuable.label_ids : nil + - label_dropdown_toggle = issuable.labels.map { |label| label.title } = f.label :label_ids, "Labels", class: "control-label #{"col-lg-4" if has_due_date}" .col-sm-10{ class: "#{"col-lg-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" } - - if has_labels - .issuable-form-select-holder - = f.collection_select :label_ids, issuable.project.labels.all, :id, :name, - { selected: issuable.label_ids }, multiple: true, class: 'select2', data: { placeholder: "Select labels" } - - else - %span.light No labels yet. - - if can? current_user, :admin_label, issuable.project - %div - = link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline" + .issuable-form-select-holder + = render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: selected_labels, selected_toggle: label_dropdown_toggle, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: "false" } - if has_due_date .col-lg-6 .form-group diff --git a/app/views/shared/issuable/_label_dropdown.html.haml b/app/views/shared/issuable/_label_dropdown.html.haml index d34d28f6736..bcbe133ce62 100644 --- a/app/views/shared/issuable/_label_dropdown.html.haml +++ b/app/views/shared/issuable/_label_dropdown.html.haml @@ -4,19 +4,21 @@ - show_footer = local_assigns.fetch(:show_footer, true) - data_options = local_assigns.fetch(:data_options, {}) - classes = local_assigns.fetch(:classes, []) -- dropdown_data = {toggle: 'dropdown', field_name: 'label_name[]', show_no: "true", show_any: "true", selected: params[:label_name], project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"} +- selected = local_assigns.fetch(:selected, nil) +- selected_toggle = local_assigns.fetch(:selected_toggle, nil) +- dropdown_data = {toggle: 'dropdown', field_name: "label_name[]", show_no: "true", show_any: "true", selected: selected, project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"} - dropdown_data.merge!(data_options) - classes << 'js-extra-options' if extra_options - classes << 'js-filter-submit' if filter_submit -- if params[:label_name].present? - - if params[:label_name].respond_to?('any?') - - params[:label_name].each do |label| - = hidden_field_tag "label_name[]", label, id: nil +- if selected.present? + - if selected.respond_to?('any?') + - selected.each do |label| + = hidden_field_tag data_options[:field_name], label, id: nil .dropdown %button.dropdown-menu-toggle.js-label-select.js-multiselect{class: classes.join(' '), type: "button", data: dropdown_data} %span.dropdown-toggle-text - = h(multi_label_name(params[:label_name], "Label")) + = h(multi_label_name(selected_toggle || selected, "Label")) = icon('chevron-down') .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable = render partial: "shared/issuable/label_page_default", locals: { title: "Filter by label", show_footer: show_footer, show_create: show_create } diff --git a/app/views/shared/issuable/_milestone_dropdown.html.haml b/app/views/shared/issuable/_milestone_dropdown.html.haml index 2fcf40ece99..9188ef72d52 100644 --- a/app/views/shared/issuable/_milestone_dropdown.html.haml +++ b/app/views/shared/issuable/_milestone_dropdown.html.haml @@ -1,7 +1,7 @@ -- if params[:milestone_title].present? - = hidden_field_tag(:milestone_title, params[:milestone_title]) -= dropdown_tag(milestone_dropdown_label(params[:milestone_title]), options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable", - placeholder: "Search milestones", footer_content: @project.present?, data: { show_no: true, show_any: true, show_upcoming: true, field_name: "milestone_title", selected: params[:milestone_title], project_id: @project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do +- if selected.present? + = hidden_field_tag(name, selected) += dropdown_tag(milestone_dropdown_label(selected), options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable", + placeholder: "Search milestones", footer_content: @project.present?, data: { show_no: true, show_any: show_any, show_upcoming: show_upcoming, field_name: name, selected: selected, project_id: @project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do - if @project %ul.dropdown-footer-list - if can? current_user, :admin_milestone, @project From a6b4164017961add393e6cc863dc5e0c3d9c7f69 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 29 Jun 2016 16:15:45 +0100 Subject: [PATCH 029/335] Updated tests --- app/assets/javascripts/users_select.js.coffee | 3 +-- app/helpers/issuables_helper.rb | 2 +- app/views/shared/issuable/_form.html.haml | 5 +++-- features/project/issues/issues.feature | 1 + features/steps/project/forked_merge_requests.rb | 12 +++++------- features/steps/project/issues/issues.rb | 3 ++- spec/features/issues/move_spec.rb | 2 +- spec/features/issues_spec.rb | 5 ++--- 8 files changed, 16 insertions(+), 17 deletions(-) diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index 95daa1c442f..c84c4960657 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -155,7 +155,7 @@ class @UsersSelect page = $('body').data 'page' isIssueIndex = page is 'projects:issues:index' isMRIndex = page is page is 'projects:merge_requests:index' - if $dropdown.hasClass('js-filter-bulk-update') + if $dropdown.hasClass('js-filter-bulk-update') or $dropdown.hasClass('js-issuable-form-dropdown') e.preventDefault() selectedId = user.id return @@ -171,7 +171,6 @@ class @UsersSelect .find("input[name='#{$dropdown.data('field-name')}']").val() assignTo(selected) id: (user) -> - return if user.id is 0 user.id renderRow: (user) -> username = if user.username then "@#{user.username}" else "" diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 294b7e92b8d..f854cbb2a1a 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -9,7 +9,7 @@ module IssuablesHelper def multi_label_name(current_labels, default_label) # current_labels may be a string from before - if current_labels.is_a?(Array) + if current_labels.is_a?(Array) && current_labels.any? if current_labels.count > 1 "#{current_labels[0]} +#{current_labels.count - 1} more" else diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index 78c42e6895e..a8a8426df52 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -52,10 +52,11 @@ = f.label :assignee_id, "Assignee", class: "control-label #{"col-lg-4" if has_due_date}" .col-sm-10{ class: ("col-lg-8" if has_due_date) } .issuable-form-select-holder + - project = @target_project || @project - if issuable.assignee_id = hidden_field_tag("#{issuable.class.model_name.param_key}[assignee_id]", issuable.assignee_id) - = dropdown_tag(user_dropdown_label(issuable.assignee_id, "Assignee"), options: { toggle_class: "js-user-search js-filter-bulk-update js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit", - placeholder: "Search assignee", data: { first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: issuable.assignee_id, field_name: "#{issuable.class.model_name.param_key}[assignee_id]", default_label: "Assignee" } }) + = dropdown_tag(user_dropdown_label(issuable.assignee_id, "Assignee"), options: { toggle_class: "js-user-search js-issuable-form-dropdown js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit", + placeholder: "Search assignee", data: { first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (project.id if project), selected: issuable.assignee_id, field_name: "#{issuable.class.model_name.param_key}[assignee_id]", default_label: "Assignee" } }) .form-group.issue-milestone = f.label :milestone_id, "Milestone", class: "control-label #{"col-lg-4" if has_due_date}" .col-sm-10{ class: ("col-lg-8" if has_due_date) } diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature index 358e622b736..80670063ea0 100644 --- a/features/project/issues/issues.feature +++ b/features/project/issues/issues.feature @@ -37,6 +37,7 @@ Feature: Project Issues And I submit new issue "500 error on profile" Then I should see issue "500 error on profile" + @javascript Scenario: I submit new unassigned issue with labels Given project "Shop" has labels: "bug", "feature", "enhancement" And I click link "New Issue" diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb index 6b56a77b832..8f71dfdd899 100644 --- a/features/steps/project/forked_merge_requests.rb +++ b/features/steps/project/forked_merge_requests.rb @@ -135,19 +135,17 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps end step 'I click "Assign to" dropdown"' do - first('.ajax-users-select').click + click_button 'Assignee' end step 'I should see the target project ID in the input selector' do - expect(page).to have_selector("input[data-project-id=\"#{@project.id}\"]") + expect(find('.js-assignee-search')["data-project-id"]).to eq "#{@project.id}" end step 'I should see the users from the target project ID' do - expect(page).to have_selector('.user-result', visible: true, count: 3) - users = page.all('.user-name') - expect(users[0].text).to eq 'Unassigned' - expect(users[1].text).to eq current_user.name - expect(users[2].text).to eq @project.users.first.name + expect(page).to have_content 'Unassigned' + expect(page).to have_content current_user.name + expect(page).to have_content @project.users.first.name end # Verify a link is generated against the correct project diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb index 35f166c7c08..b785e15f70e 100644 --- a/features/steps/project/issues/issues.rb +++ b/features/steps/project/issues/issues.rb @@ -82,7 +82,8 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps step 'I submit new issue "500 error on profile" with label \'bug\'' do fill_in "issue_title", with: "500 error on profile" - select 'bug', from: "Labels" + click_button "Label" + click_link "bug" click_button "Submit issue" end diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb index 7773c486b4e..055210399a7 100644 --- a/spec/features/issues/move_spec.rb +++ b/spec/features/issues/move_spec.rb @@ -55,7 +55,7 @@ feature 'issue move to another project' do first('.select2-choice').click end - fill_in('s2id_autogen2_search', with: new_project_search.name) + fill_in('s2id_autogen1_search', with: new_project_search.name) page.within '.select2-drop' do expect(page).to have_content(new_project_search.name) diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index d51c9abea19..d00cffa4e2b 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -50,9 +50,8 @@ describe 'Issues', feature: true do expect(page).to have_content "Assignee #{@user.name}" - first('#s2id_issue_assignee_id').click - sleep 2 # wait for ajax stuff to complete - first('.user-result').click + first('.js-user-search').click + click_link 'Unassigned' click_button 'Save changes' From afbd631c78bea27ea7e088c090e947959285a176 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 7 Jul 2016 09:44:30 +0100 Subject: [PATCH 030/335] Dropdown chevron alignment --- app/assets/stylesheets/framework/dropdowns.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index f36736c475e..fe41845022e 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -56,7 +56,7 @@ position: absolute; top: 50%; right: 6px; - margin-top: -4px; + margin-top: -6px; color: $dropdown-toggle-icon-color; font-size: 10px; } From e3b5912d634f0b879a1ebc23fa38e6f21ffcae74 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Thu, 7 Jul 2016 11:55:31 +0100 Subject: [PATCH 031/335] gets the new object through /simple endpoint and renders on the dropdown --- app/assets/javascripts/api.js.coffee | 2 +- app/assets/javascripts/gl_dropdown.js.coffee | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee index cf46f15a156..45059ae4042 100644 --- a/app/assets/javascripts/api.js.coffee +++ b/app/assets/javascripts/api.js.coffee @@ -3,7 +3,7 @@ groupPath: "/api/:version/groups/:id.json" namespacesPath: "/api/:version/namespaces.json" groupProjectsPath: "/api/:version/groups/:id/projects.json" - projectsPath: "/api/:version/projects.json" + projectsPath: "/api/:version/projects/simple.json" labelsPath: "/api/:version/projects/:id/labels" licensePath: "/api/:version/licenses/:key" gitignorePath: "/api/:version/gitignores/:key" diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index ed9dfcc917e..7c43e523572 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -122,6 +122,7 @@ class GitLabDropdownRemote # Fetch the data by calling the data funcfion @dataEndpoint "", (data) => + console.log(data) if @options.success @options.success(data) From 12791b9edaae24b0b10ff88edef83f64ac413102 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Thu, 7 Jul 2016 11:55:58 +0100 Subject: [PATCH 032/335] removes debugging print --- app/assets/javascripts/gl_dropdown.js.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 7c43e523572..ed9dfcc917e 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -122,7 +122,6 @@ class GitLabDropdownRemote # Fetch the data by calling the data funcfion @dataEndpoint "", (data) => - console.log(data) if @options.success @options.success(data) From 4c43ba8b1924fcb877a52bd622cd93074ae73584 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Thu, 7 Jul 2016 12:20:51 +0100 Subject: [PATCH 033/335] adds entry to changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 4fac555e12a..98bd11af833 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.10.0 (unreleased) + - Fix projects dropdown loading performance with a simplified api cal. !5113 (tiagonbotelho) - Fix commit builds API, return all builds for all pipelines for given commit. !4849 - Replace Haml with Hamlit to make view rendering faster. !3666 - Refactor repository paths handling to allow multiple git mount points From eda205342140e1bc71b5f0b6935b5ffc502a85cd Mon Sep 17 00:00:00 2001 From: Patricio Cano Date: Mon, 4 Jul 2016 18:29:10 -0500 Subject: [PATCH 034/335] Move Omniauth specific setup to its own file --- spec/spec_helper.rb | 4 +--- spec/support/omni_auth.rb | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 spec/support/omni_auth.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 537aa46a2fd..09ff5a18a35 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -56,6 +56,4 @@ FactoryGirl::SyntaxRunner.class_eval do include RSpec::Mocks::ExampleMethods end -ActiveRecord::Migration.maintain_test_schema! - -OmniAuth.config.test_mode = true +ActiveRecord::Migration.maintain_test_schema! \ No newline at end of file diff --git a/spec/support/omni_auth.rb b/spec/support/omni_auth.rb new file mode 100644 index 00000000000..3d262ff9ca0 --- /dev/null +++ b/spec/support/omni_auth.rb @@ -0,0 +1 @@ +OmniAuth.config.test_mode = true \ No newline at end of file From 2a0be666e3078e28a02de298b386ec4c09232978 Mon Sep 17 00:00:00 2001 From: Patricio Cano Date: Tue, 5 Jul 2016 16:34:34 -0500 Subject: [PATCH 035/335] Added a lot of stubbing to make sure OAUth requests are handled properly with 2FA --- spec/features/login_spec.rb | 19 ++++++++++++++++++- spec/spec_helper.rb | 2 +- spec/support/login_helpers.rb | 10 ++++++++++ spec/support/omni_auth.rb | 2 +- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb index 39968db5b58..58753ff21f6 100644 --- a/spec/features/login_spec.rb +++ b/spec/features/login_spec.rb @@ -110,12 +110,29 @@ feature 'Login', feature: true do end context 'logging in via OAuth' do + def saml_config + OpenStruct.new(name: 'saml', label: 'saml', args: { + assertion_consumer_service_url: 'https://localhost:3443/users/auth/saml/callback', + idp_cert_fingerprint: '26:43:2C:47:AF:F0:6B:D0:07:9C:AD:A3:74:FE:5D:94:5F:4E:9E:52', + idp_sso_target_url: 'https://idp.example.com/sso/saml', + issuer: 'https://localhost:3443/', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient' + }) + end + def stub_omniauth_config(messages) + Rails.application.env_config['devise.mapping'] = Devise.mappings[:user] + Rails.application.routes.disable_clear_and_finalize = true + Rails.application.routes.draw do + post '/users/auth/saml' => 'omniauth_callbacks#saml' + end + allow(Gitlab::OAuth::Provider).to receive_messages(providers: [:saml], config_for: saml_config) allow(Gitlab.config.omniauth).to receive_messages(messages) + allow_any_instance_of(Object).to receive(:user_omniauth_authorize_path).with('saml').and_return('/users/auth/saml') end it 'should show 2FA prompt after OAuth login' do - stub_omniauth_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [OpenStruct.new(name: 'saml', label: 'saml', args: {})]) + stub_omniauth_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [saml_config]) user = create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: 'saml') login_via('saml', user, 'my-uid') diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 09ff5a18a35..b43f38ef202 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -56,4 +56,4 @@ FactoryGirl::SyntaxRunner.class_eval do include RSpec::Mocks::ExampleMethods end -ActiveRecord::Migration.maintain_test_schema! \ No newline at end of file +ActiveRecord::Migration.maintain_test_schema! diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index f9ce929000c..2e400dd825a 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -39,6 +39,7 @@ module LoginHelpers def login_via(provider, user, uid) mock_auth_hash(provider, uid, user.email) + Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[:saml] visit new_user_session_path click_link provider end @@ -57,6 +58,15 @@ module LoginHelpers credentials: { token: 'mock_token', secret: 'mock_secret' + }, + extra: { + raw_info: { + info: { + name: 'mockuser', + email: email, + image: 'mock_user_thumbnail_url' + } + } } }) end diff --git a/spec/support/omni_auth.rb b/spec/support/omni_auth.rb index 3d262ff9ca0..0b1af4052ff 100644 --- a/spec/support/omni_auth.rb +++ b/spec/support/omni_auth.rb @@ -1 +1 @@ -OmniAuth.config.test_mode = true \ No newline at end of file +OmniAuth.config.test_mode = true From 71e4175f654a5e6b1e20f03966af49bf9af65f37 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 7 Jul 2016 18:09:19 -0400 Subject: [PATCH 036/335] Fix behavior around MRs that need legacy diff notes --- app/helpers/notes_helper.rb | 49 +++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index efb648bd8a2..16dd69ce5f6 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -25,14 +25,15 @@ module NotesHelper end def diff_view_data - return {} unless defined?(@comments_target) && @comments_target.any? + return {} unless @comments_target @comments_target.slice(:noteable_id, :noteable_type, :commit_id) end - def use_legacy_diff_notes?(line_code) - return @use_legacy_diff_notes if defined?(@use_legacy_diff_notes) + def diff_view_line_data(line_code, position, line_type) + return if @diff_notes_disabled + use_legacy_diff_note = @use_legacy_diff_notes # If the controller doesn't force the use of legacy diff notes, we # determine this on a line-by-line basis by seeing if there already exist # active legacy diff notes at this line, in which case newly created notes @@ -42,36 +43,42 @@ module NotesHelper # are incompatible. # If we didn't, diff notes that would show for the same line on the changes # tab, would show in different discussions on the discussion tab. - line_diff_notes = @grouped_diff_notes[line_code] - @use_legacy_diff_notes = line_diff_notes && line_diff_notes.any?(&:legacy_diff_note?) - end + use_legacy_diff_note ||= begin + line_diff_notes = @grouped_diff_notes[line_code] + @use_legacy_diff_notes = line_diff_notes && line_diff_notes.any?(&:legacy_diff_note?) + end - def diff_view_line_data(line_code, position, line_type) - return if @diff_notes_disabled - - { + data = { line_code: line_code, - position: position.to_json, line_type: line_type, - note_type: (use_legacy_diff_notes?(line_code) ? LegacyDiffNote.name : DiffNote.name), - discussion_id: discussion_id(line_code, position) } - end - def discussion_id(line_code, position) - if use_legacy_diff_notes?(line_code) - LegacyDiffNote.build_discussion_id( + if use_legacy_diff_note + discussion_id = LegacyDiffNote.build_discussion_id( @comments_target[:noteable_type], @comments_target[:noteable_id] || @comments_target[:commit_id], line_code ) + + data.merge!( + note_type: LegacyDiffNote.name, + discussion_id: discussion_id + ) else discussion_id = DiffNote.build_discussion_id( - @comments_target[:noteable_type], - @comments_target[:noteable_id] || @comments_target[:commit_id], - position - ) + @comments_target[:noteable_type], + @comments_target[:noteable_id] || @comments_target[:commit_id], + position + ) + + data.merge!( + position: position.to_json, + note_type: DiffNote.name, + discussion_id: discussion_id + ) end + + data end def link_to_reply_discussion(note, line_type = nil) From 1f73afd0452b7f324b5c1f6e3ffeec7110c77f31 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Fri, 8 Jul 2016 00:41:38 +0100 Subject: [PATCH 037/335] Registered FilesCommentButton as a jQuery plugin and made review changes --- app/assets/javascripts/diff.js.coffee | 2 +- .../files_comment_button.js.coffee | 118 +++++++++--------- .../javascripts/merge_request_tabs.js.coffee | 2 +- .../projects/diffs/_parallel_view.html.haml | 4 +- 4 files changed, 62 insertions(+), 64 deletions(-) diff --git a/app/assets/javascripts/diff.js.coffee b/app/assets/javascripts/diff.js.coffee index ddb43f02dec..83516f97552 100644 --- a/app/assets/javascripts/diff.js.coffee +++ b/app/assets/javascripts/diff.js.coffee @@ -1,7 +1,7 @@ class @Diff UNFOLD_COUNT = 20 constructor: -> - @filesCommentButton = new FilesCommentButton($('.files')) + @filesCommentButton = $('.files .diff-file').filesCommentButton() $(document).off('click', '.js-unfold') $(document).on('click', '.js-unfold', (event) => diff --git a/app/assets/javascripts/files_comment_button.js.coffee b/app/assets/javascripts/files_comment_button.js.coffee index 595a09e4146..2b9dc6419d5 100644 --- a/app/assets/javascripts/files_comment_button.js.coffee +++ b/app/assets/javascripts/files_comment_button.js.coffee @@ -1,95 +1,93 @@ class @FilesCommentButton + COMMENT_BUTTON_CLASS = '.add-diff-note' + COMMENT_BUTTON_TEMPLATE = _.template '' + LINE_HOLDER_CLASS = '.line_holder' + LINE_NUMBER_CLASS = 'diff-line-num' + LINE_CONTENT_CLASS = 'line_content' + UNFOLDABLE_LINE_CLASS = 'js-unfold' + EMPTY_CELL_CLASS = 'empty-cell' + OLD_LINE_CLASS = 'old_line' + LINE_COLUMN_CLASSES = ".#{LINE_NUMBER_CLASS}, .line_content" + TEXT_FILE_SELECTOR = '.text-file' + DEBOUNCE_TIMEOUT_DURATION = 100 + constructor: (@filesContainerElement) -> - return unless @filesContainerElement - return if _.isUndefined @filesContainerElement.data 'can-create-note' - - @COMMENT_BUTTON_CLASS = '.add-diff-note' - @COMMENT_BUTTON_TEMPLATE = _.template '' - - @LINE_NUMBER_CLASS = 'diff-line-num' - @LINE_CONTENT_CLASS = 'line_content' - @UNFOLDABLE_LINE_CLASS = 'js-unfold' - @EMPTY_CELL_CLASS = 'empty-cell' - @OLD_LINE_CLASS = 'old_line' - @LINE_COLUMN_CLASSES = ".#{@LINE_NUMBER_CLASS}, .line_content" - @TEXT_FILE_SELECTOR = '.text-file' - - @DEBOUNCE_TIMEOUT_DURATION = 150 - @VIEW_TYPE = $('input#view[type=hidden]').val() + debounce = _.debounce @render, DEBOUNCE_TIMEOUT_DURATION + $(document) - .on 'mouseover', @LINE_COLUMN_CLASSES, @debounceRender - .on 'mouseleave', @LINE_COLUMN_CLASSES, @destroy - - debounceRender: (e) => - clearTimeout @debounceTimeout if @debounceTimeout - @debounceTimeout = setTimeout => - @render e - , @DEBOUNCE_TIMEOUT_DURATION - return - - render: (e) -> - currentTarget = $(e.currentTarget) - textFileElement = @getTextFileElement(currentTarget) - lineContentElement = @getLineContent(currentTarget) - buttonParentElement = @getButtonParent(currentTarget) + .on 'mouseover', LINE_COLUMN_CLASSES, debounce + .on 'mouseleave', LINE_COLUMN_CLASSES, @destroy + render: (e) => + $currentTarget = $(e.currentTarget) + buttonParentElement = @getButtonParent $currentTarget return unless @shouldRender e, buttonParentElement + textFileElement = @getTextFileElement $currentTarget + lineContentElement = @getLineContent $currentTarget + buttonParentElement.append @buildButton - noteable_type: textFileElement.attr 'data-noteable-type' - noteable_id: textFileElement.attr 'data-noteable-id' - commit_id: textFileElement.attr 'data-commit-id' - note_type: lineContentElement.attr 'data-note-type' + noteableType: textFileElement.attr 'data-noteable-type' + noteableID: textFileElement.attr 'data-noteable-id' + commitID: textFileElement.attr 'data-commit-id' + noteType: lineContentElement.attr 'data-note-type' position: lineContentElement.attr 'data-position' - line_type: lineContentElement.attr 'data-line-type' - discussion_id: lineContentElement.attr 'data-discussion-id' - line_code: lineContentElement.attr 'data-line-code' + lineType: lineContentElement.attr 'data-line-type' + discussionID: lineContentElement.attr 'data-discussion-id' + lineCode: lineContentElement.attr 'data-line-code' return destroy: (e) => return if @isMovingToSameType e - $(@COMMENT_BUTTON_CLASS, @getButtonParent $(e.currentTarget)).remove() + $(COMMENT_BUTTON_CLASS, @getButtonParent $(e.currentTarget)).remove() return buildButton: (buttonAttributes) -> - initializedButtonTemplate = @COMMENT_BUTTON_TEMPLATE - COMMENT_BUTTON_CLASS: @COMMENT_BUTTON_CLASS.substr 1 + initializedButtonTemplate = COMMENT_BUTTON_TEMPLATE + COMMENT_BUTTON_CLASS: COMMENT_BUTTON_CLASS.substr 1 $(initializedButtonTemplate).attr - 'data-noteable-type': buttonAttributes.noteable_type - 'data-noteable-id': buttonAttributes.noteable_id - 'data-commit-id': buttonAttributes.commit_id - 'data-note-type': buttonAttributes.note_type - 'data-line-code': buttonAttributes.line_code + 'data-noteable-type': buttonAttributes.noteableType + 'data-noteable-id': buttonAttributes.noteableID + 'data-commit-id': buttonAttributes.commitID + 'data-note-type': buttonAttributes.noteType + 'data-line-code': buttonAttributes.lineCode 'data-position': buttonAttributes.position - 'data-discussion-id': buttonAttributes.discussion_id - 'data-line-type': buttonAttributes.line_type + 'data-discussion-id': buttonAttributes.discussionID + 'data-line-type': buttonAttributes.lineType getTextFileElement: (hoveredElement) -> - $(hoveredElement.closest(@TEXT_FILE_SELECTOR)) + $(hoveredElement.closest TEXT_FILE_SELECTOR) getLineContent: (hoveredElement) -> - return hoveredElement if hoveredElement.hasClass @LINE_CONTENT_CLASS + return hoveredElement if hoveredElement.hasClass LINE_CONTENT_CLASS - $(hoveredElement).next ".#{@LINE_CONTENT_CLASS}" + $(hoveredElement).next ".#{LINE_CONTENT_CLASS}" getButtonParent: (hoveredElement) -> if @VIEW_TYPE is 'inline' - return hoveredElement if hoveredElement.hasClass @OLD_LINE_CLASS + return hoveredElement if hoveredElement.hasClass OLD_LINE_CLASS - $(hoveredElement).parent().find ".#{@OLD_LINE_CLASS}" + hoveredElement.parent().find ".#{OLD_LINE_CLASS}" else - return hoveredElement if hoveredElement.hasClass @LINE_NUMBER_CLASS + return hoveredElement if hoveredElement.hasClass LINE_NUMBER_CLASS - $(hoveredElement).prev ".#{@LINE_NUMBER_CLASS}" + $(hoveredElement).prev ".#{LINE_NUMBER_CLASS}" isMovingToSameType: (e) -> - newButtonParent = @getButtonParent($(e.toElement)) + newButtonParent = @getButtonParent $(e.toElement) return false unless newButtonParent - (newButtonParent).is @getButtonParent($(e.currentTarget)) + newButtonParent.is @getButtonParent $(e.currentTarget) shouldRender: (e, buttonParentElement) -> - (!buttonParentElement.hasClass(@EMPTY_CELL_CLASS) and \ - !buttonParentElement.hasClass(@UNFOLDABLE_LINE_CLASS) and \ - $(@COMMENT_BUTTON_CLASS, buttonParentElement).length is 0) + (not buttonParentElement.hasClass(EMPTY_CELL_CLASS) and \ + not buttonParentElement.hasClass(UNFOLDABLE_LINE_CLASS) and \ + $(COMMENT_BUTTON_CLASS, buttonParentElement).length is 0) + +$.fn.filesCommentButton = -> + return unless this and @parent().data('can-create-note')? + + @each -> + unless $.data this, 'filesCommentButton' + $.data this, 'filesCommentButton', new FilesCommentButton $(this) diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee index cf54aa92520..87916823f81 100644 --- a/app/assets/javascripts/merge_request_tabs.js.coffee +++ b/app/assets/javascripts/merge_request_tabs.js.coffee @@ -163,7 +163,7 @@ class @MergeRequestTabs @diffsLoaded = true @scrollToElement("#diffs") @highlighSelectedLine() - @filesCommentButton = new FilesCommentButton($('.files')) + @filesCommentButton = $('.files .diff-file').filesCommentButton() $(document) .off 'click', '.diff-line-num a' diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index 0f75fb53eb7..d208fcee10b 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -15,7 +15,7 @@ - else %td.old_line.diff-line-num{id: left[:line_code], class: [left[:type], ('empty-cell' unless left[:number])], data: { linenumber: left[:number] }} %a{href: "##{left[:line_code]}" }= raw(left[:number]) - %td.line_content.parallel.noteable_line{class: [left[:type], ('empty-cell' if left[:text].empty?)], data: diff_view_line_data(left[:line_code], left[:position], left[:type])}= diff_line_content(left[:text]) + %td.line_content.parallel.noteable_line{class: [left[:type], ('empty-cell' if left[:text].empty?)], data: diff_view_line_data(left[:line_code], left[:position], 'old')}= diff_line_content(left[:text]) - if right[:type] == 'new' - new_line_type = 'new' @@ -28,7 +28,7 @@ %td.new_line.diff-line-num{id: new_line_code, class: [new_line_type, ('empty-cell' unless right[:number])], data: { linenumber: right[:number] }} %a{href: "##{new_line_code}" }= raw(right[:number]) - %td.line_content.parallel.noteable_line{class: [new_line_type, ('empty-cell' if right[:text].empty?)], data: diff_view_line_data(new_line_code, new_position, new_line_type)}= diff_line_content(right[:text]) + %td.line_content.parallel.noteable_line{class: [new_line_type, ('empty-cell' if right[:text].empty?)], data: diff_view_line_data(new_line_code, new_position, 'new')}= diff_line_content(right[:text]) - unless @diff_notes_disabled - notes_left, notes_right = organize_comments(left, right) From ce30827ccb4eb9febd09f1fdea01c2fda93fe8bb Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 7 Jul 2016 23:44:04 +0000 Subject: [PATCH 038/335] Do not set `@use_legacy_diff_notes` --- app/helpers/notes_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 16dd69ce5f6..98143dcee9b 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -45,7 +45,7 @@ module NotesHelper # tab, would show in different discussions on the discussion tab. use_legacy_diff_note ||= begin line_diff_notes = @grouped_diff_notes[line_code] - @use_legacy_diff_notes = line_diff_notes && line_diff_notes.any?(&:legacy_diff_note?) + line_diff_notes && line_diff_notes.any?(&:legacy_diff_note?) end data = { From d1d74814e35cbff4234fceb1f9333ba76cc91f30 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 7 Jul 2016 19:49:19 -0400 Subject: [PATCH 039/335] Fix creating diff notes in features --- spec/features/notes_on_merge_requests_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index 61eec0afbee..dd016a36d1e 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -231,7 +231,7 @@ describe 'Comments', feature: true do end def click_diff_line(data = line_code) - find(".line_holder[id='#{data}'] td:nth-of-type(1)").hover + find(".line_holder[id='#{data}'] td.line_content").hover find(".line_holder[id='#{data}'] button").trigger('click') end end From ec37d9553274e3bca58e4de44b932cdc72a37325 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Fri, 8 Jul 2016 01:33:33 +0100 Subject: [PATCH 040/335] Refactored .prev and .next methods --- app/assets/javascripts/files_comment_button.js.coffee | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/files_comment_button.js.coffee b/app/assets/javascripts/files_comment_button.js.coffee index 2b9dc6419d5..db0bf7082a9 100644 --- a/app/assets/javascripts/files_comment_button.js.coffee +++ b/app/assets/javascripts/files_comment_button.js.coffee @@ -7,6 +7,7 @@ class @FilesCommentButton UNFOLDABLE_LINE_CLASS = 'js-unfold' EMPTY_CELL_CLASS = 'empty-cell' OLD_LINE_CLASS = 'old_line' + NEW_CLASS = 'new' LINE_COLUMN_CLASSES = ".#{LINE_NUMBER_CLASS}, .line_content" TEXT_FILE_SELECTOR = '.text-file' DEBOUNCE_TIMEOUT_DURATION = 100 @@ -63,17 +64,20 @@ class @FilesCommentButton getLineContent: (hoveredElement) -> return hoveredElement if hoveredElement.hasClass LINE_CONTENT_CLASS - $(hoveredElement).next ".#{LINE_CONTENT_CLASS}" + $(".#{LINE_CONTENT_CLASS + @diffTypeClass hoveredElement}", hoveredElement.parent()) getButtonParent: (hoveredElement) -> if @VIEW_TYPE is 'inline' return hoveredElement if hoveredElement.hasClass OLD_LINE_CLASS - hoveredElement.parent().find ".#{OLD_LINE_CLASS}" + $(".#{OLD_LINE_CLASS}", hoveredElement.parent()) else return hoveredElement if hoveredElement.hasClass LINE_NUMBER_CLASS - $(hoveredElement).prev ".#{LINE_NUMBER_CLASS}" + $(".#{LINE_NUMBER_CLASS + @diffTypeClass hoveredElement}", hoveredElement.parent()) + + diffTypeClass: (hoveredElement) -> + if hoveredElement.hasClass(NEW_CLASS) then '.new' else '.old' isMovingToSameType: (e) -> newButtonParent = @getButtonParent $(e.toElement) From e26f8bf7ba26e0967044e0ae30f9a75d5e165cd1 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 24 Jun 2016 17:15:02 +0100 Subject: [PATCH 041/335] Dashboard projects blank state --- app/assets/stylesheets/framework/blank.scss | 11 ++- app/assets/stylesheets/framework/common.scss | 15 ---- .../_zero_authorized_projects.html.haml | 87 +++++++++---------- app/views/dashboard/projects/index.html.haml | 3 +- .../icons/{_group.svg => _group.svg.erb} | 9 +- app/views/shared/icons/_project.svg | 10 --- app/views/shared/icons/_project.svg.erb | 3 + 7 files changed, 56 insertions(+), 82 deletions(-) rename app/views/shared/icons/{_group.svg => _group.svg.erb} (83%) delete mode 100644 app/views/shared/icons/_project.svg create mode 100644 app/views/shared/icons/_project.svg.erb diff --git a/app/assets/stylesheets/framework/blank.scss b/app/assets/stylesheets/framework/blank.scss index d28cda6d62d..540718197e0 100644 --- a/app/assets/stylesheets/framework/blank.scss +++ b/app/assets/stylesheets/framework/blank.scss @@ -20,9 +20,12 @@ .blank-state-icon { padding-bottom: 20px; + color: $gray-darkest; + font-size: 56px; - path { - fill: $gray-darkest; + path, + polygon { + fill: currentColor; } } @@ -37,6 +40,10 @@ margin-top: 0; margin-bottom: $gl-padding; font-size: 15px; + + > strong { + font-weight: 600; + } } .blank-state-welcome-title { diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index f8aecd0558d..c1e5305644b 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -270,21 +270,6 @@ table { } } -.dashboard-intro-icon { - float: left; - text-align: center; - font-size: 32px; - color: #aaa; - width: 60px; -} - -.dashboard-intro-text { - display: inline-block; - margin-left: -60px; - padding-left: 60px; - width: 100%; -} - .btn-sign-in { text-shadow: none; diff --git a/app/views/dashboard/projects/_zero_authorized_projects.html.haml b/app/views/dashboard/projects/_zero_authorized_projects.html.haml index d54c7cad7be..40c70fa3025 100644 --- a/app/views/dashboard/projects/_zero_authorized_projects.html.haml +++ b/app/views/dashboard/projects/_zero_authorized_projects.html.haml @@ -1,53 +1,46 @@ - publicish_project_count = ProjectsFinder.new.execute(current_user).count -%h3.page-title Welcome to GitLab! -%p.light Self hosted Git management application. -%hr -%div - .dashboard-intro-icon - %i.fa.fa-bookmark-o - .dashboard-intro-text - %p.slead - You don't have access to any projects right now. - %br - - if current_user.can_create_project? - You can create up to - %strong= pluralize(number_with_delimiter(current_user.projects_limit), "project") + "." - - else - If you are added to a project, it will be displayed here. - +.blank-state.blank-state-welcome + %h2.blank-state-welcome-title + Welcome to GitLab + %p.blank-state-text + Code, test, and deploy together +.blank-state + .blank-state-icon + = navbar_icon("project", size: 50) + %h3.blank-state-title + You don't have access to any projects right now + %p.blank-state-text - if current_user.can_create_project? - .link_holder - = link_to new_project_path, class: "btn btn-new" do - = icon('plus') - New Project + You can create up to + %strong= number_with_delimiter(current_user.projects_limit) + = succeed "." do + = "project".pluralize(current_user.projects_limit) + - else + If you are added to a project, it will be displayed here. + - if current_user.can_create_project? + = link_to new_project_path, class: "btn btn-new" do + New project - if current_user.can_create_group? - %hr - %div - .dashboard-intro-icon - %i.fa.fa-users - .dashboard-intro-text - %p.slead - You can create a group for several dependent projects. - %br - Groups are the best way to manage projects and members. - .link_holder - = link_to new_group_path, class: "btn btn-new" do - %i.fa.fa-plus - New Group + .blank-state + .blank-state-icon + = navbar_icon("group", size: 50) + %h3.blank-state-title + You can create a group for several dependent projects. + %p.blank-state-text + Groups are the best way to manage projects and members. + = link_to new_group_path, class: "btn btn-new" do + New group -if publicish_project_count > 0 - %hr - %div - .dashboard-intro-icon - %i.fa.fa-globe - .dashboard-intro-text - %p.slead - There are - %strong= number_with_delimiter(publicish_project_count) - public projects on this server. - %br - Public projects are an easy way to allow everyone to have read-only access. - .link_holder - = link_to trending_explore_projects_path, class: "btn btn-new" do - Browse public projects + .blank-state + .blank-state-icon + = icon("globe") + %h3.blank-state-title + There are + = number_with_delimiter(publicish_project_count) + public projects on this server. + %p.blank-state-text + Public projects are an easy way to allow everyone to have read-only access. + = link_to trending_explore_projects_path, class: "btn btn-new" do + Browse projects diff --git a/app/views/dashboard/projects/index.html.haml b/app/views/dashboard/projects/index.html.haml index 4565e752c1f..4f36a4a1c73 100644 --- a/app/views/dashboard/projects/index.html.haml +++ b/app/views/dashboard/projects/index.html.haml @@ -5,7 +5,8 @@ - page_title "Projects" - header_title "Projects", dashboard_projects_path -= render 'dashboard/projects_head' +- if @projects.any? || params[:filter_projects] + = render 'dashboard/projects_head' - if @last_push = render "events/event_last_push", event: @last_push diff --git a/app/views/shared/icons/_group.svg b/app/views/shared/icons/_group.svg.erb similarity index 83% rename from app/views/shared/icons/_group.svg rename to app/views/shared/icons/_group.svg.erb index 75cae0d16c8..53635016900 100644 --- a/app/views/shared/icons/_group.svg +++ b/app/views/shared/icons/_group.svg.erb @@ -1,9 +1,4 @@ - - - - Group - Created with Sketch. - + @@ -15,4 +10,4 @@ - \ No newline at end of file + diff --git a/app/views/shared/icons/_project.svg b/app/views/shared/icons/_project.svg deleted file mode 100644 index 1e8b43f8c6b..00000000000 --- a/app/views/shared/icons/_project.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - Page 1 - Created with Sketch. - - - - - \ No newline at end of file diff --git a/app/views/shared/icons/_project.svg.erb b/app/views/shared/icons/_project.svg.erb new file mode 100644 index 00000000000..2f60bb7245e --- /dev/null +++ b/app/views/shared/icons/_project.svg.erb @@ -0,0 +1,3 @@ + + + From 1b111b83bf79a0f2e27c2a445a4757d399b36ca0 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 8 Jul 2016 09:47:09 +0100 Subject: [PATCH 042/335] changes the usage of simpleprojectdetails to already implemented basicprojectsdetails and changes the url to a more reader friendly format --- app/assets/javascripts/api.js.coffee | 2 +- lib/api/entities.rb | 8 +------- lib/api/projects.rb | 17 +++++------------ 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee index 45059ae4042..8028e66f089 100644 --- a/app/assets/javascripts/api.js.coffee +++ b/app/assets/javascripts/api.js.coffee @@ -3,7 +3,7 @@ groupPath: "/api/:version/groups/:id.json" namespacesPath: "/api/:version/namespaces.json" groupProjectsPath: "/api/:version/groups/:id/projects.json" - projectsPath: "/api/:version/projects/simple.json" + projectsPath: "/api/:version/projects.json?format=simple" labelsPath: "/api/:version/projects/:id/labels" licensePath: "/api/:version/licenses/:key" gitignorePath: "/api/:version/gitignores/:key" diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 0f26a1f00a2..aae1840821e 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -79,12 +79,6 @@ module API expose :public_builds end - class SimpleProject < Grape::Entity - expose :id - expose :name, :name_with_namespace - expose :http_url_to_repo - end - class ProjectMember < UserBasic expose :access_level do |user, options| options[:project].project_members.find_by(user_id: user.id).access_level @@ -334,7 +328,7 @@ module API end end - class SimpleProjectWithAccess < SimpleProject + class BasicProjectWithAccess < BasicProjectDetails expose :permissions do expose :project_access, using: Entities::ProjectAccess do |project, options| project.project_members.find_by(user_id: options[:user].id) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index c1e66b239aa..c46764c4897 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -25,18 +25,11 @@ module API @projects = current_user.authorized_projects @projects = filter_projects(@projects) @projects = paginate @projects - present @projects, with: Entities::ProjectWithAccess, user: current_user - end - - # Get a simplified project list for authenticated user - # - # Example Request: - # GET /projects/simple - get '/simple' do - @projects = current_user.authorized_projects - @projects = filter_projects(@projects) - @projects = paginate @projects - present @projects, with: Entities::SimpleProjectWithAccess, user: current_user + if params["format"] + present @projects, with: Entities::BasicProjectWithAccess, user: current_user + else + present @projects, with: Entities::ProjectWithAccess, user: current_user + end end # Get an owned projects list for authenticated user From b6b26692ea44cfeab7e8fd64b7df60852850fce2 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Tue, 28 Jun 2016 17:25:32 +0100 Subject: [PATCH 043/335] Collapse large diffs by default When rendering a list of diff files, skip those where the diff is over 10 KB and provide an endpoint to render individually instead. --- CHANGELOG | 2 + app/controllers/projects/commit_controller.rb | 20 +- .../projects/compare_controller.rb | 18 +- .../projects/merge_requests_controller.rb | 76 +++-- app/helpers/diff_helper.rb | 19 ++ app/models/merge_request.rb | 6 +- app/models/merge_request_diff.rb | 6 + app/views/projects/diffs/_content.html.haml | 25 ++ app/views/projects/diffs/_file.html.haml | 31 +- config/routes.rb | 15 +- lib/gitlab/diff/file.rb | 4 + spec/controllers/commit_controller_spec.rb | 246 --------------- .../projects/commit_controller_spec.rb | 293 +++++++++++++++++- .../projects/compare_controller_spec.rb | 69 +++++ .../merge_requests_controller_spec.rb | 280 ++++++++++++----- spec/models/merge_request_diff_spec.rb | 47 +++ spec/models/merge_request_spec.rb | 25 ++ 17 files changed, 785 insertions(+), 397 deletions(-) create mode 100644 app/views/projects/diffs/_content.html.haml delete mode 100644 spec/controllers/commit_controller_spec.rb create mode 100644 spec/models/merge_request_diff_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 09f2c44e02c..680078622cf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -32,6 +32,8 @@ v 8.10.0 (unreleased) - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - PipelinesFinder uses git cache data - Throttle the update of `project.pushes_since_gc` to 1 minute. + - Allow expanding and collapsing files in diff view (!4990) + - Collapse large diffs by default (!4990) - Check for conflicts with existing Project's wiki path when creating a new project. - Show last push widget in upstream after push to fork - Don't instantiate a git tree on Projects show default view diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb index 37d6521026c..810653b4264 100644 --- a/app/controllers/projects/commit_controller.rb +++ b/app/controllers/projects/commit_controller.rb @@ -19,7 +19,7 @@ class Projects::CommitController < Projects::ApplicationController @grouped_diff_notes = commit.notes.grouped_diff_notes @notes = commit.notes.non_diff_notes.fresh - + Banzai::NoteRenderer.render( @grouped_diff_notes.values.flatten + @notes, @project, @@ -41,6 +41,24 @@ class Projects::CommitController < Projects::ApplicationController end end + def diff_for_path + return git_not_found! unless commit + + opts = diff_options + opts[:ignore_whitespace_change] = true if params[:format] == 'diff' + + diffs = commit.diffs(opts.merge(paths: [params[:path]])) + diff_refs = [commit.parent || commit, commit] + + @comments_target = { + noteable_type: 'Commit', + commit_id: @commit.id + } + @grouped_diff_notes = {} + + render_diff_for_path(diffs, diff_refs, @project) + end + def builds end diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index d240b9fe989..8a04f63f4d4 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -6,7 +6,7 @@ class Projects::CompareController < Projects::ApplicationController # Authorize before_action :require_non_empty_project before_action :authorize_download_code! - before_action :assign_ref_vars, only: [:index, :show] + before_action :assign_ref_vars, only: [:index, :show, :diff_for_path] before_action :merge_request, only: [:index, :show] def index @@ -35,6 +35,22 @@ class Projects::CompareController < Projects::ApplicationController end end + def diff_for_path + compare = CompareService.new. + execute(@project, @head_ref, @project, @base_ref, diff_options) + + return render_404 unless compare + + @commit = @project.commit(@head_ref) + @base_commit = @project.merge_base_commit(@base_ref, @head_ref) + diffs = compare.diffs(diff_options.merge(paths: [params[:path]])) + + @diff_notes_disabled = true + @grouped_diff_notes = {} + + render_diff_for_path(diffs, [@base_commit, @commit], @project) + end + def create redirect_to namespace_project_compare_path(@project.namespace, @project, params[:from], params[:to]) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index df1943dd9bb..3fc5a319c9b 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -13,6 +13,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds] before_action :define_show_vars, only: [:show, :diffs, :commits, :builds] before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds, :merge_check] + before_action :define_commit_vars, only: [:diffs] + before_action :define_diff_comment_vars, only: [:diffs] before_action :ensure_ref_fetched, only: [:show, :diffs, :commits, :builds] # Allow read any merge_request @@ -58,7 +60,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController respond_to do |format| format.html - + format.json do render json: @merge_request end @@ -80,32 +82,32 @@ class Projects::MergeRequestsController < Projects::ApplicationController def diffs apply_diff_view_cookie! - @commit = @merge_request.diff_head_commit - @base_commit = @merge_request.diff_base_commit || @merge_request.likely_diff_base_commit - - @comments_target = { - noteable_type: 'MergeRequest', - noteable_id: @merge_request.id - } - - @use_legacy_diff_notes = !@merge_request.support_new_diff_notes? - @grouped_diff_notes = @merge_request.notes.grouped_diff_notes - - Banzai::NoteRenderer.render( - @grouped_diff_notes.values.flatten, - @project, - current_user, - @path, - @project_wiki, - @ref - ) - respond_to do |format| format.html format.json { render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") } } end end + # With an ID param, loads the MR at that ID. Otherwise, accepts the same params as #new + # and uses that (unsaved) MR. + # + def diff_for_path + if params[:id] + merge_request + define_diff_comment_vars + else + build_merge_request + @diff_notes_disabled = true + @grouped_diff_notes = {} + end + + define_commit_vars + diffs = @merge_request.diffs(diff_options.merge(paths: [params[:path]])) + diff_refs = @merge_request.diff_refs + + render_diff_for_path(diffs, diff_refs, @merge_request.project) + end + def commits respond_to do |format| format.html { render 'show' } @@ -121,8 +123,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController end def new - params[:merge_request] ||= ActionController::Parameters.new(source_project: @project) - @merge_request = MergeRequests::BuildService.new(project, current_user, merge_request_params).execute + build_merge_request @noteable = @merge_request @target_branches = if @merge_request.target_project @@ -380,6 +381,30 @@ class Projects::MergeRequestsController < Projects::ApplicationController closes_issues end + def define_commit_vars + @commit = @merge_request.diff_head_commit + @base_commit = @merge_request.diff_base_commit || @merge_request.likely_diff_base_commit + end + + def define_diff_comment_vars + @comments_target = { + noteable_type: 'MergeRequest', + noteable_id: @merge_request.id + } + + @use_legacy_diff_notes = !@merge_request.support_new_diff_notes? + @grouped_diff_notes = @merge_request.notes.grouped_diff_notes + + Banzai::NoteRenderer.render( + @grouped_diff_notes.values.flatten, + @project, + current_user, + @path, + @project_wiki, + @ref + ) + end + def invalid_mr # Render special view for MR with removed source or target branch render 'invalid' @@ -408,4 +433,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController params[:merge_when_build_succeeds].present? && @merge_request.pipeline && @merge_request.pipeline.active? end + + def build_merge_request + params[:merge_request] ||= ActionController::Parameters.new(source_project: @project) + @merge_request = MergeRequests::BuildService.new(project, current_user, merge_request_params).execute + end end diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index eb57516247d..d4655d60799 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -8,6 +8,25 @@ module DiffHelper [marked_old_line, marked_new_line] end + def render_diff_for_path(diffs, diff_refs, project) + diff_file = safe_diff_files(diffs, diff_refs).first + + return render_404 unless diff_file + + diff_commit = commit_for_diff(diff_file) + blob = project.repository.blob_for_diff(diff_commit, diff_file) + + locals = { + diff_file: diff_file, + diff_commit: diff_commit, + diff_refs: diff_refs, + blob: blob, + project: project + } + + render json: { html: view_to_html_string('projects/diffs/_content', locals) } + end + def diff_view diff_views = %w(inline parallel) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 083e93f1ee7..d5c23716b04 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -19,7 +19,7 @@ class MergeRequest < ActiveRecord::Base after_create :create_merge_request_diff, unless: :importing? after_update :update_merge_request_diff - delegate :commits, :diffs, :real_size, to: :merge_request_diff, prefix: nil + delegate :commits, :real_size, to: :merge_request_diff, prefix: nil # When this attribute is true some MR validation is ignored # It allows us to close or modify broken merge requests @@ -164,6 +164,10 @@ class MergeRequest < ActiveRecord::Base merge_request_diff ? merge_request_diff.first_commit : compare_commits.first end + def diffs(*args) + merge_request_diff ? merge_request_diff.diffs(*args) : compare.diffs(*args) + end + def diff_size merge_request_diff.size end diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index ba235750aeb..06b28fc5a75 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -144,6 +144,12 @@ class MergeRequestDiff < ActiveRecord::Base def load_diffs(raw, options) if raw.respond_to?(:each) + if options[:paths] + raw = raw.select do |diff| + options[:paths].include?(diff[:new_path]) + end + end + Gitlab::Git::DiffCollection.new(raw, options) else Gitlab::Git::DiffCollection.new([]) diff --git a/app/views/projects/diffs/_content.html.haml b/app/views/projects/diffs/_content.html.haml new file mode 100644 index 00000000000..832aa0c5a14 --- /dev/null +++ b/app/views/projects/diffs/_content.html.haml @@ -0,0 +1,25 @@ +.diff-content.diff-wrap-lines + - # Skip all non non-supported blobs + - return unless blob.respond_to?(:text?) + - if diff_file.too_large? + .nothing-here-block This diff could not be displayed because it is too large. + - elsif blob.only_display_raw? + .nothing-here-block This file is too large to display. + - elsif blob_text_viewable?(blob) + - if !project.repository.diffable?(blob) + .nothing-here-block This diff was suppressed by a .gitattributes entry. + - elsif diff_file.diff_lines.length > 0 + - if diff_view == 'parallel' + = render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob + - else + = render "projects/diffs/text_file", diff_file: diff_file + - else + - if diff_file.mode_changed? + .nothing-here-block File mode changed + - elsif diff_file.renamed_file + .nothing-here-block File moved + - elsif blob.image? + - old_blob = diff_file.old_blob(diff_commit) + = render "projects/diffs/image", diff_file: diff_file, old_file: old_blob, file: blob + - else + .nothing-here-block No preview for this file type diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml index 3b758a1ec4e..c83ed55efe1 100644 --- a/app/views/projects/diffs/_file.html.haml +++ b/app/views/projects/diffs/_file.html.haml @@ -16,28 +16,9 @@ = view_file_btn(diff_commit.id, diff_file, project) - .diff-content.diff-wrap-lines - - # Skip all non non-supported blobs - - return unless blob.respond_to?(:text?) - - if diff_file.too_large? - .nothing-here-block This diff could not be displayed because it is too large. - - elsif blob.only_display_raw? - .nothing-here-block This file is too large to display. - - elsif blob_text_viewable?(blob) - - if !project.repository.diffable?(blob) - .nothing-here-block This diff was suppressed by a .gitattributes entry. - - elsif diff_file.diff_lines.length > 0 - - if diff_view == 'parallel' - = render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob, index: i - - else - = render "projects/diffs/text_file", diff_file: diff_file, index: i - - else - - if diff_file.mode_changed? - .nothing-here-block File mode changed - - elsif diff_file.renamed_file - .nothing-here-block File moved - - elsif blob.image? - - old_blob = diff_file.old_blob(diff_commit) - = render "projects/diffs/image", diff_file: diff_file, old_file: old_blob, file: blob, index: i - - else - .nothing-here-block No preview for this file type + - if diff_file.collapsed_by_default? + - url = url_for(params.merge(action: :diff_for_path, path: diff_file.file_path, format: nil)) + .diff-content.diff-wrap-lines{data: { diff_for_path: url }} + .nothing-here-block File hidden by default; content for this element available at #{url} + - else + = render 'projects/diffs/content', diff_file: diff_file, diff_commit: diff_commit, diff_refs: diff_refs, blob: blob, project: project diff --git a/config/routes.rb b/config/routes.rb index 18a4ead2b37..f31f8171993 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -615,10 +615,18 @@ Rails.application.routes.draw do post :retry_builds post :revert post :cherry_pick + get '/diffs/*path', action: :diff_for_path, constraints: { format: false } end end - resources :compare, only: [:index, :create] + resources :compare, only: [:index, :create] do + collection do + get '/diffs/*path', action: :diff_for_path, constraints: { format: false } + end + end + + get '/compare/:from...:to', to: 'compare#show', as: 'compare', constraints: { from: /.+/, to: /.+/ } + resources :network, only: [:show], constraints: { id: /(?:[^.]|\.(?!json$))+/, format: /json/ } resources :graphs, only: [:show], constraints: { id: /(?:[^.]|\.(?!json$))+/, format: /json/ } do @@ -629,9 +637,6 @@ Rails.application.routes.draw do end end - get '/compare/:from...:to' => 'compare#show', :as => 'compare', - :constraints => { from: /.+/, to: /.+/ } - resources :snippets, constraints: { id: /\d+/ } do member do get 'raw' @@ -706,12 +711,14 @@ Rails.application.routes.draw do post :toggle_subscription post :toggle_award_emoji post :remove_wip + get '/diffs/*path', action: :diff_for_path, constraints: { format: false } end collection do get :branch_from get :branch_to get :update_branches + get '/diffs/*path', action: :diff_for_path, constraints: { format: false } end end diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index b0c50edba59..7e01f7b61fb 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -68,6 +68,10 @@ module Gitlab @lines ||= Gitlab::Diff::Parser.new.parse(raw_diff.each_line).to_a end + def collapsed_by_default? + diff.diff.bytesize > 10240 # 10 KB + end + def highlighted_diff_lines @highlighted_diff_lines ||= Gitlab::Diff::Highlight.new(self, repository: self.repository).highlight end diff --git a/spec/controllers/commit_controller_spec.rb b/spec/controllers/commit_controller_spec.rb deleted file mode 100644 index a3a3309e15e..00000000000 --- a/spec/controllers/commit_controller_spec.rb +++ /dev/null @@ -1,246 +0,0 @@ -require 'spec_helper' - -describe Projects::CommitController do - let(:project) { create(:project) } - let(:user) { create(:user) } - let(:commit) { project.commit("master") } - let(:master_pickable_sha) { '7d3b0f7cff5f37573aea97cebfd5692ea1689924' } - let(:master_pickable_commit) { project.commit(master_pickable_sha) } - - before do - sign_in(user) - project.team << [user, :master] - end - - describe "#show" do - shared_examples "export as" do |format| - it "should generally work" do - get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: commit.id, - format: format) - - expect(response).to be_success - end - - it "should generate it" do - expect_any_instance_of(Commit).to receive(:"to_#{format}") - - get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: commit.id, format: format) - end - - it "should render it" do - get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: commit.id, format: format) - - expect(response.body).to eq(commit.send(:"to_#{format}")) - end - - it "should not escape Html" do - allow_any_instance_of(Commit).to receive(:"to_#{format}"). - and_return('HTML entities &<>" ') - - get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: commit.id, format: format) - - expect(response.body).not_to include('&') - expect(response.body).not_to include('>') - expect(response.body).not_to include('<') - expect(response.body).not_to include('"') - end - end - - describe "as diff" do - include_examples "export as", :diff - let(:format) { :diff } - - it "should really only be a git diff" do - get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: commit.id, - format: format) - - expect(response.body).to start_with("diff --git") - end - - it "should really only be a git diff without whitespace changes" do - get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: '66eceea0db202bb39c4e445e8ca28689645366c5', - # id: commit.id, - format: format, - w: 1) - - expect(response.body).to start_with("diff --git") - # without whitespace option, there are more than 2 diff_splits - diff_splits = assigns(:diffs).first.diff.split("\n") - expect(diff_splits.length).to be <= 2 - end - end - - describe "as patch" do - include_examples "export as", :patch - let(:format) { :patch } - - it "should really be a git email patch" do - get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: commit.id, - format: format) - - expect(response.body).to start_with("From #{commit.id}") - end - - it "should contain a git diff" do - get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: commit.id, - format: format) - - expect(response.body).to match(/^diff --git/) - end - end - - context 'commit that removes a submodule' do - render_views - - let(:fork_project) { create(:forked_project_with_submodules) } - let(:commit) { fork_project.commit('remove-submodule') } - - before do - fork_project.team << [user, :master] - end - - it 'renders it' do - get(:show, - namespace_id: fork_project.namespace.to_param, - project_id: fork_project.to_param, - id: commit.id) - - expect(response).to be_success - end - end - end - - describe "#branches" do - it "contains branch and tags information" do - get(:branches, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: commit.id) - - expect(assigns(:branches)).to include("master", "feature_conflict") - expect(assigns(:tags)).to include("v1.1.0") - end - end - - describe '#revert' do - context 'when target branch is not provided' do - it 'should render the 404 page' do - post(:revert, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: commit.id) - - expect(response).not_to be_success - expect(response).to have_http_status(404) - end - end - - context 'when the revert was successful' do - it 'should redirect to the commits page' do - post(:revert, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - target_branch: 'master', - id: commit.id) - - expect(response).to redirect_to namespace_project_commits_path(project.namespace, project, 'master') - expect(flash[:notice]).to eq('The commit has been successfully reverted.') - end - end - - context 'when the revert failed' do - before do - post(:revert, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - target_branch: 'master', - id: commit.id) - end - - it 'should redirect to the commit page' do - # Reverting a commit that has been already reverted. - post(:revert, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - target_branch: 'master', - id: commit.id) - - expect(response).to redirect_to namespace_project_commit_path(project.namespace, project, commit.id) - expect(flash[:alert]).to match('Sorry, we cannot revert this commit automatically.') - end - end - end - - describe '#cherry_pick' do - context 'when target branch is not provided' do - it 'should render the 404 page' do - post(:cherry_pick, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: master_pickable_commit.id) - - expect(response).not_to be_success - expect(response).to have_http_status(404) - end - end - - context 'when the cherry-pick was successful' do - it 'should redirect to the commits page' do - post(:cherry_pick, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - target_branch: 'master', - id: master_pickable_commit.id) - - expect(response).to redirect_to namespace_project_commits_path(project.namespace, project, 'master') - expect(flash[:notice]).to eq('The commit has been successfully cherry-picked.') - end - end - - context 'when the cherry_pick failed' do - before do - post(:cherry_pick, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - target_branch: 'master', - id: master_pickable_commit.id) - end - - it 'should redirect to the commit page' do - # Cherry-picking a commit that has been already cherry-picked. - post(:cherry_pick, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - target_branch: 'master', - id: master_pickable_commit.id) - - expect(response).to redirect_to namespace_project_commit_path(project.namespace, project, master_pickable_commit.id) - expect(flash[:alert]).to match('Sorry, we cannot cherry-pick this commit automatically.') - end - end - end -end diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb index 6e3db10e451..9679b4f849f 100644 --- a/spec/controllers/projects/commit_controller_spec.rb +++ b/spec/controllers/projects/commit_controller_spec.rb @@ -1,9 +1,29 @@ -require 'rails_helper' +require 'spec_helper' describe Projects::CommitController do - describe 'GET show' do + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:commit) { project.commit("master") } + let(:master_pickable_sha) { '7d3b0f7cff5f37573aea97cebfd5692ea1689924' } + let(:master_pickable_commit) { project.commit(master_pickable_sha) } + + before do + sign_in(user) + project.team << [user, :master] + end + + describe 'GET #show' do render_views + def go(extra_params = {}) + params = { + namespace_id: project.namespace.to_param, + project_id: project.to_param + } + + get :show, params.merge(extra_params) + end + let(:project) { create(:project) } before do @@ -15,7 +35,7 @@ describe Projects::CommitController do context 'with valid id' do it 'responds with 200' do - go id: project.commit.id + go(id: commit.id) expect(response).to be_ok end @@ -23,27 +43,274 @@ describe Projects::CommitController do context 'with invalid id' do it 'responds with 404' do - go id: project.commit.id.reverse + go(id: commit.id.reverse) expect(response).to be_not_found end end it 'handles binary files' do - get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: TestEnv::BRANCH_SHA['binary-encoding'], - format: "html") + go(id: TestEnv::BRANCH_SHA['binary-encoding'], format: 'html') expect(response).to be_success end - def go(id:) - get :show, + shared_examples "export as" do |format| + it "should generally work" do + go(id: commit.id, format: format) + + expect(response).to be_success + end + + it "should generate it" do + expect_any_instance_of(Commit).to receive(:"to_#{format}") + + go(id: commit.id, format: format) + end + + it "should render it" do + go(id: commit.id, format: format) + + expect(response.body).to eq(commit.send(:"to_#{format}")) + end + + it "should not escape Html" do + allow_any_instance_of(Commit).to receive(:"to_#{format}"). + and_return('HTML entities &<>" ') + + go(id: commit.id, format: format) + + expect(response.body).not_to include('&') + expect(response.body).not_to include('>') + expect(response.body).not_to include('<') + expect(response.body).not_to include('"') + end + end + + describe "as diff" do + include_examples "export as", :diff + let(:format) { :diff } + + it "should really only be a git diff" do + go(id: commit.id, format: format) + + expect(response.body).to start_with("diff --git") + end + + it "should really only be a git diff without whitespace changes" do + go(id: '66eceea0db202bb39c4e445e8ca28689645366c5', format: format, w: 1) + + expect(response.body).to start_with("diff --git") + # without whitespace option, there are more than 2 diff_splits + diff_splits = assigns(:diffs).first.diff.split("\n") + expect(diff_splits.length).to be <= 2 + end + end + + describe "as patch" do + include_examples "export as", :patch + let(:format) { :patch } + + it "should really be a git email patch" do + go(id: commit.id, format: format) + + expect(response.body).to start_with("From #{commit.id}") + end + + it "should contain a git diff" do + go(id: commit.id, format: format) + + expect(response.body).to match(/^diff --git/) + end + end + + context 'commit that removes a submodule' do + render_views + + let(:fork_project) { create(:forked_project_with_submodules, visibility_level: 20) } + let(:commit) { fork_project.commit('remove-submodule') } + + it 'renders it' do + get(:show, + namespace_id: fork_project.namespace.to_param, + project_id: fork_project.to_param, + id: commit.id) + + expect(response).to be_success + end + end + end + + describe "#branches" do + it "contains branch and tags information" do + get(:branches, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + id: commit.id) + + expect(assigns(:branches)).to include("master", "feature_conflict") + expect(assigns(:tags)).to include("v1.1.0") + end + end + + describe '#revert' do + context 'when target branch is not provided' do + it 'should render the 404 page' do + post(:revert, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + id: commit.id) + + expect(response).not_to be_success + expect(response).to have_http_status(404) + end + end + + context 'when the revert was successful' do + it 'should redirect to the commits page' do + post(:revert, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + target_branch: 'master', + id: commit.id) + + expect(response).to redirect_to namespace_project_commits_path(project.namespace, project, 'master') + expect(flash[:notice]).to eq('The commit has been successfully reverted.') + end + end + + context 'when the revert failed' do + before do + post(:revert, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + target_branch: 'master', + id: commit.id) + end + + it 'should redirect to the commit page' do + # Reverting a commit that has been already reverted. + post(:revert, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + target_branch: 'master', + id: commit.id) + + expect(response).to redirect_to namespace_project_commit_path(project.namespace, project, commit.id) + expect(flash[:alert]).to match('Sorry, we cannot revert this commit automatically.') + end + end + end + + describe '#cherry_pick' do + context 'when target branch is not provided' do + it 'should render the 404 page' do + post(:cherry_pick, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + id: master_pickable_commit.id) + + expect(response).not_to be_success + expect(response).to have_http_status(404) + end + end + + context 'when the cherry-pick was successful' do + it 'should redirect to the commits page' do + post(:cherry_pick, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + target_branch: 'master', + id: master_pickable_commit.id) + + expect(response).to redirect_to namespace_project_commits_path(project.namespace, project, 'master') + expect(flash[:notice]).to eq('The commit has been successfully cherry-picked.') + end + end + + context 'when the cherry_pick failed' do + before do + post(:cherry_pick, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + target_branch: 'master', + id: master_pickable_commit.id) + end + + it 'should redirect to the commit page' do + # Cherry-picking a commit that has been already cherry-picked. + post(:cherry_pick, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + target_branch: 'master', + id: master_pickable_commit.id) + + expect(response).to redirect_to namespace_project_commit_path(project.namespace, project, master_pickable_commit.id) + expect(flash[:alert]).to match('Sorry, we cannot cherry-pick this commit automatically.') + end + end + end + + describe 'GET #diff_for_path' do + def diff_for_path(extra_params = {}) + params = { namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: id + project_id: project.to_param + } + + get :diff_for_path, params.merge(extra_params) + end + + let(:existing_path) { '.gitmodules' } + + context 'when the commit exists' do + context 'when the user has access to the project' do + context 'when the path exists in the diff' do + it 'enables diff notes' do + diff_for_path(id: commit.id, path: existing_path) + + expect(assigns(:diff_notes_disabled)).to be_falsey + expect(assigns(:comments_target)).to eq(noteable_type: 'Commit', + commit_id: commit.id) + end + + it 'only renders the diffs for the path given' do + expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs, diff_refs, project| + expect(diffs.map(&:new_path)).to contain_exactly(existing_path) + meth.call(diffs, diff_refs, project) + end + + diff_for_path(id: commit.id, path: existing_path) + end + end + + context 'when the path does not exist in the diff' do + before { diff_for_path(id: commit.id, path: existing_path.succ) } + + it 'returns a 404' do + expect(response).to have_http_status(404) + end + end + end + + context 'when the user does not have access to the project' do + before do + project.team.truncate + diff_for_path(id: commit.id, path: existing_path) + end + + it 'returns a 404' do + expect(response).to have_http_status(404) + end + end + end + + context 'when the commit does not exist' do + before { diff_for_path(id: commit.id.succ, path: existing_path) } + + it 'returns a 404' do + expect(response).to have_http_status(404) + end end end end diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb index 4018dac95a2..40a068a87bb 100644 --- a/spec/controllers/projects/compare_controller_spec.rb +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -64,4 +64,73 @@ describe Projects::CompareController do expect(assigns(:commits)).to eq(nil) end end + + describe 'GET #diff_for_path' do + def diff_for_path(extra_params = {}) + params = { + namespace_id: project.namespace.to_param, + project_id: project.to_param + } + + get :diff_for_path, params.merge(extra_params) + end + + let(:existing_path) { 'files/ruby/feature.rb' } + + context 'when the from and to refs exist' do + context 'when the user has access to the project' do + context 'when the path exists in the diff' do + it 'disables diff notes' do + diff_for_path(from: ref_from, to: ref_to, path: existing_path) + + expect(assigns(:diff_notes_disabled)).to be_truthy + end + + it 'only renders the diffs for the path given' do + expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs, diff_refs, project| + expect(diffs.map(&:new_path)).to contain_exactly(existing_path) + meth.call(diffs, diff_refs, project) + end + + diff_for_path(from: ref_from, to: ref_to, path: existing_path) + end + end + + context 'when the path does not exist in the diff' do + before { diff_for_path(from: ref_from, to: ref_to, path: existing_path.succ) } + + it 'returns a 404' do + expect(response).to have_http_status(404) + end + end + end + + context 'when the user does not have access to the project' do + before do + project.team.truncate + diff_for_path(from: ref_from, to: ref_to, path: existing_path) + end + + it 'returns a 404' do + expect(response).to have_http_status(404) + end + end + end + + context 'when the from ref does not exist' do + before { diff_for_path(from: ref_from.succ, to: ref_to, path: existing_path) } + + it 'returns a 404' do + expect(response).to have_http_status(404) + end + end + + context 'when the to ref does not exist' do + before { diff_for_path(from: ref_from, to: ref_to.succ, path: existing_path) } + + it 'returns a 404' do + expect(response).to have_http_status(404) + end + end + end end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index c4b57e77804..1b4c4dcd1e5 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -289,101 +289,215 @@ describe Projects::MergeRequestsController do end end - describe 'GET diffs' do - def go(format: 'html') - get :diffs, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: merge_request.iid, - format: format - end - - context 'as html' do - it 'renders the diff template' do - go - - expect(response).to render_template('diffs') - end - end - - context 'as json' do - it 'renders the diffs template to a string' do - go format: 'json' - - expect(response).to render_template('projects/merge_requests/show/_diffs') - expect(JSON.parse(response.body)).to have_key('html') - end - end - - context 'with forked projects with submodules' do - render_views - - let(:project) { create(:project) } - let(:fork_project) { create(:forked_project_with_submodules) } - let(:merge_request) { create(:merge_request_with_diffs, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) } - - before do - fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id) - fork_project.save - merge_request.reload - end - - it 'renders' do - go format: 'json' - - expect(response).to be_success - expect(response.body).to have_content('Subproject commit') - end - end - end - - describe 'GET diffs with ignore_whitespace_change' do - def go(format: 'html') - get :diffs, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: merge_request.iid, - format: format, - w: 1 - end - - context 'as html' do - it 'renders the diff template' do - go - - expect(response).to render_template('diffs') - end - end - - context 'as json' do - it 'renders the diffs template to a string' do - go format: 'json' - - expect(response).to render_template('projects/merge_requests/show/_diffs') - expect(JSON.parse(response.body)).to have_key('html') - end - end - end - - describe 'GET diffs with view' do + describe 'GET #diffs' do def go(extra_params = {}) params = { namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: merge_request.iid + project_id: project.to_param, + id: merge_request.iid } get :diffs, params.merge(extra_params) end - it 'saves the preferred diff view in a cookie' do - go view: 'parallel' + context 'with default params' do + context 'as html' do + before { go(format: 'html') } - expect(response.cookies['diff_view']).to eq('parallel') + it 'renders the diff template' do + expect(response).to render_template('diffs') + end + end + + context 'as json' do + before { go(format: 'json') } + + it 'renders the diffs template to a string' do + expect(response).to render_template('projects/merge_requests/show/_diffs') + expect(JSON.parse(response.body)).to have_key('html') + end + end + + context 'with forked projects with submodules' do + render_views + + let(:project) { create(:project) } + let(:fork_project) { create(:forked_project_with_submodules) } + let(:merge_request) { create(:merge_request_with_diffs, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) } + + before do + fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id) + fork_project.save + merge_request.reload + go(format: 'json') + end + + it 'renders' do + expect(response).to be_success + expect(response.body).to have_content('Subproject commit') + end + end + end + + context 'with ignore_whitespace_change' do + context 'as html' do + before { go(format: 'html', w: 1) } + + it 'renders the diff template' do + expect(response).to render_template('diffs') + end + end + + context 'as json' do + before { go(format: 'json', w: 1) } + + it 'renders the diffs template to a string' do + expect(response).to render_template('projects/merge_requests/show/_diffs') + expect(JSON.parse(response.body)).to have_key('html') + end + end + end + + context 'with view' do + before { go(view: 'parallel') } + + it 'saves the preferred diff view in a cookie' do + expect(response.cookies['diff_view']).to eq('parallel') + end end end - describe 'GET commits' do + describe 'GET #diff_for_path' do + def diff_for_path(extra_params = {}) + params = { + namespace_id: project.namespace.to_param, + project_id: project.to_param + } + + get :diff_for_path, params.merge(extra_params) + end + + context 'when an ID param is passed' do + let(:existing_path) { 'files/ruby/popen.rb' } + + context 'when the merge request exists' do + context 'when the user can view the merge request' do + context 'when the path exists in the diff' do + it 'enables diff notes' do + diff_for_path(id: merge_request.iid, path: existing_path) + + expect(assigns(:diff_notes_disabled)).to be_falsey + expect(assigns(:comments_target)).to eq(noteable_type: 'MergeRequest', + noteable_id: merge_request.id) + end + + it 'only renders the diffs for the path given' do + expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs, diff_refs, project| + expect(diffs.map(&:new_path)).to contain_exactly(existing_path) + meth.call(diffs, diff_refs, project) + end + + diff_for_path(id: merge_request.iid, path: existing_path) + end + end + + context 'when the path does not exist in the diff' do + before { diff_for_path(id: merge_request.iid, path: 'files/ruby/nopen.rb') } + + it 'returns a 404' do + expect(response).to have_http_status(404) + end + end + end + + context 'when the user cannot view the merge request' do + before do + project.team.truncate + diff_for_path(id: merge_request.iid, path: existing_path) + end + + it 'returns a 404' do + expect(response).to have_http_status(404) + end + end + end + + context 'when the merge request does not exist' do + before { diff_for_path(id: merge_request.iid.succ, path: existing_path) } + + it 'returns a 404' do + expect(response).to have_http_status(404) + end + end + + context 'when the merge request belongs to a different project' do + let(:other_project) { create(:empty_project) } + + before do + other_project.team << [user, :master] + diff_for_path(id: merge_request.iid, path: existing_path, project_id: other_project.to_param) + end + + it 'returns a 404' do + expect(response).to have_http_status(404) + end + end + end + + context 'when source and target params are passed' do + let(:existing_path) { 'files/ruby/feature.rb' } + + context 'when both branches are in the same project' do + it 'disables diff notes' do + diff_for_path(path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' }) + + expect(assigns(:diff_notes_disabled)).to be_truthy + end + + it 'only renders the diffs for the path given' do + expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs, diff_refs, project| + expect(diffs.map(&:new_path)).to contain_exactly(existing_path) + meth.call(diffs, diff_refs, project) + end + + diff_for_path(path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' }) + end + end + + context 'when the source branch is in a different project to the target' do + let(:other_project) { create(:project) } + + before { other_project.team << [user, :master] } + + context 'when the path exists in the diff' do + it 'disables diff notes' do + diff_for_path(path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' }) + + expect(assigns(:diff_notes_disabled)).to be_truthy + end + + it 'only renders the diffs for the path given' do + expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs, diff_refs, project| + expect(diffs.map(&:new_path)).to contain_exactly(existing_path) + meth.call(diffs, diff_refs, project) + end + + diff_for_path(path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' }) + end + end + + context 'when the path does not exist in the diff' do + before { diff_for_path(path: 'files/ruby/nopen.rb', merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' }) } + + it 'returns a 404' do + expect(response).to have_http_status(404) + end + end + end + end + end + + describe 'GET #commits' do def go(format: 'html') get :commits, namespace_id: project.namespace.to_param, diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb new file mode 100644 index 00000000000..3f5763b6408 --- /dev/null +++ b/spec/models/merge_request_diff_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe MergeRequestDiff, models: true do + describe '#diffs' do + let(:mr) { create(:merge_request, :with_diffs) } + let(:mr_diff) { mr.merge_request_diff } + + context 'when the :ignore_whitespace_change option is set' do + it 'creates a new compare object instead of loading from the DB' do + expect(mr_diff).not_to receive(:load_diffs) + expect(Gitlab::Git::Compare).to receive(:new).and_call_original + + mr_diff.diffs(ignore_whitespace_change: true) + end + end + + context 'when the raw diffs are empty' do + before { mr_diff.update_attributes(st_diffs: '') } + + it 'returns an empty DiffCollection' do + expect(mr_diff.diffs).to be_a(Gitlab::Git::DiffCollection) + expect(mr_diff.diffs).to be_empty + end + end + + context 'when the raw diffs exist' do + it 'returns the diffs' do + expect(mr_diff.diffs).to be_a(Gitlab::Git::DiffCollection) + expect(mr_diff.diffs).not_to be_empty + end + + context 'when the :paths option is set' do + let(:diffs) { mr_diff.diffs(paths: ['.gitignore', 'files/ruby/popen.rb', 'files/ruby/string.rb']) } + + it 'only returns diffs that match the paths given' do + expect(diffs.map(&:new_path)).to contain_exactly('.gitignore', 'files/ruby/popen.rb') + end + + it 'uses the diffs from the DB' do + expect(mr_diff).to receive(:load_diffs) + + diffs + end + end + end + end +end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index a4b6ff8f8ad..c8ad7ab3e7f 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -116,6 +116,31 @@ describe MergeRequest, models: true do end end + describe '#diffs' do + let(:merge_request) { build(:merge_request) } + let(:options) { { paths: ['a/b', 'b/a', 'c/*'] } } + + context 'when there are MR diffs' do + it 'delegates to the MR diffs' do + merge_request.merge_request_diff = MergeRequestDiff.new + + expect(merge_request.merge_request_diff).to receive(:diffs).with(options) + + merge_request.diffs(options) + end + end + + context 'when there are no MR diffs' do + it 'delegates to the compare object' do + merge_request.compare = double(:compare) + + expect(merge_request.compare).to receive(:diffs).with(options) + + merge_request.diffs(options) + end + end + end + describe "#mr_and_commit_notes" do let!(:merge_request) { create(:merge_request) } From 78496e8c38ce0b415fa7aad5310b937a95265627 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 30 Jun 2016 16:17:10 +0100 Subject: [PATCH 044/335] Disable overflow messages With the option to expand and collapse individual diffs, these aren't needed any more. --- app/helpers/diff_helper.rb | 10 +--------- app/views/projects/diffs/_text_file.html.haml | 7 +------ app/views/projects/diffs/_warning.html.haml | 3 --- features/project/commits/commits.feature | 5 ----- features/steps/project/commits/commits.rb | 19 ------------------- spec/helpers/diff_helper_spec.rb | 17 +---------------- 6 files changed, 3 insertions(+), 58 deletions(-) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index d4655d60799..9a5920edfa2 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -37,16 +37,8 @@ module DiffHelper end end - def diff_hard_limit_enabled? - params[:force_show_diff].present? - end - def diff_options - options = { ignore_whitespace_change: hide_whitespace? } - if diff_hard_limit_enabled? - options.merge!(Commit.max_diff_options) - end - options + Commit.max_diff_options.merge(ignore_whitespace_change: hide_whitespace?) end def safe_diff_files(diffs, diff_refs: nil, repository: nil) diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index 192093d1273..d61292c4bcb 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -1,9 +1,4 @@ -- too_big = diff_file.diff_lines.count > Commit::DIFF_SAFE_LINES -- if too_big - .suppressed-container - %a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show. - -%table.text-file.code.js-syntax-highlight{ class: too_big ? 'hide' : '' } +%table.text-file.code.js-syntax-highlight - last_line = 0 - diff_file.highlighted_diff_lines.each do |line| - last_line = line.new_pos diff --git a/app/views/projects/diffs/_warning.html.haml b/app/views/projects/diffs/_warning.html.haml index 15536c17f8e..10fa1ddf2e5 100644 --- a/app/views/projects/diffs/_warning.html.haml +++ b/app/views/projects/diffs/_warning.html.haml @@ -2,9 +2,6 @@ %h4 Too many changes to show. .pull-right - - unless diff_hard_limit_enabled? - = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: nil)), class: "btn btn-sm" - - if current_controller?(:commit) or current_controller?(:merge_requests) - if current_controller?(:commit) = link_to "Plain diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff), class: "btn btn-sm" diff --git a/features/project/commits/commits.feature b/features/project/commits/commits.feature index a95df038357..8b0cb90765e 100644 --- a/features/project/commits/commits.feature +++ b/features/project/commits/commits.feature @@ -83,11 +83,6 @@ Feature: Project Commits #Given I visit my project's commits stats page #Then I see commits stats - Scenario: I browse big commit - Given I visit big commit page - Then I see big commit warning - And I see "Reload with full diff" link - Scenario: I browse a commit with an image Given I visit a commit with an image that changed Then The diff links to both the previous and current image diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb index 239036e431d..bea9f9d198b 100644 --- a/features/steps/project/commits/commits.rb +++ b/features/steps/project/commits/commits.rb @@ -125,25 +125,6 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps expect(page).to have_content 'Authors' end - step 'I visit big commit page' do - # Create a temporary scope to ensure that the stub_const is removed after user - RSpec::Mocks.with_temporary_scope do - stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_lines: 1, max_files: 1 }) - visit namespace_project_commit_path(@project.namespace, @project, sample_big_commit.id) - end - end - - step 'I see big commit warning' do - expect(page).to have_content sample_big_commit.message - expect(page).to have_content "Too many changes" - end - - step 'I see "Reload with full diff" link' do - link = find_link('Reload with full diff') - expect(link[:href]).to end_with('?force_show_diff=true') - expect(link[:href]).not_to include('.html') - end - step 'I visit a commit with an image that changed' do visit namespace_project_commit_path(@project.namespace, @project, sample_image_commit.id) end diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index e2db33d8345..65ca8760958 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -31,26 +31,11 @@ describe DiffHelper do end end - describe 'diff_hard_limit_enabled?' do - it 'should return true if param is provided' do - allow(controller).to receive(:params) { { force_show_diff: true } } - expect(diff_hard_limit_enabled?).to be_truthy - end - - it 'should return false if param is not provided' do - expect(diff_hard_limit_enabled?).to be_falsey - end - end - describe 'diff_options' do - it 'should return hard limit for a diff if force diff is true' do + it 'should return hard limit for a diff' do allow(controller).to receive(:params) { { force_show_diff: true } } expect(diff_options).to include(Commit.max_diff_options) end - - it 'should return safe limit for a diff if force diff is false' do - expect(diff_options).not_to include(:max_lines, :max_files) - end end describe 'unfold_bottom_class' do From b8d3016abbfeaa0658216a9d21138435f2379e38 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Wed, 29 Jun 2016 17:14:17 +0100 Subject: [PATCH 045/335] Added frontend collapsible behavior --- app/assets/javascripts/diff.js.coffee | 2 + .../javascripts/merge_request_tabs.js.coffee | 1 + app/assets/javascripts/single_diff.js.coffee | 52 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 app/assets/javascripts/single_diff.js.coffee diff --git a/app/assets/javascripts/diff.js.coffee b/app/assets/javascripts/diff.js.coffee index 6d9b364cb8d..49c43c09983 100644 --- a/app/assets/javascripts/diff.js.coffee +++ b/app/assets/javascripts/diff.js.coffee @@ -1,6 +1,8 @@ class @Diff UNFOLD_COUNT = 20 constructor: -> + $('.files .diff-file').singleDiff() + $(document).off('click', '.js-unfold') $(document).on('click', '.js-unfold', (event) => target = $(event.target) diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee index 894f80586f1..728ee5a2aa2 100644 --- a/app/assets/javascripts/merge_request_tabs.js.coffee +++ b/app/assets/javascripts/merge_request_tabs.js.coffee @@ -160,6 +160,7 @@ class @MergeRequestTabs $('#diffs').html data.html gl.utils.localTimeAgo($('.js-timeago', 'div#diffs')) $('#diffs .js-syntax-highlight').syntaxHighlight() + $('#diffs .diff-file').singleDiff() @expandViewContainer() if @diffViewType() is 'parallel' @diffsLoaded = true @scrollToElement("#diffs") diff --git a/app/assets/javascripts/single_diff.js.coffee b/app/assets/javascripts/single_diff.js.coffee new file mode 100644 index 00000000000..4d1c28c082b --- /dev/null +++ b/app/assets/javascripts/single_diff.js.coffee @@ -0,0 +1,52 @@ +class @SingleDiff + + LOADING_HTML = '' + ERROR_HTML = '
Could not load diff
' + + constructor: (@file) -> + @content = $('.diff-content', @file) + @diffForPath = @content.data 'diff-for-path' + @setOpenState() + + $('.file-title > a', @file).on 'click', @toggleDiff + + setOpenState: -> + if @diffForPath + @isOpen = false + else + @isOpen = true + @contentHTML = @content.html() + return + + toggleDiff: (e) => + e.preventDefault() + @isOpen = !@isOpen + if not @isOpen and not @hasError + @content.empty() + return + if @contentHTML + @setContentHTML() + else + @getContentHTML() + return + + getContentHTML: -> + @content.html(LOADING_HTML).addClass 'loading' + $.get @diffForPath, (data) => + if data.html + @setContentHTML data.html + else + @hasError = true + @content.html ERROR_HTML + @content.removeClass 'loading' + return + + setContentHTML: (contentHTML) -> + @contentHTML = contentHTML if contentHTML + @content.html @contentHTML + @content.syntaxHighlight() + +$.fn.singleDiff = -> + return @each -> + if not $.data this, 'singleDiff' + $.data this, 'singleDiff', new SingleDiff this From 94d9e168def805afe04084c4206a78e3fa0e9f69 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 8 Jul 2016 11:17:37 +0100 Subject: [PATCH 046/335] changes the project_title_spec accordingly --- spec/javascripts/project_title_spec.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/javascripts/project_title_spec.js.coffee b/spec/javascripts/project_title_spec.js.coffee index f0d26fb5446..e49dfbf1ba4 100644 --- a/spec/javascripts/project_title_spec.js.coffee +++ b/spec/javascripts/project_title_spec.js.coffee @@ -22,7 +22,7 @@ describe 'Project Title', -> @projects_data = fixture.load('projects.json')[0] spyOn(jQuery, 'ajax').and.callFake (req) => - expect(req.url).toBe('/api/v3/projects.json') + expect(req.url).toBe('/api/v3/projects.json?format=simple') d = $.Deferred() d.resolve @projects_data d.promise() From 58c76f4be1b6c3ea3db62b771f8df8b71bc57273 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 8 Jul 2016 12:06:39 +0100 Subject: [PATCH 047/335] fixes missing field on basicprojectdetails --- .Gemfile.swm | Bin 0 -> 16384 bytes .Gemfile.swn | Bin 0 -> 16384 bytes app/assets/javascripts/gl_dropdown.js.coffee | 1 + lib/api/entities.rb | 1 + 4 files changed, 2 insertions(+) create mode 100644 .Gemfile.swm create mode 100644 .Gemfile.swn diff --git a/.Gemfile.swm b/.Gemfile.swm new file mode 100644 index 0000000000000000000000000000000000000000..c5905cff7932aba6a13e5bafc60086613e1d4416 GIT binary patch literal 16384 zcmeI3U5qS66~`M8L?>Z54KP8FvrKD&>Rj$b6uZO_8c16L}SG$jbfPJtVTB zOvNi#+Wy*FptZnjw7~hn(qeCcgy%Y!u?sJ_;WggZinSJKEznw^wLoiu)&i{sS_`xm zXf5#nV1cSQE4Tw4In#CKPWO4nj?b6>ZLbI1?|1DeKg<2S>OL=Z75IAG&+SKRfz|@8 z1zHQV7HBQdTA;N+Yk}4Rtp!>Ov=(SB@ISBsPlDiFw0k)v0Py_ZpZ{NcOA!14{0ck- z9t1VG8QcUe0e^aP5c~rC9DEmi4%`Ja_z>uT%fLC{h4X{pN8lbX1XqBIz)R-^!Oy_A zKmiVc^S~e96a+s8_kuCF3hV*P;O*drH=V3^`El?Q@ECXqJP5uBCg9_s2SPwT@qW-; zB2NOwMj~VLbuMF7=HWz@8=}P98fhxZ`ODe-?N_peXgOM(caj|^*|BBI(Sc}TJ{Xm% zF4&4IV~Gmp*lJOvGUk<3In$!t6lD;Ywh}oUZn?UbqJ?N_9@1<0Q9FTLZK#nfrIYDJ zd!v2y{mLtt`A*u*F`g%ETvdf$>2^)~IvOc8N<|c_tUFX?opt9ft5hN5ZdnhuLM`ID zl+{+q^SryZweKeR;X%JxUq@ZXg!nJ&;>QM~H8~k9F8dz993ugh{Y7T%MZF#@Mb_pz zmNHRsrO3w2Sh*MNp?;b2iQJHJs;aT8VtygoANiZ(QmAyMayvwO%rH>psvL#XU*Ehf zKM?hN?Il|Fg`^+^mZH6`>7ydKdZuNg+H$nis8)(3=4Bx&uNr!`gmMg`Q5~=TjO#&| z@p7XsAY*&J)M#IEz0pslp1r>ZCs>4RDNfX~6f11Lk?NLQrj-<~_HmV^VId2V%A8DK zYww`~@`!abny5)`T;tl~>xWrUs#s_(^O1F}jus*bhqd$GMJT?9?!@>fEa4URV)8a8 z0?lmYt93P2r95dI+KJWquo3G;%TyEmj`4|R8e_{x!g=&iVN7_up$i^+y%!>QgzFcT zt3u?uf{^PM%4bTgYd1yS+;n5AVxGQY38u7f4eHT6B?qB<_{q8{T4-FyluUF}*8$(7 z0o1As@7+nMijyiAw`z1src?QSq%!6*dTz#G4T9{3>zuXVH>DKigl~$e)lB1a>>9if zrWvo$|1rHU=9?PxES2OdG}4Q9u&!NQKkTa9;F-*MDN$d?M5^AtXrTiYj_?r*DE7D! zAnS*)2Px}j9L2Q-{5f?y66zWu=gcK9L9FeLst#=v$+#AXmw4$fl_y21yH=H`9I#4} zKvk-grHUs^l?kH#9K-8?>_)^gHwN~#z`n|I$uXP46xus&dYEQCd~e30vrUSI6jOH^ zqfL}CfnK6rnF!w9b^}H+D|jio8P_mS6h*f2@rf1ti`DKhAJB~5U=vh`7O+V1l*tTn zV^bJEq`qO=lQ*Gra!~SeD`MARmJjQce$f?ELl%!QU_#T#t*stm6fB&Jx=!Q6Iem|U z9R!b{4JgidOd*QeIb>d&Tv@@VZwhiBysd&?R`4DS1eDF}k~%C^#yCU0Fj}FsM8Mf{ zZ4OE`!IJA5T(s>Sv_GEaQT5``4FbhFA9FAj%f86tatjWYI00I%eH1BAl(E8Vq9y_? zH8u3GR9lb3+n-X4u$riF2>s1cN3+;fGRKZLC5+sGrkUL?ICtS2QfFqNv6H`PS;X*q zSbVA#zBQgRU;1*hcxbZqv4X=`*f4N365T4Db6DYhOj3FyKU#+OG(RZy8)MGgqV43$@fZYWVAZJ>3E8^Z}n3@`~ zts96^x%g-I9N2rA7+|(fD{RHf*a2*AwQEn*DtA!5Q)T?^GSD_0(skHJbUm zQ*gQ-HiGaRF;I%uL~~J%vtHN;#$1yVHkWN0VZ{w4Ij7oOaq+ zmIVDysi~1Xg(9iHY}1IZJDQ#mv7%ORx;IJ`?Y>1}0=ln_K5egkeRg7z6a{0*EBlsDvPmY$w~&C(^}67OL)@ku{|>yXvA) zCBg(-JLp?T#E{o%)!*c4E&2#ssDzeiGk6rv*Q@|D0^01GR*$j_Atm*TzozXQMv8pa zn!xz=j_tbfIkOa4_Y1KB_HUraqARtoh3@WM*n7YP0ujsM76NBeIYZFbbVx~RK~Y#D z=n1aT8w`Yrw|VUMaWG7wax89MCAT>|+Wd|-eJ&ZS^r$IzqQQ0iFMQI0s)(=VYA!{qy@% zINv`Feht0@J`HXF$H6{u0eBmr9Kd7XOW+gW7SIJR<81#lcnI7H1h@)Z3Em0b0se+_ z{tMuF@Emvw+y^G$X0Qx8;1cj&a4z^O&i<#spTU#hm*5fb1Mm&-b&!J$jKB(b54ady z2>yY7{vDhG&w$^6$HBwk+u+Nf1Z0mRpuJiPv=(SB&|09iKx={40<8sJ#RBGlr?+%S z|FVhCN@UG070Gya#M#V{xtylyTt4=g5ueRkxE=6V@U$BDzrd(yY$|?$dCi=BL|ai^^tNy-o+Vc0bSaU9lJeA z86l;pRhz2Z-*MKU=K%QkSa%mC+o83+D;JXzx$d}M7G7PP!H{SUrq6CV_Sn-$s)Q^w zkF+92#XgY10V=6Y`jDQ<%-l4uky-6iro%tjnXh1(J|7}I(MR$uYZTh{_-B411{n@z zjSnoEv35_9tSNLM==p*@-I^1dE7oIGBj<;Q1IXUYo}uxZT9+Ji+s?kk^SZ!wxZ5*)Zjl z72d5-jdm^6$S|gGvQ0>knQ#gxGwxQGj zTndCHG<<(s&1m%W%hqfrf|vG6hPQH!X9j*gBR7h!?i6x8K|YEKeQBXmOpcM5KD?rq zZCmCks8bBt$*loGR;ZCkfLo50A2{m3v^6icy$e(yPWqIO@(mA%9GN+%6!f)qAiXYf O8_b6w!5ou zSN9Hkqo81n3QAA|nh=l&6ZJt79>n+}`hW_G_$U~O=z~{c;;R}z{--{AX7{pz#0L}8 zo%}MhQ>Uv=ojP@@>U8g5;Um|rvwhKWfa}dc@MwO=jZg5$&b<2lX9ShxBb5(SCDO5? z@?Ea=gGa(dgvUudT#Qnlzr5h>+bZnpGVUIdRmun5k@-L+n<7<3Ch{uWkd^zndq`wM znTnUMwEeZUKx=_lX@T>DrN!O?3D0#dV;5dhcn6>BZfTA;N+Yk}4Rtp!>Ov=(SB z&|2XC!2(rrR&WP8a;EFdo$m9D9iRVp*Msi&yLObH<^EoEpO?A{d_C^x_M^2xYk}4R ztp!>Ov=(SB&|09iKx={40<8sF3$zyaA6S4VL2xeGy_^yNc>eFt|1Z8N2!0QK0Uibq zfg0QlZUUEpKfW;teg=LDz70ML?gAQo5Olz0;2iM6`9bgla4#5wE5JqIrSpQ|C*T{P z0EfVN;16#If**qWz!+Qw_JC#ZR`9~>(Jpurd>4EU2(Shs5Q2ArGe7`-{kkCd4)_wd z2Yed52mA(||2lX8+yhp@Mc}uu4T9&vli*(PW$<}02G@a$z=hx(@aJ=a;1qZfJPn=# z-vS2M55V;B4^H*+K9ucno|6+z0Le5{$t|!9lPJ_JE7QJHbC*69mtJ z2f-)7E#Q6NQt&S%V}1vI3?2b@g3o|G;1tIB3GgHEICvO51ik}XtR3YPTSr4{CE#kVA z)mF&!yt}rw?#|EP{ITmjqsH9EH?h-@Gk9 z5cPcRC0h1{q#y*AqP?!^qawL_re&krap__D za-%LFV|%{TXkT%?(NCqGy}t)1ScGgTPSmm#D{Q`z>Xuxll@zY_ah0WEAq$bpoJ?SA z@1X+nh;=lYs7Y>Ilc-) zLgc!Fkn0!9XG*PWH$~pubYrSwp1y1ernGMj>d`zU2cdiT$+{_8Xk5pXOmtJ%0pFtm z)T#^b-ASp6lPVXtYII7bQ~7hmExZxhDeGn&#kB?eIdwY{>KY;E%q1^G2z3xO8l#wCXnmcEZGF=^dkAS{gw-Ry-)>64 zWk)p}-|4y>k*YJTcNziQeV9WS{=*VciFl?TBbBCgh6z3ziKNdHUQ{~*^-PsRo@(K` zV(&}kz;$F9?zgS?R(OsbwX-l`8P98;rdv$rELQnYj=D0JcdCq=2dR+Xq6uu73Y zRjQPwiYH8!38MWR!|QwHXb1)UlzR2Tp3l5ez0a~qn6e&-XvBGPjCIT!q zHT1AlTaUxrpHhpkny7FH{moKGv)ENK$Bs88jNE~yncXfpci|gSXJ(uXLnfF_O-31XKXIgeE;@)PMni{dK z8;DZ5_-FSV*n626V75;yY{kpi0c>uyYfspigp_gX;`Z*r8S(n>R2{4J)MutOn)$m^ zaJn8gg76$MP>R+>b5V`6Uf2l6T$2+vmu(th#SLmBIFQw#jyJY#V4&gYf@X=FcG_5$ z1pQ8_sgXQ|BB{S@(}=G-nw}A{qE>LaH%b)kzC~dIy048sNs!j6*@<;pZ8Kt6eYQ;~ z7fmDrl&PXqj9hHMCSyOkemV0lfJjn}N(j=(cCsyfB3*1`q3YflSyM{0t1b#vB22Kg zgT94C40)Ya{Y{?MqK~kJN@$5TgGb?f%?dChpv}H%^(e~_Qc}P8YudhHq{wH<1lXmL z5q50XjnA2-z`9?E4X}R$Jr-T5buDyv@50^#CJ=~N4!00Eo5~r2zNSM;QVWX05XZ-178I>$iN7!fOmn5!G+-O z=;zOv=(SB@Cp_%2Ryx{L;9CZ zd{!cBcBx3lyCcbFhRo$OP3Q8l$Bg)F*23+8$AYKTxF3&2lkKGRw@DseYs!#NL76|T z@RH|Ba(9Hlo|_I3$JDSwG6QGiX_jx>5tX*l=D6@-It{tHa)B-+bRfxQjy3+2NO=|< z2Ly6}37!`qbFA_{rE;ffR9oj9yV|Aq=0%1aXdgM4bgPe)6Y?(3Knv*7e(c!oNy-Q* zMXlOY<^GPd20aJBzsI_}DA^9J?OnN;l*o0*{j%`t;tYmFb1;2&)3L{%K2jxQp?Rbg zF)H?f3=U99ZPJJIOlIb$d5z3!pE4c(!OnaI%k=pW>4`p)XIZ1rw#Ps76EVneC~JIR z(Tufwieycp3qj8p?CI8=*j%w5s~R~!JRCswX7&uVA1cpea9rBbc7fE|sr*LH3q7Md zQl~MJ=Qw9dI-J1@O*Y8Z6*vtB$Y_n}*+eJ{I>PNHR_6(xe}%kGj2U)_xyptqr>yX9 zg=(~Gp+<%=g_CVUg3N?dIGJ&`x^%2Ho|)v{MKB^X$h(Q-M5tm_gypt@pa(>+a7Uxf zGCBEa!rq8DIU^Z~WO{}SaiYTtr{zMayt&;ZQ~a3k5Y`1Usj+#mWgTSJe|FaFd*D(a zG@;@9+iFImr(d>aGZDPBS2DbnYdkaX^BK8ObakhY>k0BvROm|!m11&?#Ps16wQSom zPeGkx$WCqz5VAszL;~D$to*=H2d1rgx$Rw``f$>xe3Wl^IONF8Ii;Yltpn+Gkt1JS M33d(2?c=Ne087$n)Bpeg literal 0 HcmV?d00001 diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index ed9dfcc917e..233a3873ce9 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -399,6 +399,7 @@ class GitLabDropdown selected = true # Set URL + console.log(data) if @options.url? url = @options.url(data) else diff --git a/lib/api/entities.rb b/lib/api/entities.rb index aae1840821e..8cba77b148a 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -54,6 +54,7 @@ module API class BasicProjectDetails < Grape::Entity expose :id + expose :http_url_to_repo, :web_url expose :name, :name_with_namespace expose :path, :path_with_namespace end From b0b374b8c9c95eb65e3ff8bf854353cbf2f86a16 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 8 Jul 2016 12:07:17 +0100 Subject: [PATCH 048/335] removes gemfile.lock dotfiles --- .Gemfile.swm | Bin 16384 -> 0 bytes .Gemfile.swn | Bin 16384 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .Gemfile.swm delete mode 100644 .Gemfile.swn diff --git a/.Gemfile.swm b/.Gemfile.swm deleted file mode 100644 index c5905cff7932aba6a13e5bafc60086613e1d4416..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeI3U5qS66~`M8L?>Z54KP8FvrKD&>Rj$b6uZO_8c16L}SG$jbfPJtVTB zOvNi#+Wy*FptZnjw7~hn(qeCcgy%Y!u?sJ_;WggZinSJKEznw^wLoiu)&i{sS_`xm zXf5#nV1cSQE4Tw4In#CKPWO4nj?b6>ZLbI1?|1DeKg<2S>OL=Z75IAG&+SKRfz|@8 z1zHQV7HBQdTA;N+Yk}4Rtp!>Ov=(SB@ISBsPlDiFw0k)v0Py_ZpZ{NcOA!14{0ck- z9t1VG8QcUe0e^aP5c~rC9DEmi4%`Ja_z>uT%fLC{h4X{pN8lbX1XqBIz)R-^!Oy_A zKmiVc^S~e96a+s8_kuCF3hV*P;O*drH=V3^`El?Q@ECXqJP5uBCg9_s2SPwT@qW-; zB2NOwMj~VLbuMF7=HWz@8=}P98fhxZ`ODe-?N_peXgOM(caj|^*|BBI(Sc}TJ{Xm% zF4&4IV~Gmp*lJOvGUk<3In$!t6lD;Ywh}oUZn?UbqJ?N_9@1<0Q9FTLZK#nfrIYDJ zd!v2y{mLtt`A*u*F`g%ETvdf$>2^)~IvOc8N<|c_tUFX?opt9ft5hN5ZdnhuLM`ID zl+{+q^SryZweKeR;X%JxUq@ZXg!nJ&;>QM~H8~k9F8dz993ugh{Y7T%MZF#@Mb_pz zmNHRsrO3w2Sh*MNp?;b2iQJHJs;aT8VtygoANiZ(QmAyMayvwO%rH>psvL#XU*Ehf zKM?hN?Il|Fg`^+^mZH6`>7ydKdZuNg+H$nis8)(3=4Bx&uNr!`gmMg`Q5~=TjO#&| z@p7XsAY*&J)M#IEz0pslp1r>ZCs>4RDNfX~6f11Lk?NLQrj-<~_HmV^VId2V%A8DK zYww`~@`!abny5)`T;tl~>xWrUs#s_(^O1F}jus*bhqd$GMJT?9?!@>fEa4URV)8a8 z0?lmYt93P2r95dI+KJWquo3G;%TyEmj`4|R8e_{x!g=&iVN7_up$i^+y%!>QgzFcT zt3u?uf{^PM%4bTgYd1yS+;n5AVxGQY38u7f4eHT6B?qB<_{q8{T4-FyluUF}*8$(7 z0o1As@7+nMijyiAw`z1src?QSq%!6*dTz#G4T9{3>zuXVH>DKigl~$e)lB1a>>9if zrWvo$|1rHU=9?PxES2OdG}4Q9u&!NQKkTa9;F-*MDN$d?M5^AtXrTiYj_?r*DE7D! zAnS*)2Px}j9L2Q-{5f?y66zWu=gcK9L9FeLst#=v$+#AXmw4$fl_y21yH=H`9I#4} zKvk-grHUs^l?kH#9K-8?>_)^gHwN~#z`n|I$uXP46xus&dYEQCd~e30vrUSI6jOH^ zqfL}CfnK6rnF!w9b^}H+D|jio8P_mS6h*f2@rf1ti`DKhAJB~5U=vh`7O+V1l*tTn zV^bJEq`qO=lQ*Gra!~SeD`MARmJjQce$f?ELl%!QU_#T#t*stm6fB&Jx=!Q6Iem|U z9R!b{4JgidOd*QeIb>d&Tv@@VZwhiBysd&?R`4DS1eDF}k~%C^#yCU0Fj}FsM8Mf{ zZ4OE`!IJA5T(s>Sv_GEaQT5``4FbhFA9FAj%f86tatjWYI00I%eH1BAl(E8Vq9y_? zH8u3GR9lb3+n-X4u$riF2>s1cN3+;fGRKZLC5+sGrkUL?ICtS2QfFqNv6H`PS;X*q zSbVA#zBQgRU;1*hcxbZqv4X=`*f4N365T4Db6DYhOj3FyKU#+OG(RZy8)MGgqV43$@fZYWVAZJ>3E8^Z}n3@`~ zts96^x%g-I9N2rA7+|(fD{RHf*a2*AwQEn*DtA!5Q)T?^GSD_0(skHJbUm zQ*gQ-HiGaRF;I%uL~~J%vtHN;#$1yVHkWN0VZ{w4Ij7oOaq+ zmIVDysi~1Xg(9iHY}1IZJDQ#mv7%ORx;IJ`?Y>1}0=ln_K5egkeRg7z6a{0*EBlsDvPmY$w~&C(^}67OL)@ku{|>yXvA) zCBg(-JLp?T#E{o%)!*c4E&2#ssDzeiGk6rv*Q@|D0^01GR*$j_Atm*TzozXQMv8pa zn!xz=j_tbfIkOa4_Y1KB_HUraqARtoh3@WM*n7YP0ujsM76NBeIYZFbbVx~RK~Y#D z=n1aT8w`Yrw|VUMaWG7wax89MCAT>|+Wd|-eJ&ZS^r$IzqQQ0iFMQI0s)(=VYA!{qy@% zINv`Feht0@J`HXF$H6{u0eBmr9Kd7XOW+gW7SIJR<81#lcnI7H1h@)Z3Em0b0se+_ z{tMuF@Emvw+y^G$X0Qx8;1cj&a4z^O&i<#spTU#hm*5fb1Mm&-b&!J$jKB(b54ady z2>yY7{vDhG&w$^6$HBwk+u+Nf1Z0mRpuJiPv=(SB&|09iKx={40<8sJ#RBGlr?+%S z|FVhCN@UG070Gya#M#V{xtylyTt4=g5ueRkxE=6V@U$BDzrd(yY$|?$dCi=BL|ai^^tNy-o+Vc0bSaU9lJeA z86l;pRhz2Z-*MKU=K%QkSa%mC+o83+D;JXzx$d}M7G7PP!H{SUrq6CV_Sn-$s)Q^w zkF+92#XgY10V=6Y`jDQ<%-l4uky-6iro%tjnXh1(J|7}I(MR$uYZTh{_-B411{n@z zjSnoEv35_9tSNLM==p*@-I^1dE7oIGBj<;Q1IXUYo}uxZT9+Ji+s?kk^SZ!wxZ5*)Zjl z72d5-jdm^6$S|gGvQ0>knQ#gxGwxQGj zTndCHG<<(s&1m%W%hqfrf|vG6hPQH!X9j*gBR7h!?i6x8K|YEKeQBXmOpcM5KD?rq zZCmCks8bBt$*loGR;ZCkfLo50A2{m3v^6icy$e(yPWqIO@(mA%9GN+%6!f)qAiXYf O8_b6w!5ou zSN9Hkqo81n3QAA|nh=l&6ZJt79>n+}`hW_G_$U~O=z~{c;;R}z{--{AX7{pz#0L}8 zo%}MhQ>Uv=ojP@@>U8g5;Um|rvwhKWfa}dc@MwO=jZg5$&b<2lX9ShxBb5(SCDO5? z@?Ea=gGa(dgvUudT#Qnlzr5h>+bZnpGVUIdRmun5k@-L+n<7<3Ch{uWkd^zndq`wM znTnUMwEeZUKx=_lX@T>DrN!O?3D0#dV;5dhcn6>BZfTA;N+Yk}4Rtp!>Ov=(SB z&|2XC!2(rrR&WP8a;EFdo$m9D9iRVp*Msi&yLObH<^EoEpO?A{d_C^x_M^2xYk}4R ztp!>Ov=(SB&|09iKx={40<8sF3$zyaA6S4VL2xeGy_^yNc>eFt|1Z8N2!0QK0Uibq zfg0QlZUUEpKfW;teg=LDz70ML?gAQo5Olz0;2iM6`9bgla4#5wE5JqIrSpQ|C*T{P z0EfVN;16#If**qWz!+Qw_JC#ZR`9~>(Jpurd>4EU2(Shs5Q2ArGe7`-{kkCd4)_wd z2Yed52mA(||2lX8+yhp@Mc}uu4T9&vli*(PW$<}02G@a$z=hx(@aJ=a;1qZfJPn=# z-vS2M55V;B4^H*+K9ucno|6+z0Le5{$t|!9lPJ_JE7QJHbC*69mtJ z2f-)7E#Q6NQt&S%V}1vI3?2b@g3o|G;1tIB3GgHEICvO51ik}XtR3YPTSr4{CE#kVA z)mF&!yt}rw?#|EP{ITmjqsH9EH?h-@Gk9 z5cPcRC0h1{q#y*AqP?!^qawL_re&krap__D za-%LFV|%{TXkT%?(NCqGy}t)1ScGgTPSmm#D{Q`z>Xuxll@zY_ah0WEAq$bpoJ?SA z@1X+nh;=lYs7Y>Ilc-) zLgc!Fkn0!9XG*PWH$~pubYrSwp1y1ernGMj>d`zU2cdiT$+{_8Xk5pXOmtJ%0pFtm z)T#^b-ASp6lPVXtYII7bQ~7hmExZxhDeGn&#kB?eIdwY{>KY;E%q1^G2z3xO8l#wCXnmcEZGF=^dkAS{gw-Ry-)>64 zWk)p}-|4y>k*YJTcNziQeV9WS{=*VciFl?TBbBCgh6z3ziKNdHUQ{~*^-PsRo@(K` zV(&}kz;$F9?zgS?R(OsbwX-l`8P98;rdv$rELQnYj=D0JcdCq=2dR+Xq6uu73Y zRjQPwiYH8!38MWR!|QwHXb1)UlzR2Tp3l5ez0a~qn6e&-XvBGPjCIT!q zHT1AlTaUxrpHhpkny7FH{moKGv)ENK$Bs88jNE~yncXfpci|gSXJ(uXLnfF_O-31XKXIgeE;@)PMni{dK z8;DZ5_-FSV*n626V75;yY{kpi0c>uyYfspigp_gX;`Z*r8S(n>R2{4J)MutOn)$m^ zaJn8gg76$MP>R+>b5V`6Uf2l6T$2+vmu(th#SLmBIFQw#jyJY#V4&gYf@X=FcG_5$ z1pQ8_sgXQ|BB{S@(}=G-nw}A{qE>LaH%b)kzC~dIy048sNs!j6*@<;pZ8Kt6eYQ;~ z7fmDrl&PXqj9hHMCSyOkemV0lfJjn}N(j=(cCsyfB3*1`q3YflSyM{0t1b#vB22Kg zgT94C40)Ya{Y{?MqK~kJN@$5TgGb?f%?dChpv}H%^(e~_Qc}P8YudhHq{wH<1lXmL z5q50XjnA2-z`9?E4X}R$Jr-T5buDyv@50^#CJ=~N4!00Eo5~r2zNSM;QVWX05XZ-178I>$iN7!fOmn5!G+-O z=;zOv=(SB@Cp_%2Ryx{L;9CZ zd{!cBcBx3lyCcbFhRo$OP3Q8l$Bg)F*23+8$AYKTxF3&2lkKGRw@DseYs!#NL76|T z@RH|Ba(9Hlo|_I3$JDSwG6QGiX_jx>5tX*l=D6@-It{tHa)B-+bRfxQjy3+2NO=|< z2Ly6}37!`qbFA_{rE;ffR9oj9yV|Aq=0%1aXdgM4bgPe)6Y?(3Knv*7e(c!oNy-Q* zMXlOY<^GPd20aJBzsI_}DA^9J?OnN;l*o0*{j%`t;tYmFb1;2&)3L{%K2jxQp?Rbg zF)H?f3=U99ZPJJIOlIb$d5z3!pE4c(!OnaI%k=pW>4`p)XIZ1rw#Ps76EVneC~JIR z(Tufwieycp3qj8p?CI8=*j%w5s~R~!JRCswX7&uVA1cpea9rBbc7fE|sr*LH3q7Md zQl~MJ=Qw9dI-J1@O*Y8Z6*vtB$Y_n}*+eJ{I>PNHR_6(xe}%kGj2U)_xyptqr>yX9 zg=(~Gp+<%=g_CVUg3N?dIGJ&`x^%2Ho|)v{MKB^X$h(Q-M5tm_gypt@pa(>+a7Uxf zGCBEa!rq8DIU^Z~WO{}SaiYTtr{zMayt&;ZQ~a3k5Y`1Usj+#mWgTSJe|FaFd*D(a zG@;@9+iFImr(d>aGZDPBS2DbnYdkaX^BK8ObakhY>k0BvROm|!m11&?#Ps16wQSom zPeGkx$WCqz5VAszL;~D$to*=H2d1rgx$Rw``f$>xe3Wl^IONF8Ii;Yltpn+Gkt1JS M33d(2?c=Ne087$n)Bpeg From 90a6be190feea0966e9ed9b6731d930bcff32d68 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 6 Jul 2016 12:36:39 +0100 Subject: [PATCH 049/335] Ensure only renderable text diffs are collapsed Other diffs (those that are too large to render anyway, image diffs, diffs suppressed by .gitattributes) should be rendered immediately. --- app/assets/javascripts/single_diff.js.coffee | 10 +- app/assets/stylesheets/framework/files.scss | 4 + app/helpers/diff_helper.rb | 1 + app/views/projects/diffs/_content.html.haml | 6 +- app/views/projects/diffs/_file.html.haml | 7 +- .../expand_collapse_diffs_spec.rb | 138 ++++++++++++++++++ .../labels/update_prioritization_spec.rb | 2 +- spec/support/capybara_helpers.rb | 8 + 8 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 spec/features/merge_requests/expand_collapse_diffs_spec.rb diff --git a/app/assets/javascripts/single_diff.js.coffee b/app/assets/javascripts/single_diff.js.coffee index 4d1c28c082b..76db716317b 100644 --- a/app/assets/javascripts/single_diff.js.coffee +++ b/app/assets/javascripts/single_diff.js.coffee @@ -2,13 +2,15 @@ class @SingleDiff LOADING_HTML = '' ERROR_HTML = '
Could not load diff
' + COLLAPSED_HTML = '
This diff is collapsed. Click to expand it.
' constructor: (@file) -> @content = $('.diff-content', @file) - @diffForPath = @content.data 'diff-for-path' + @diffForPath = @content.find('[data-diff-for-path]').data 'diff-for-path' @setOpenState() $('.file-title > a', @file).on 'click', @toggleDiff + @enableToggleOnContent() setOpenState: -> if @diffForPath @@ -18,11 +20,15 @@ class @SingleDiff @contentHTML = @content.html() return + enableToggleOnContent: -> + @content.find('.nothing-here-block.diff-collapsed').on 'click', @toggleDiff + toggleDiff: (e) => e.preventDefault() @isOpen = !@isOpen if not @isOpen and not @hasError - @content.empty() + @content.html COLLAPSED_HTML + @enableToggleOnContent return if @contentHTML @setContentHTML() diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 71e4b50f2af..02480689f09 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -189,3 +189,7 @@ span.idiff { border-bottom-right-radius: 2px; } } + +.nothing-here-block.diff-collapsed { + cursor: pointer; +} diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 9a5920edfa2..93f12198a58 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -15,6 +15,7 @@ module DiffHelper diff_commit = commit_for_diff(diff_file) blob = project.repository.blob_for_diff(diff_commit, diff_file) + @expand_all = true locals = { diff_file: diff_file, diff --git a/app/views/projects/diffs/_content.html.haml b/app/views/projects/diffs/_content.html.haml index 832aa0c5a14..9c6a17c0a8c 100644 --- a/app/views/projects/diffs/_content.html.haml +++ b/app/views/projects/diffs/_content.html.haml @@ -9,7 +9,11 @@ - if !project.repository.diffable?(blob) .nothing-here-block This diff was suppressed by a .gitattributes entry. - elsif diff_file.diff_lines.length > 0 - - if diff_view == 'parallel' + - if diff_file.collapsed_by_default? && !@expand_all + - url = url_for(params.merge(action: :diff_for_path, path: diff_file.file_path, format: nil)) + .nothing-here-block.diff-collapsed{data: { diff_for_path: url } } + This diff is collapsed. Click to expand it. + - elsif diff_view == 'parallel' = render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob - else = render "projects/diffs/text_file", diff_file: diff_file diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml index c83ed55efe1..c306909fb1a 100644 --- a/app/views/projects/diffs/_file.html.haml +++ b/app/views/projects/diffs/_file.html.haml @@ -16,9 +16,4 @@ = view_file_btn(diff_commit.id, diff_file, project) - - if diff_file.collapsed_by_default? - - url = url_for(params.merge(action: :diff_for_path, path: diff_file.file_path, format: nil)) - .diff-content.diff-wrap-lines{data: { diff_for_path: url }} - .nothing-here-block File hidden by default; content for this element available at #{url} - - else - = render 'projects/diffs/content', diff_file: diff_file, diff_commit: diff_commit, diff_refs: diff_refs, blob: blob, project: project + = render 'projects/diffs/content', diff_file: diff_file, diff_commit: diff_commit, diff_refs: diff_refs, blob: blob, project: project diff --git a/spec/features/merge_requests/expand_collapse_diffs_spec.rb b/spec/features/merge_requests/expand_collapse_diffs_spec.rb new file mode 100644 index 00000000000..173ea3720da --- /dev/null +++ b/spec/features/merge_requests/expand_collapse_diffs_spec.rb @@ -0,0 +1,138 @@ +require 'spec_helper' + +feature 'Expand and collapse diffs', js: true, feature: true do + include WaitForAjax + + before do + login_as :admin + merge_request = create(:merge_request, source_branch: 'expand-collapse-diffs', target_branch: 'master') + project = merge_request.source_project + + # Ensure that undiffable.md is in .gitattributes + project.repository.copy_gitattributes('expand-collapse-diffs') + visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request) + execute_script('window.ajaxUris = []; $(document).ajaxSend(function(event, xhr, settings) { ajaxUris.push(settings.url) });') + end + + def file_container(filename) + find("[data-blob-diff-path*='#{filename}']") + end + + # Use define_method instead of let (which is memoized) so that this just works across a + # reload. + # + ['small_diff.md', 'large_diff.md', 'undiffable.md', 'too_large.md', 'too_large_image.jpg'].each do |file| + define_method(file.split('.').first) { file_container(file) } + end + + context 'visiting an existing merge request' do + it 'shows small diffs immediately' do + expect(small_diff).to have_selector('.code') + expect(small_diff).not_to have_selector('.nothing-here-block') + end + + it 'collapses larges diffs by default' do + expect(large_diff).not_to have_selector('.code') + expect(large_diff).to have_selector('.nothing-here-block') + end + + it 'shows non-renderable diffs as such immediately, regardless of their size' do + expect(undiffable).not_to have_selector('.code') + expect(undiffable).to have_selector('.nothing-here-block') + expect(undiffable).to have_content('gitattributes') + end + + it 'does not allow diffs that are larger than the maximum size to be expanded' do + expect(too_large).not_to have_selector('.code') + expect(too_large).to have_selector('.nothing-here-block') + expect(too_large).to have_content('too large') + end + + it 'shows image diffs immediately, regardless of their size' do + expect(too_large_image).not_to have_selector('.nothing-here-block') + expect(too_large_image).to have_selector('.image') + end + + context 'expanding a large diff' do + before do + click_link('large_diff.md') + wait_for_ajax + end + + it 'makes a request to get the content' do + ajax_uris = evaluate_script('ajaxUris') + + expect(ajax_uris).not_to be_empty + expect(ajax_uris.first).to include('large_diff.md') + end + + it 'shows the diff content' do + expect(large_diff).to have_selector('.code') + expect(large_diff).not_to have_selector('.nothing-here-block') + end + + context 'adding a comment to the expanded diff' do + let(:comment_text) { 'A comment' } + + before do + large_diff.find('.line_holder', match: :prefer_exact).hover + large_diff.find('.add-diff-note').click + large_diff.find('.note-textarea').send_keys comment_text + large_diff.find_button('Comment').click + wait_for_ajax + end + + it 'adds the comment' do + expect(large_diff.find('.notes')).to have_content comment_text + end + + context 'reloading the page' do + before { refresh } + + it 'collapses the large diff by default' do + expect(large_diff).not_to have_selector('.code') + expect(large_diff).to have_selector('.nothing-here-block') + end + + context 'expanding the diff' do + before do + click_link('large_diff.md') + wait_for_ajax + end + + it 'shows the diff content' do + expect(large_diff).to have_selector('.code') + expect(large_diff).not_to have_selector('.nothing-here-block') + end + + it 'shows the diff comment' do + expect(large_diff.find('.notes')).to have_content comment_text + end + end + end + end + end + + context 'collapsing an expanded diff' do + before { click_link('small_diff.md') } + + it 'hides the diff content' do + expect(small_diff).not_to have_selector('.code') + expect(small_diff).to have_selector('.nothing-here-block') + end + + context 're-expanding the same diff' do + before { click_link('small_diff.md') } + + it 'shows the diff content' do + expect(small_diff).to have_selector('.code') + expect(small_diff).not_to have_selector('.nothing-here-block') + end + + it 'does not make a new HTTP request' do + expect(evaluate_script('ajaxUris')).to be_empty + end + end + end + end +end diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb index 6a39c302f55..98ba93b4036 100644 --- a/spec/features/projects/labels/update_prioritization_spec.rb +++ b/spec/features/projects/labels/update_prioritization_spec.rb @@ -76,7 +76,7 @@ feature 'Prioritize labels', feature: true do expect(page.all('li').last).to have_content('bug') end - visit current_url + refresh wait_for_ajax page.within('.prioritized-labels') do diff --git a/spec/support/capybara_helpers.rb b/spec/support/capybara_helpers.rb index 9b5c3065eed..b57a3493aff 100644 --- a/spec/support/capybara_helpers.rb +++ b/spec/support/capybara_helpers.rb @@ -27,6 +27,14 @@ module CapybaraHelpers end end end + + # Refresh the page. Calling `visit current_url` doesn't seem to work consistently. + # + def refresh + url = current_url + visit 'about:blank' + visit url + end end RSpec.configure do |config| From c082d92fb959ee2344b90b7fd4e316019452c094 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 6 Jul 2016 13:04:52 +0100 Subject: [PATCH 050/335] Allow expanding all diffs at once --- app/helpers/diff_helper.rb | 4 ++ app/views/projects/diffs/_content.html.haml | 2 +- app/views/projects/diffs/_diffs.html.haml | 2 + .../expand_collapse_diffs_spec.rb | 38 +++++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 93f12198a58..fd7b71407f3 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -8,6 +8,10 @@ module DiffHelper [marked_old_line, marked_new_line] end + def expand_all? + @expand_all || params[:expand].present? + end + def render_diff_for_path(diffs, diff_refs, project) diff_file = safe_diff_files(diffs, diff_refs).first diff --git a/app/views/projects/diffs/_content.html.haml b/app/views/projects/diffs/_content.html.haml index 9c6a17c0a8c..5f4572ab9b0 100644 --- a/app/views/projects/diffs/_content.html.haml +++ b/app/views/projects/diffs/_content.html.haml @@ -9,7 +9,7 @@ - if !project.repository.diffable?(blob) .nothing-here-block This diff was suppressed by a .gitattributes entry. - elsif diff_file.diff_lines.length > 0 - - if diff_file.collapsed_by_default? && !@expand_all + - if diff_file.collapsed_by_default? && !expand_all? - url = url_for(params.merge(action: :diff_for_path, path: diff_file.file_path, format: nil)) .nothing-here-block.diff-collapsed{data: { diff_for_path: url } } This diff is collapsed. Click to expand it. diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index 1975287faee..7b530af0f4a 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -6,6 +6,8 @@ .content-block.oneline-block.files-changed .inline-parallel-buttons + - unless expand_all? + = link_to 'Expand all', url_for(params.merge(expand: 1, format: 'html')), class: 'btn btn-default' - if show_whitespace_toggle - if current_controller?(:commit) = commit_diff_whitespace_link(@project, @commit, class: 'hidden-xs') diff --git a/spec/features/merge_requests/expand_collapse_diffs_spec.rb b/spec/features/merge_requests/expand_collapse_diffs_spec.rb index 173ea3720da..f9c89c4ad96 100644 --- a/spec/features/merge_requests/expand_collapse_diffs_spec.rb +++ b/spec/features/merge_requests/expand_collapse_diffs_spec.rb @@ -135,4 +135,42 @@ feature 'Expand and collapse diffs', js: true, feature: true do end end end + + context 'expanding all diffs' do + before do + click_link('Expand all') + wait_for_ajax + execute_script('window.ajaxUris = []; $(document).ajaxSend(function(event, xhr, settings) { ajaxUris.push(settings.url) });') + end + + it 'reloads the page with all diffs expanded' do + expect(small_diff).to have_selector('.code') + expect(small_diff).not_to have_selector('.nothing-here-block') + + expect(large_diff).to have_selector('.code') + expect(large_diff).not_to have_selector('.nothing-here-block') + end + + context 'collapsing an expanded diff' do + before { click_link('small_diff.md') } + + it 'hides the diff content' do + expect(small_diff).not_to have_selector('.code') + expect(small_diff).to have_selector('.nothing-here-block') + end + + context 're-expanding the same diff' do + before { click_link('small_diff.md') } + + it 'shows the diff content' do + expect(small_diff).to have_selector('.code') + expect(small_diff).not_to have_selector('.nothing-here-block') + end + + it 'does not make a new HTTP request' do + expect(evaluate_script('ajaxUris')).to be_empty + end + end + end + end end From 4add7f65bc925fac3f6380f896fb2eccd236b2f7 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 6 Jul 2016 13:54:38 +0100 Subject: [PATCH 051/335] Fix comments on collapsed and expanded diffs We can't save the HTML as it was on page load, because comments etc. add content that we would lose if we kept the initial HTML. Instead, shuffle elements around. --- app/assets/javascripts/single_diff.js.coffee | 53 +++++++++----------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/app/assets/javascripts/single_diff.js.coffee b/app/assets/javascripts/single_diff.js.coffee index 76db716317b..884d5d43d03 100644 --- a/app/assets/javascripts/single_diff.js.coffee +++ b/app/assets/javascripts/single_diff.js.coffee @@ -1,5 +1,6 @@ class @SingleDiff + WRAPPER = '
' LOADING_HTML = '' ERROR_HTML = '
Could not load diff
' COLLAPSED_HTML = '
This diff is collapsed. Click to expand it.
' @@ -7,51 +8,47 @@ class @SingleDiff constructor: (@file) -> @content = $('.diff-content', @file) @diffForPath = @content.find('[data-diff-for-path]').data 'diff-for-path' - @setOpenState() + @isOpen = !@diffForPath + + if @diffForPath + @collapsedContent = @content + @loadingContent = $(WRAPPER).addClass('loading').html(LOADING_HTML).hide() + @content = null + @collapsedContent.after(@loadingContent) + else + @collapsedContent = $(WRAPPER).html(COLLAPSED_HTML).hide() + @content.after(@collapsedContent) + + @collapsedContent.on 'click', @toggleDiff $('.file-title > a', @file).on 'click', @toggleDiff - @enableToggleOnContent() - - setOpenState: -> - if @diffForPath - @isOpen = false - else - @isOpen = true - @contentHTML = @content.html() - return - - enableToggleOnContent: -> - @content.find('.nothing-here-block.diff-collapsed').on 'click', @toggleDiff toggleDiff: (e) => e.preventDefault() @isOpen = !@isOpen if not @isOpen and not @hasError - @content.html COLLAPSED_HTML - @enableToggleOnContent - return - if @contentHTML - @setContentHTML() + @content.hide() + @collapsedContent.show() + else if @content + @collapsedContent.hide() + @content.show() else @getContentHTML() - return getContentHTML: -> - @content.html(LOADING_HTML).addClass 'loading' + @collapsedContent.hide() + @loadingContent.show() $.get @diffForPath, (data) => + @loadingContent.hide() if data.html - @setContentHTML data.html + @content = $(data.html) + @content.syntaxHighlight() else @hasError = true - @content.html ERROR_HTML - @content.removeClass 'loading' + @content = $(ERROR_HTML) + @collapsedContent.after(@content) return - setContentHTML: (contentHTML) -> - @contentHTML = contentHTML if contentHTML - @content.html @contentHTML - @content.syntaxHighlight() - $.fn.singleDiff = -> return @each -> if not $.data this, 'singleDiff' From 6a46926f88d504778ae49f7824d2b1284a1c62ff Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 6 Jul 2016 17:51:02 +0100 Subject: [PATCH 052/335] Remove unused argument to CompareService#execute --- app/controllers/projects/compare_controller.rb | 14 ++++++++++---- app/services/compare_service.rb | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index 8a04f63f4d4..5e00d2d5aff 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -14,7 +14,7 @@ class Projects::CompareController < Projects::ApplicationController def show compare = CompareService.new. - execute(@project, @head_ref, @project, @start_ref, diff_options) + execute(@project, @head_ref, @project, @start_ref) if compare @commits = Commit.decorate(compare.commits, @project) @@ -37,18 +37,24 @@ class Projects::CompareController < Projects::ApplicationController def diff_for_path compare = CompareService.new. - execute(@project, @head_ref, @project, @base_ref, diff_options) + execute(@project, @head_ref, @project, @start_ref) return render_404 unless compare + @start_commit = @project.commit(@start_ref) @commit = @project.commit(@head_ref) - @base_commit = @project.merge_base_commit(@base_ref, @head_ref) + @base_commit = @project.merge_base_commit(@start_ref, @head_ref) diffs = compare.diffs(diff_options.merge(paths: [params[:path]])) + diff_refs = Gitlab::Diff::DiffRefs.new( + base_sha: @base_commit.try(:sha), + start_sha: @start_commit.try(:sha), + head_sha: @commit.try(:sha) + ) @diff_notes_disabled = true @grouped_diff_notes = {} - render_diff_for_path(diffs, [@base_commit, @commit], @project) + render_diff_for_path(diffs, diff_refs, @project) end def create diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index e2bccbdbcc3..149822aa647 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -3,7 +3,7 @@ require 'securerandom' # Compare 2 branches for one repo or between repositories # and return Gitlab::Git::Compare object that responds to commits and diffs class CompareService - def execute(source_project, source_branch, target_project, target_branch, diff_options = {}) + def execute(source_project, source_branch, target_project, target_branch) source_commit = source_project.commit(source_branch) return unless source_commit From ff55398aafa2feccaba4ed470becabc526b4df48 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 6 Jul 2016 18:15:27 +0100 Subject: [PATCH 053/335] DRY up diff_for_path actions 1. Move render method to a concern, not a helper. 2. Let DiffHelper#diff_options automatically add the path option. 3. Move more instance var definitions to before filters. --- app/controllers/concerns/diff_for_path.rb | 23 +++++++ app/controllers/projects/commit_controller.rb | 61 ++++++++--------- .../projects/compare_controller.rb | 68 ++++++++----------- .../projects/merge_requests_controller.rb | 6 +- app/helpers/diff_helper.rb | 24 +------ 5 files changed, 84 insertions(+), 98 deletions(-) create mode 100644 app/controllers/concerns/diff_for_path.rb diff --git a/app/controllers/concerns/diff_for_path.rb b/app/controllers/concerns/diff_for_path.rb new file mode 100644 index 00000000000..b9b5d136bd9 --- /dev/null +++ b/app/controllers/concerns/diff_for_path.rb @@ -0,0 +1,23 @@ +module DiffForPath + extend ActiveSupport::Concern + + def render_diff_for_path(diffs, diff_refs, project) + diff_file = safe_diff_files(diffs, diff_refs: diff_refs, repository: project.repository).first + + return render_404 unless diff_file + + diff_commit = commit_for_diff(diff_file) + blob = diff_file.blob(diff_commit) + @expand_all = true + + locals = { + diff_file: diff_file, + diff_commit: diff_commit, + diff_refs: diff_refs, + blob: blob, + project: project + } + + render json: { html: view_to_html_string('projects/diffs/_content', locals) } + end +end diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb index 810653b4264..727e84b40a1 100644 --- a/app/controllers/projects/commit_controller.rb +++ b/app/controllers/projects/commit_controller.rb @@ -3,6 +3,7 @@ # Not to be confused with CommitsController, plural. class Projects::CommitController < Projects::ApplicationController include CreatesCommit + include DiffForPath include DiffHelper # Authorize @@ -11,29 +12,14 @@ class Projects::CommitController < Projects::ApplicationController before_action :authorize_update_build!, only: [:cancel_builds, :retry_builds] before_action :authorize_read_commit_status!, only: [:builds] before_action :commit - before_action :define_show_vars, only: [:show, :builds] + before_action :define_commit_vars, only: [:show, :diff_for_path, :builds] + before_action :define_status_vars, only: [:show, :builds] + before_action :define_note_vars, only: [:show, :diff_for_path] before_action :authorize_edit_tree!, only: [:revert, :cherry_pick] def show apply_diff_view_cookie! - @grouped_diff_notes = commit.notes.grouped_diff_notes - @notes = commit.notes.non_diff_notes.fresh - - Banzai::NoteRenderer.render( - @grouped_diff_notes.values.flatten + @notes, - @project, - current_user, - ) - - @note = @project.build_commit_note(commit) - - @noteable = @commit - @comments_target = { - noteable_type: 'Commit', - commit_id: @commit.id - } - respond_to do |format| format.html format.diff { render text: @commit.to_diff } @@ -42,21 +28,7 @@ class Projects::CommitController < Projects::ApplicationController end def diff_for_path - return git_not_found! unless commit - - opts = diff_options - opts[:ignore_whitespace_change] = true if params[:format] == 'diff' - - diffs = commit.diffs(opts.merge(paths: [params[:path]])) - diff_refs = [commit.parent || commit, commit] - - @comments_target = { - noteable_type: 'Commit', - commit_id: @commit.id - } - @grouped_diff_notes = {} - - render_diff_for_path(diffs, diff_refs, @project) + render_diff_for_path(@diffs, @commit.diff_refs, @project) end def builds @@ -132,7 +104,7 @@ class Projects::CommitController < Projects::ApplicationController @ci_builds ||= Ci::Build.where(pipeline: pipelines) end - def define_show_vars + def define_commit_vars return git_not_found! unless commit opts = diff_options @@ -140,7 +112,28 @@ class Projects::CommitController < Projects::ApplicationController @diffs = commit.diffs(opts) @notes_count = commit.notes.count + end + def define_note_vars + @grouped_diff_notes = commit.notes.grouped_diff_notes + @notes = commit.notes.non_diff_notes.fresh + + Banzai::NoteRenderer.render( + @grouped_diff_notes.values.flatten + @notes, + @project, + current_user, + ) + + @note = @project.build_commit_note(commit) + + @noteable = @commit + @comments_target = { + noteable_type: 'Commit', + commit_id: @commit.id + } + end + + def define_status_vars @statuses = CommitStatus.where(pipeline: pipelines) @builds = Ci::Build.where(pipeline: pipelines) end diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index 5e00d2d5aff..5f3ee71444d 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -1,29 +1,51 @@ require 'addressable/uri' class Projects::CompareController < Projects::ApplicationController + include DiffForPath include DiffHelper # Authorize before_action :require_non_empty_project before_action :authorize_download_code! - before_action :assign_ref_vars, only: [:index, :show, :diff_for_path] + before_action :define_ref_vars, only: [:index, :show, :diff_for_path] + before_action :define_diff_vars, only: [:show, :diff_for_path] before_action :merge_request, only: [:index, :show] def index end def show - compare = CompareService.new. - execute(@project, @head_ref, @project, @start_ref) + end - if compare - @commits = Commit.decorate(compare.commits, @project) + def diff_for_path + return render_404 unless @compare + + render_diff_for_path(@diffs, @diff_refs, @project) + end + + def create + redirect_to namespace_project_compare_path(@project.namespace, @project, + params[:from], params[:to]) + end + + private + + def define_ref_vars + @start_ref = Addressable::URI.unescape(params[:from]) + @ref = @head_ref = Addressable::URI.unescape(params[:to]) + end + + def define_diff_vars + @compare = CompareService.new.execute(@project, @head_ref, @project, @start_ref) + + if @compare + @commits = Commit.decorate(@compare.commits, @project) @start_commit = @project.commit(@start_ref) @commit = @project.commit(@head_ref) @base_commit = @project.merge_base_commit(@start_ref, @head_ref) - @diffs = compare.diffs(diff_options) + @diffs = @compare.diffs(diff_options) @diff_refs = Gitlab::Diff::DiffRefs.new( base_sha: @base_commit.try(:sha), start_sha: @start_commit.try(:sha), @@ -35,40 +57,6 @@ class Projects::CompareController < Projects::ApplicationController end end - def diff_for_path - compare = CompareService.new. - execute(@project, @head_ref, @project, @start_ref) - - return render_404 unless compare - - @start_commit = @project.commit(@start_ref) - @commit = @project.commit(@head_ref) - @base_commit = @project.merge_base_commit(@start_ref, @head_ref) - diffs = compare.diffs(diff_options.merge(paths: [params[:path]])) - diff_refs = Gitlab::Diff::DiffRefs.new( - base_sha: @base_commit.try(:sha), - start_sha: @start_commit.try(:sha), - head_sha: @commit.try(:sha) - ) - - @diff_notes_disabled = true - @grouped_diff_notes = {} - - render_diff_for_path(diffs, diff_refs, @project) - end - - def create - redirect_to namespace_project_compare_path(@project.namespace, @project, - params[:from], params[:to]) - end - - private - - def assign_ref_vars - @start_ref = Addressable::URI.unescape(params[:from]) - @ref = @head_ref = Addressable::URI.unescape(params[:to]) - end - def merge_request @merge_request ||= @project.merge_requests.opened. find_by(source_project: @project, source_branch: @head_ref, target_branch: @start_ref) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 3fc5a319c9b..31d7c324e55 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -1,5 +1,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController include ToggleSubscriptionAction + include DiffForPath include DiffHelper include IssuableActions include ToggleAwardEmoji @@ -102,10 +103,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController end define_commit_vars - diffs = @merge_request.diffs(diff_options.merge(paths: [params[:path]])) - diff_refs = @merge_request.diff_refs + diffs = @merge_request.diffs(diff_options) - render_diff_for_path(diffs, diff_refs, @merge_request.project) + render_diff_for_path(diffs, @merge_request.diff_refs, @merge_request.project) end def commits diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index fd7b71407f3..ebfe4e27b78 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -12,26 +12,6 @@ module DiffHelper @expand_all || params[:expand].present? end - def render_diff_for_path(diffs, diff_refs, project) - diff_file = safe_diff_files(diffs, diff_refs).first - - return render_404 unless diff_file - - diff_commit = commit_for_diff(diff_file) - blob = project.repository.blob_for_diff(diff_commit, diff_file) - @expand_all = true - - locals = { - diff_file: diff_file, - diff_commit: diff_commit, - diff_refs: diff_refs, - blob: blob, - project: project - } - - render json: { html: view_to_html_string('projects/diffs/_content', locals) } - end - def diff_view diff_views = %w(inline parallel) @@ -43,7 +23,9 @@ module DiffHelper end def diff_options - Commit.max_diff_options.merge(ignore_whitespace_change: hide_whitespace?) + default_options = Commit.max_diff_options + default_options[:paths] = [params[:path]] if params[:path] + default_options.merge(ignore_whitespace_change: hide_whitespace?) end def safe_diff_files(diffs, diff_refs: nil, repository: nil) From ea1827c9a491de719be6a084fc092b88b1f54600 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 6 Jul 2016 18:35:55 +0100 Subject: [PATCH 054/335] Make expand_all param more explicit --- app/controllers/concerns/diff_for_path.rb | 2 +- app/helpers/diff_helper.rb | 4 ++-- app/views/projects/diffs/_content.html.haml | 2 +- app/views/projects/diffs/_diffs.html.haml | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/concerns/diff_for_path.rb b/app/controllers/concerns/diff_for_path.rb index b9b5d136bd9..5ca8d3af0c9 100644 --- a/app/controllers/concerns/diff_for_path.rb +++ b/app/controllers/concerns/diff_for_path.rb @@ -8,7 +8,7 @@ module DiffForPath diff_commit = commit_for_diff(diff_file) blob = diff_file.blob(diff_commit) - @expand_all = true + @expand_all_diffs = true locals = { diff_file: diff_file, diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index ebfe4e27b78..04490226e50 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -8,8 +8,8 @@ module DiffHelper [marked_old_line, marked_new_line] end - def expand_all? - @expand_all || params[:expand].present? + def expand_all_diffs? + @expand_all_diffs || params[:expand_all_diffs].present? end def diff_view diff --git a/app/views/projects/diffs/_content.html.haml b/app/views/projects/diffs/_content.html.haml index 5f4572ab9b0..bfcd3ee9132 100644 --- a/app/views/projects/diffs/_content.html.haml +++ b/app/views/projects/diffs/_content.html.haml @@ -9,7 +9,7 @@ - if !project.repository.diffable?(blob) .nothing-here-block This diff was suppressed by a .gitattributes entry. - elsif diff_file.diff_lines.length > 0 - - if diff_file.collapsed_by_default? && !expand_all? + - if diff_file.collapsed_by_default? && !expand_all_diffs? - url = url_for(params.merge(action: :diff_for_path, path: diff_file.file_path, format: nil)) .nothing-here-block.diff-collapsed{data: { diff_for_path: url } } This diff is collapsed. Click to expand it. diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index 7b530af0f4a..5db70bbb478 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -6,8 +6,8 @@ .content-block.oneline-block.files-changed .inline-parallel-buttons - - unless expand_all? - = link_to 'Expand all', url_for(params.merge(expand: 1, format: 'html')), class: 'btn btn-default' + - unless expand_all_diffs? + = link_to 'Expand all', url_for(params.merge(expand_all_diffs: 1, format: 'html')), class: 'btn btn-default' - if show_whitespace_toggle - if current_controller?(:commit) = commit_diff_whitespace_link(@project, @commit, class: 'hidden-xs') From 32e593c66323a2cc5cd3b25070c9ae8db725f5be Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Wed, 6 Jul 2016 21:11:44 +0100 Subject: [PATCH 055/335] review changes --- app/assets/javascripts/diff.js.coffee | 2 +- app/assets/javascripts/merge_request_tabs.js.coffee | 2 +- ...{single_diff.js.coffee => single_file_diff.js.coffee} | 9 ++++----- app/assets/stylesheets/framework/blocks.scss | 3 +++ app/assets/stylesheets/framework/files.scss | 4 ---- 5 files changed, 9 insertions(+), 11 deletions(-) rename app/assets/javascripts/{single_diff.js.coffee => single_file_diff.js.coffee} (91%) diff --git a/app/assets/javascripts/diff.js.coffee b/app/assets/javascripts/diff.js.coffee index 49c43c09983..feb908c1abb 100644 --- a/app/assets/javascripts/diff.js.coffee +++ b/app/assets/javascripts/diff.js.coffee @@ -1,7 +1,7 @@ class @Diff UNFOLD_COUNT = 20 constructor: -> - $('.files .diff-file').singleDiff() + $('.files .diff-file').singleFileDiff() $(document).off('click', '.js-unfold') $(document).on('click', '.js-unfold', (event) => diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee index 728ee5a2aa2..d55c4a34c07 100644 --- a/app/assets/javascripts/merge_request_tabs.js.coffee +++ b/app/assets/javascripts/merge_request_tabs.js.coffee @@ -160,7 +160,7 @@ class @MergeRequestTabs $('#diffs').html data.html gl.utils.localTimeAgo($('.js-timeago', 'div#diffs')) $('#diffs .js-syntax-highlight').syntaxHighlight() - $('#diffs .diff-file').singleDiff() + $('#diffs .diff-file').singleFileDiff() @expandViewContainer() if @diffViewType() is 'parallel' @diffsLoaded = true @scrollToElement("#diffs") diff --git a/app/assets/javascripts/single_diff.js.coffee b/app/assets/javascripts/single_file_diff.js.coffee similarity index 91% rename from app/assets/javascripts/single_diff.js.coffee rename to app/assets/javascripts/single_file_diff.js.coffee index 884d5d43d03..f3e225c3728 100644 --- a/app/assets/javascripts/single_diff.js.coffee +++ b/app/assets/javascripts/single_file_diff.js.coffee @@ -1,4 +1,4 @@ -class @SingleDiff +class @SingleFileDiff WRAPPER = '
' LOADING_HTML = '' @@ -24,7 +24,6 @@ class @SingleDiff $('.file-title > a', @file).on 'click', @toggleDiff toggleDiff: (e) => - e.preventDefault() @isOpen = !@isOpen if not @isOpen and not @hasError @content.hide() @@ -49,7 +48,7 @@ class @SingleDiff @collapsedContent.after(@content) return -$.fn.singleDiff = -> +$.fn.singleFileDiff = -> return @each -> - if not $.data this, 'singleDiff' - $.data this, 'singleDiff', new SingleDiff this + if not $.data this, 'singleFileDiff' + $.data this, 'singleFileDiff', new SingleFileDiff this diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 41e77a4ac68..24b1ebab4b0 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -16,6 +16,9 @@ font-weight: normal; font-size: 16px; line-height: 36px; + &.diff-collapsed { + cursor: pointer; + } } .row-content-block { diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 02480689f09..71e4b50f2af 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -189,7 +189,3 @@ span.idiff { border-bottom-right-radius: 2px; } } - -.nothing-here-block.diff-collapsed { - cursor: pointer; -} From 87aba17ecdc74cac627dbd6731ea000933182f3a Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Fri, 8 Jul 2016 10:37:11 +0100 Subject: [PATCH 056/335] Memoize diffs with path options set separately --- app/models/merge_request_diff.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 06b28fc5a75..7e22491d0a3 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -46,7 +46,8 @@ class MergeRequestDiff < ActiveRecord::Base compare.diffs(options) end else - @diffs ||= load_diffs(st_diffs, options) + @diffs ||= {} + @diffs[options[:paths]] ||= load_diffs(st_diffs, options) end end From c160aae6269720b6c2f33de0c4b5c04000f3c745 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 24 Jun 2016 10:06:57 +0100 Subject: [PATCH 057/335] Updated compare dropdowns Closes #18891 --- app/assets/javascripts/project.js.coffee | 5 +++-- .../stylesheets/framework/dropdowns.scss | 11 +++++++--- app/assets/stylesheets/pages/projects.scss | 18 +++++++++++++++++ app/views/projects/compare/_form.html.haml | 20 ++++++++----------- .../projects/compare/_ref_dropdown.html.haml | 5 +++++ app/views/shared/_ref_switcher.html.haml | 2 +- 6 files changed, 43 insertions(+), 18 deletions(-) create mode 100644 app/views/projects/compare/_ref_dropdown.html.haml diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee index 3288c801388..01b08103dcb 100644 --- a/app/assets/javascripts/project.js.coffee +++ b/app/assets/javascripts/project.js.coffee @@ -67,7 +67,7 @@ class @Project selectable: true filterable: true filterByText: true - fieldName: 'ref' + fieldName: $dropdown.data('field-name') renderRow: (ref) -> if ref.header? $('
  • ') @@ -87,5 +87,6 @@ class @Project toggleLabel: (obj, $el) -> $el.text().trim() clicked: (e) -> - $dropdown.closest('form').submit() + unless $dropdown.hasClass('js-compare-dropdown') + $dropdown.closest('form').submit() ) diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index d4e900f80ef..f4edafb2560 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -48,9 +48,6 @@ border: 1px solid $dropdown-toggle-border-color; border-radius: $border-radius-base; outline: 0; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; .fa { position: absolute; @@ -61,6 +58,14 @@ font-size: 10px; } + .dropdown-toggle-text { + display: block; + min-height: 19px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } + &:hover, { border-color: $dropdown-toggle-hover-border-color; diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index bce4aac3334..4e722542fc6 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -632,3 +632,21 @@ pre.light-well { width: 300px; } } + +.compare-input-group { + &.input-group .input-group-addon { + @media (min-width: $screen-sm-min) { + width: 1%; + } + } + + .dropdown-menu-toggle { + width: 100%; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + + .dropdown-menu { + width: 300px; + } +} diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml index dd590a4b8ec..ea9e99ac518 100644 --- a/app/views/projects/compare/_form.html.haml +++ b/app/views/projects/compare/_form.html.haml @@ -3,14 +3,18 @@ - if params[:to] && params[:from] = link_to 'switch', {from: params[:to], to: params[:from]}, {class: 'commits-compare-switch has-tooltip', title: 'Switch base of comparison'} .form-group - .input-group.inline-input-group + = hidden_field_tag :from, params[:from] + .input-group.inline-input-group.compare-input-group.dropdown %span.input-group-addon from - = text_field_tag :from, params[:from], class: "form-control", required: true + = dropdown_toggle h(params[:from].presence || ''), { toggle: "dropdown", refs_url: refs_namespace_project_path(@project.namespace, @project), field_name: 'from', selected: params[:from] }, { toggle_class: "js-project-refs-dropdown js-compare-dropdown" } + = render "ref_dropdown" = "..." .form-group - .input-group.inline-input-group + = hidden_field_tag :to, params[:to] + .input-group.inline-input-group.compare-input-group.dropdown %span.input-group-addon to - = text_field_tag :to, params[:to], class: "form-control", required: true + = dropdown_toggle h(params[:from].presence || ''), { toggle: "dropdown", refs_url: refs_namespace_project_path(@project.namespace, @project), field_name: 'to', selected: params[:to] }, { toggle_class: "js-project-refs-dropdown js-compare-dropdown" } + = render "ref_dropdown"   = button_tag "Compare", class: "btn btn-create commits-compare-btn" - if @merge_request.present? @@ -19,11 +23,3 @@ = link_to create_mr_path, class: 'prepend-left-10 btn' do = icon("plus") Create Merge Request - -:javascript - var availableTags = #{@project.repository.ref_names.to_json}; - - $("#from, #to").autocomplete({ - source: availableTags, - minLength: 1 - }); diff --git a/app/views/projects/compare/_ref_dropdown.html.haml b/app/views/projects/compare/_ref_dropdown.html.haml new file mode 100644 index 00000000000..30340db469a --- /dev/null +++ b/app/views/projects/compare/_ref_dropdown.html.haml @@ -0,0 +1,5 @@ +.dropdown-menu.dropdown-menu-selectable + = dropdown_title "Switch branch/tag" + = dropdown_filter "Search branches and tags" + = dropdown_content + = dropdown_loading diff --git a/app/views/shared/_ref_switcher.html.haml b/app/views/shared/_ref_switcher.html.haml index ea7162d4d63..73e805ffea4 100644 --- a/app/views/shared/_ref_switcher.html.haml +++ b/app/views/shared/_ref_switcher.html.haml @@ -6,7 +6,7 @@ - @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_namespace_project_path(@project.namespace, @project) }, { toggle_class: "js-project-refs-dropdown" } + = dropdown_toggle dropdown_toggle_text, { toggle: "dropdown", selected: dropdown_toggle_text, field_name: 'ref', ref: @ref, refs_url: refs_namespace_project_path(@project.namespace, @project) }, { toggle_class: "js-project-refs-dropdown" } .dropdown-menu.dropdown-menu-selectable{ class: ("dropdown-menu-align-right" if local_assigns[:align_right]) } = dropdown_title "Switch branch/tag" = dropdown_filter "Search branches and tags" From 8b9a4963a4f3a9e02f77ace387d25c8ff39d937d Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 24 Jun 2016 12:29:42 +0100 Subject: [PATCH 058/335] Updated dropdowns to use field instead Allows a bit more flexibilty and keeps the current functionality --- .../compare_autocomplete.js.coffee | 41 +++++++++++++++++++ app/assets/javascripts/dispatcher.js.coffee | 2 + app/assets/javascripts/gl_dropdown.js.coffee | 19 +++++++-- app/assets/javascripts/project.js.coffee | 5 +-- .../stylesheets/framework/dropdowns.scss | 11 ++--- app/assets/stylesheets/pages/projects.scss | 14 +------ app/views/projects/compare/_form.html.haml | 18 ++++---- .../projects/compare/_ref_dropdown.html.haml | 3 +- app/views/shared/_ref_switcher.html.haml | 2 +- 9 files changed, 75 insertions(+), 40 deletions(-) create mode 100644 app/assets/javascripts/compare_autocomplete.js.coffee diff --git a/app/assets/javascripts/compare_autocomplete.js.coffee b/app/assets/javascripts/compare_autocomplete.js.coffee new file mode 100644 index 00000000000..7ad9fd97637 --- /dev/null +++ b/app/assets/javascripts/compare_autocomplete.js.coffee @@ -0,0 +1,41 @@ +class @CompareAutocomplete + constructor: -> + @initDropdown() + + initDropdown: -> + $('.js-compare-dropdown').each -> + $dropdown = $(@) + selected = $dropdown.data('selected') + + $dropdown.glDropdown( + data: (term, callback) -> + $.ajax( + url: $dropdown.data('refs-url') + data: + ref: $dropdown.data('ref') + ).done (refs) -> + callback(refs) + selectable: true + filterable: true + filterByText: true + fieldName: $dropdown.attr('name') + filterInput: 'input[type="text"]' + renderRow: (ref) -> + if ref.header? + $('
  • ') + .addClass('dropdown-header') + .text(ref.header) + else + link = $('') + .attr('href', '#') + .addClass(if ref is selected then 'is-active' else '') + .text(ref) + .attr('data-ref', escape(ref)) + + $('
  • ') + .append(link) + id: (obj, $el) -> + $el.attr('data-ref') + toggleLabel: (obj, $el) -> + $el.text().trim() + ) diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index a39df421832..c8db27759ad 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -138,6 +138,8 @@ class Dispatcher new Project() new ProjectAvatar() switch path[1] + when 'compare' + new CompareAutocomplete() when 'edit' shortcut_handler = new ShortcutsNavigation() new ProjectNew() diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 1c65e833d47..5ffacf9a184 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -456,6 +456,8 @@ class GitLabDropdown rowClicked: (el) -> fieldName = @options.fieldName + isInput = $(@el).is('input') + if @renderedData groupName = el.data('group') if groupName @@ -466,10 +468,19 @@ class GitLabDropdown selectedObject = @renderedData[selectedIndex] value = if @options.id then @options.id(selectedObject, el) else selectedObject.id - field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']") + + if isInput + field = $(@el) + else + field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']") + if el.hasClass(ACTIVE_CLASS) el.removeClass(ACTIVE_CLASS) - field.remove() + + if isInput + field.val('') + else + field.remove() # Toggle the dropdown label if @options.toggleLabel @@ -490,7 +501,9 @@ class GitLabDropdown else if not @options.multiSelect or el.hasClass('dropdown-clear-active') @dropdown.find(".#{ACTIVE_CLASS}").removeClass ACTIVE_CLASS - @dropdown.parent().find("input[name='#{fieldName}']").remove() + + unless isInput + @dropdown.parent().find("input[name='#{fieldName}']").remove() if !value? field.remove() diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee index 01b08103dcb..3288c801388 100644 --- a/app/assets/javascripts/project.js.coffee +++ b/app/assets/javascripts/project.js.coffee @@ -67,7 +67,7 @@ class @Project selectable: true filterable: true filterByText: true - fieldName: $dropdown.data('field-name') + fieldName: 'ref' renderRow: (ref) -> if ref.header? $('
  • ') @@ -87,6 +87,5 @@ class @Project toggleLabel: (obj, $el) -> $el.text().trim() clicked: (e) -> - unless $dropdown.hasClass('js-compare-dropdown') - $dropdown.closest('form').submit() + $dropdown.closest('form').submit() ) diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index f4edafb2560..d4e900f80ef 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -48,6 +48,9 @@ border: 1px solid $dropdown-toggle-border-color; border-radius: $border-radius-base; outline: 0; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; .fa { position: absolute; @@ -58,14 +61,6 @@ font-size: 10px; } - .dropdown-toggle-text { - display: block; - min-height: 19px; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - } - &:hover, { border-color: $dropdown-toggle-hover-border-color; diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 4e722542fc6..9c73739fd3d 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -633,19 +633,7 @@ pre.light-well { } } -.compare-input-group { - &.input-group .input-group-addon { - @media (min-width: $screen-sm-min) { - width: 1%; - } - } - - .dropdown-menu-toggle { - width: 100%; - border-top-left-radius: 0; - border-bottom-left-radius: 0; - } - +.compare-form-group { .dropdown-menu { width: 300px; } diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml index ea9e99ac518..af09b3418ea 100644 --- a/app/views/projects/compare/_form.html.haml +++ b/app/views/projects/compare/_form.html.haml @@ -2,19 +2,17 @@ .clearfix - if params[:to] && params[:from] = link_to 'switch', {from: params[:to], to: params[:from]}, {class: 'commits-compare-switch has-tooltip', title: 'Switch base of comparison'} - .form-group - = hidden_field_tag :from, params[:from] - .input-group.inline-input-group.compare-input-group.dropdown + .form-group.dropdown.compare-form-group.js-compare-from-dropdown + .input-group.inline-input-group %span.input-group-addon from - = dropdown_toggle h(params[:from].presence || ''), { toggle: "dropdown", refs_url: refs_namespace_project_path(@project.namespace, @project), field_name: 'from', selected: params[:from] }, { toggle_class: "js-project-refs-dropdown js-compare-dropdown" } - = render "ref_dropdown" + = text_field_tag :from, params[:from], class: "form-control js-compare-dropdown", required: true, data: { refs_url: refs_namespace_project_path(@project.namespace, @project), toggle: "dropdown", target: ".js-compare-from-dropdown", selected: params[:from].presence } + = render "ref_dropdown" = "..." - .form-group - = hidden_field_tag :to, params[:to] - .input-group.inline-input-group.compare-input-group.dropdown + .form-group.dropdown.compare-form-group.js-compare-to-dropdown + .input-group.inline-input-group %span.input-group-addon to - = dropdown_toggle h(params[:from].presence || ''), { toggle: "dropdown", refs_url: refs_namespace_project_path(@project.namespace, @project), field_name: 'to', selected: params[:to] }, { toggle_class: "js-project-refs-dropdown js-compare-dropdown" } - = render "ref_dropdown" + = text_field_tag :to, params[:to], class: "form-control js-compare-dropdown", required: true, data: { refs_url: refs_namespace_project_path(@project.namespace, @project), toggle: "dropdown", target: ".js-compare-to-dropdown", selected: params[:to].presence } + = render "ref_dropdown"   = button_tag "Compare", class: "btn btn-create commits-compare-btn" - if @merge_request.present? diff --git a/app/views/projects/compare/_ref_dropdown.html.haml b/app/views/projects/compare/_ref_dropdown.html.haml index 30340db469a..c604c6d0135 100644 --- a/app/views/projects/compare/_ref_dropdown.html.haml +++ b/app/views/projects/compare/_ref_dropdown.html.haml @@ -1,5 +1,4 @@ .dropdown-menu.dropdown-menu-selectable - = dropdown_title "Switch branch/tag" - = dropdown_filter "Search branches and tags" + = dropdown_title "Select branch/tag" = dropdown_content = dropdown_loading diff --git a/app/views/shared/_ref_switcher.html.haml b/app/views/shared/_ref_switcher.html.haml index 73e805ffea4..ea7162d4d63 100644 --- a/app/views/shared/_ref_switcher.html.haml +++ b/app/views/shared/_ref_switcher.html.haml @@ -6,7 +6,7 @@ - @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, field_name: 'ref', ref: @ref, refs_url: refs_namespace_project_path(@project.namespace, @project) }, { toggle_class: "js-project-refs-dropdown" } + = dropdown_toggle dropdown_toggle_text, { toggle: "dropdown", selected: dropdown_toggle_text, ref: @ref, refs_url: refs_namespace_project_path(@project.namespace, @project) }, { toggle_class: "js-project-refs-dropdown" } .dropdown-menu.dropdown-menu-selectable{ class: ("dropdown-menu-align-right" if local_assigns[:align_right]) } = dropdown_title "Switch branch/tag" = dropdown_filter "Search branches and tags" From d7450946a75a5e344bf996542114ab0499f6a7fa Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 29 Jun 2016 11:24:58 +0100 Subject: [PATCH 059/335] Added tests for compare dropdowns CHANGELOG --- CHANGELOG | 2 ++ spec/features/compare_spec.rb | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 spec/features/compare_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 09f2c44e02c..325db5b565d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,8 @@ v 8.10.0 (unreleased) - Fix issue, preventing users w/o push access to sort tags !5105 (redetection) - Add Spring EmojiOne updates. - Fix viewing notification settings when a project is pending deletion + - Updated compare dropdown menus to use GL dropdown + - Eager load award emoji on notes - Fix pagination when sorting by columns with lots of ties (like priority) - Updated project header design - Exclude email check from the standard health check diff --git a/spec/features/compare_spec.rb b/spec/features/compare_spec.rb new file mode 100644 index 00000000000..faffe314912 --- /dev/null +++ b/spec/features/compare_spec.rb @@ -0,0 +1,42 @@ +require "spec_helper" + +describe "Compare", js: true do + let(:user) { create(:user) } + let(:project) { create(:project) } + + before do + project.team << [user, :master] + login_as user + visit namespace_project_compare_index_path(project.namespace, project, from: "master", to: "master") + end + + describe "branches" do + it "should pre-populate fields" do + expect(page.find_field("from").value).to eq("master") + end + + it "should compare branches" do + fill_in "from", with: "mast" + find("#from").click + + click_link "feature" + expect(page.find_field("from").value).to eq("feature") + + click_button "Compare" + expect(page).to have_content "Commits" + end + end + + describe "tags" do + it "should compare tags" do + fill_in "from", with: "v1.0" + find("#from").click + + click_link "v1.0.0" + expect(page.find_field("from").value).to eq("v1.0.0") + + click_button "Compare" + expect(page).to have_content "Commits" + end + end +end From bd888e135d5cd9d7e9ffb6c3a79fc2ce2f56770d Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 7 Jul 2016 11:25:04 +0100 Subject: [PATCH 060/335] Fixed submit button not enabling Fixed tests --- app/assets/javascripts/gl_dropdown.js.coffee | 4 +++- spec/features/compare_spec.rb | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 5ffacf9a184..1b0d0db8954 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -518,7 +518,9 @@ class GitLabDropdown if !field.length and fieldName @addInput(fieldName, value) else - field.val value + field + .val value + .trigger 'change' return selectedObject diff --git a/spec/features/compare_spec.rb b/spec/features/compare_spec.rb index faffe314912..c62556948e0 100644 --- a/spec/features/compare_spec.rb +++ b/spec/features/compare_spec.rb @@ -16,7 +16,7 @@ describe "Compare", js: true do end it "should compare branches" do - fill_in "from", with: "mast" + fill_in "from", with: "fea" find("#from").click click_link "feature" From e462e122784f40550c53224af5a58b201ed1fd8f Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Fri, 8 Jul 2016 18:11:47 +0100 Subject: [PATCH 061/335] Tidy up spec action names --- .../projects/commit_controller_spec.rb | 10 +++++----- .../projects/compare_controller_spec.rb | 2 +- .../projects/merge_requests_controller_spec.rb | 16 ++++++++-------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb index 9679b4f849f..472c4904919 100644 --- a/spec/controllers/projects/commit_controller_spec.rb +++ b/spec/controllers/projects/commit_controller_spec.rb @@ -12,7 +12,7 @@ describe Projects::CommitController do project.team << [user, :master] end - describe 'GET #show' do + describe 'GET show' do render_views def go(extra_params = {}) @@ -141,7 +141,7 @@ describe Projects::CommitController do end end - describe "#branches" do + describe "GET branches" do it "contains branch and tags information" do get(:branches, namespace_id: project.namespace.to_param, @@ -153,7 +153,7 @@ describe Projects::CommitController do end end - describe '#revert' do + describe 'POST revert' do context 'when target branch is not provided' do it 'should render the 404 page' do post(:revert, @@ -202,7 +202,7 @@ describe Projects::CommitController do end end - describe '#cherry_pick' do + describe 'POST cherry_pick' do context 'when target branch is not provided' do it 'should render the 404 page' do post(:cherry_pick, @@ -251,7 +251,7 @@ describe Projects::CommitController do end end - describe 'GET #diff_for_path' do + describe 'GET diff_for_path' do def diff_for_path(extra_params = {}) params = { namespace_id: project.namespace.to_param, diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb index 40a068a87bb..1dd144a7b72 100644 --- a/spec/controllers/projects/compare_controller_spec.rb +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -65,7 +65,7 @@ describe Projects::CompareController do end end - describe 'GET #diff_for_path' do + describe 'GET diff_for_path' do def diff_for_path(extra_params = {}) params = { namespace_id: project.namespace.to_param, diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 1b4c4dcd1e5..ff160f51329 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -10,7 +10,7 @@ describe Projects::MergeRequestsController do project.team << [user, :master] end - describe '#new' do + describe 'GET new' do context 'merge request that removes a submodule' do render_views @@ -34,7 +34,7 @@ describe Projects::MergeRequestsController do end end - describe "#show" do + describe "GET show" do shared_examples "export merge as" do |format| it "should generally work" do get(:show, @@ -108,7 +108,7 @@ describe Projects::MergeRequestsController do end end - describe 'GET #index' do + describe 'GET index' do def get_merge_requests get :index, namespace_id: project.namespace.to_param, @@ -140,7 +140,7 @@ describe Projects::MergeRequestsController do end end - describe 'PUT #update' do + describe 'PUT update' do context 'there is no source project' do let(:project) { create(:project) } let(:fork_project) { create(:forked_project_with_submodules) } @@ -168,7 +168,7 @@ describe Projects::MergeRequestsController do end end - describe 'POST #merge' do + describe 'POST merge' do let(:base_params) do { namespace_id: project.namespace.path, @@ -266,7 +266,7 @@ describe Projects::MergeRequestsController do end end - describe "DELETE #destroy" do + describe "DELETE destroy" do it "denies access to users unless they're admin or project owner" do delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: merge_request.iid @@ -289,7 +289,7 @@ describe Projects::MergeRequestsController do end end - describe 'GET #diffs' do + describe 'GET diffs' do def go(extra_params = {}) params = { namespace_id: project.namespace.to_param, @@ -367,7 +367,7 @@ describe Projects::MergeRequestsController do end end - describe 'GET #diff_for_path' do + describe 'GET diff_for_path' do def diff_for_path(extra_params = {}) params = { namespace_id: project.namespace.to_param, From 454e6c7b8c227f97d3158564273504067be05eab Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 9 Jul 2016 14:48:36 +0300 Subject: [PATCH 062/335] Add side shadow for unpinned sidebar Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/sidebar.scss | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 188823054fd..78eefa538c3 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -3,6 +3,12 @@ padding-bottom: 25px; transition: padding $sidebar-transition-duration; + &.page-sidebar-pinned { + .sidebar-wrapper { + @include box-shadow(none); + } + } + .sidebar-wrapper { position: fixed; top: 0; @@ -11,6 +17,7 @@ height: 100%; overflow: hidden; transition: width $sidebar-transition-duration; + @include box-shadow(2px 0px 16px 0px #bbb); } } From f52e83a5c09badbfa713875184d2c52797f98f42 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 9 Jul 2016 15:05:05 +0300 Subject: [PATCH 063/335] Make color that highligh today issues more lightweight Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/pages/issues.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 4e35ca329e4..05e1713d64a 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -63,8 +63,8 @@ form.edit-issue { .merge-request, .issue { &.today { - background: #efe; - border-color: #cec; + background: #F8FEEF; + border-color: #E1E8D5; } &.closed { From b684517907c8783320a58a541b13e6efd77c36cc Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 11 Jul 2016 08:51:18 +0100 Subject: [PATCH 064/335] Moved merge request button visibility out of issue_helper --- app/helpers/issues_helper.rb | 2 +- app/helpers/merge_requests_helper.rb | 4 ++++ .../projects/merge_requests/show/_mr_title.html.haml | 8 ++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 46334f939d2..72bd1fbbd81 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -102,7 +102,7 @@ module IssuesHelper end def issue_button_visibility(issue, closed) - return 'hidden' if issue.closed? == closed || (issue.try(:merged?) == closed && !issue.closed?) + return 'hidden' if issue.closed? == closed end def merge_requests_sentence(merge_requests) diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index 1dd07a2a220..631a0bb758d 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -92,4 +92,8 @@ module MergeRequestsHelper ["#{source_path}:#{source_branch}", "#{target_path}:#{target_branch}"] end end + + def merge_request_button_visibility(merge_request, closed) + return 'hidden' if merge_request.closed? == closed || (merge_request.merged? == closed && !merge_request.closed?) + end end diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index 5bf5210aeab..b24bdf22ceb 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -19,13 +19,13 @@ Options .dropdown-menu.dropdown-menu-align-right.hidden-lg %ul - %li{ class: issue_button_visibility(@merge_request, true) } + %li{ class: merge_request_button_visibility(@merge_request, true) } = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, title: 'Close merge request' - %li{ class: issue_button_visibility(@merge_request, false) } + %li{ class: merge_request_button_visibility(@merge_request, false) } = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'reopen-mr-link', title: 'Reopen merge request' %li = link_to 'Edit', edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'issuable-edit' - = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: "hidden-xs hidden-sm btn btn-grouped btn-close #{issue_button_visibility(@merge_request, true)}", title: 'Close merge request' - = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "hidden-xs hidden-sm btn btn-grouped btn-reopen reopen-mr-link #{issue_button_visibility(@merge_request, false)}", title: 'Reopen merge request' + = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: "hidden-xs hidden-sm btn btn-grouped btn-close #{merge_request_button_visibility(@merge_request, true)}", title: 'Close merge request' + = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "hidden-xs hidden-sm btn btn-grouped btn-reopen reopen-mr-link #{merge_request_button_visibility(@merge_request, false)}", title: 'Reopen merge request' = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "hidden-xs hidden-sm btn btn-grouped issuable-edit" do Edit From 5266ae87c43a6760600e397257f9791d950dbe15 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Fri, 8 Jul 2016 22:50:06 +0100 Subject: [PATCH 065/335] Support renames in diff_for_path actions --- app/helpers/diff_helper.rb | 8 +++- app/models/merge_request_diff.rb | 5 ++- app/views/projects/diffs/_content.html.haml | 2 +- config/routes.rb | 8 ++-- .../projects/commit_controller_spec.rb | 10 ++--- .../projects/compare_controller_spec.rb | 12 +++--- .../merge_requests_controller_spec.rb | 24 ++++++------ .../expand_collapse_diffs_spec.rb | 37 +++++++++++++++++-- spec/models/merge_request_diff_spec.rb | 6 +-- spec/support/test_env.rb | 28 +++++++------- 10 files changed, 89 insertions(+), 51 deletions(-) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 04490226e50..e29f665baec 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -24,7 +24,11 @@ module DiffHelper def diff_options default_options = Commit.max_diff_options - default_options[:paths] = [params[:path]] if params[:path] + + if action_name == 'diff_for_path' + default_options[:paths] = params.values_at(:old_path, :new_path) + end + default_options.merge(ignore_whitespace_change: hide_whitespace?) end @@ -88,7 +92,7 @@ module DiffHelper def commit_for_diff(diff_file) return diff_file.content_commit if diff_file.content_commit - + if diff_file.deleted_file @base_commit || @commit.parent || @commit else diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 7e22491d0a3..d54369c3483 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -47,7 +47,7 @@ class MergeRequestDiff < ActiveRecord::Base end else @diffs ||= {} - @diffs[options[:paths]] ||= load_diffs(st_diffs, options) + @diffs[options] ||= load_diffs(st_diffs, options) end end @@ -146,8 +146,9 @@ class MergeRequestDiff < ActiveRecord::Base def load_diffs(raw, options) if raw.respond_to?(:each) if options[:paths] + old_path, new_path = options[:paths] raw = raw.select do |diff| - options[:paths].include?(diff[:new_path]) + old_path == diff[:old_path] && new_path == diff[:new_path] end end diff --git a/app/views/projects/diffs/_content.html.haml b/app/views/projects/diffs/_content.html.haml index bfcd3ee9132..0c0424edffd 100644 --- a/app/views/projects/diffs/_content.html.haml +++ b/app/views/projects/diffs/_content.html.haml @@ -10,7 +10,7 @@ .nothing-here-block This diff was suppressed by a .gitattributes entry. - elsif diff_file.diff_lines.length > 0 - if diff_file.collapsed_by_default? && !expand_all_diffs? - - url = url_for(params.merge(action: :diff_for_path, path: diff_file.file_path, format: nil)) + - url = url_for(params.merge(action: :diff_for_path, old_path: diff_file.old_path, new_path: diff_file.new_path)) .nothing-here-block.diff-collapsed{data: { diff_for_path: url } } This diff is collapsed. Click to expand it. - elsif diff_view == 'parallel' diff --git a/config/routes.rb b/config/routes.rb index f31f8171993..b4f83c58bbd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -615,13 +615,13 @@ Rails.application.routes.draw do post :retry_builds post :revert post :cherry_pick - get '/diffs/*path', action: :diff_for_path, constraints: { format: false } + get :diff_for_path end end resources :compare, only: [:index, :create] do collection do - get '/diffs/*path', action: :diff_for_path, constraints: { format: false } + get :diff_for_path end end @@ -711,14 +711,14 @@ Rails.application.routes.draw do post :toggle_subscription post :toggle_award_emoji post :remove_wip - get '/diffs/*path', action: :diff_for_path, constraints: { format: false } + get :diff_for_path end collection do get :branch_from get :branch_to get :update_branches - get '/diffs/*path', action: :diff_for_path, constraints: { format: false } + get :diff_for_path end end diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb index 472c4904919..3001d32e719 100644 --- a/spec/controllers/projects/commit_controller_spec.rb +++ b/spec/controllers/projects/commit_controller_spec.rb @@ -267,7 +267,7 @@ describe Projects::CommitController do context 'when the user has access to the project' do context 'when the path exists in the diff' do it 'enables diff notes' do - diff_for_path(id: commit.id, path: existing_path) + diff_for_path(id: commit.id, old_path: existing_path, new_path: existing_path) expect(assigns(:diff_notes_disabled)).to be_falsey expect(assigns(:comments_target)).to eq(noteable_type: 'Commit', @@ -280,12 +280,12 @@ describe Projects::CommitController do meth.call(diffs, diff_refs, project) end - diff_for_path(id: commit.id, path: existing_path) + diff_for_path(id: commit.id, old_path: existing_path, new_path: existing_path) end end context 'when the path does not exist in the diff' do - before { diff_for_path(id: commit.id, path: existing_path.succ) } + before { diff_for_path(id: commit.id, old_path: existing_path.succ, new_path: existing_path.succ) } it 'returns a 404' do expect(response).to have_http_status(404) @@ -296,7 +296,7 @@ describe Projects::CommitController do context 'when the user does not have access to the project' do before do project.team.truncate - diff_for_path(id: commit.id, path: existing_path) + diff_for_path(id: commit.id, old_path: existing_path, new_path: existing_path) end it 'returns a 404' do @@ -306,7 +306,7 @@ describe Projects::CommitController do end context 'when the commit does not exist' do - before { diff_for_path(id: commit.id.succ, path: existing_path) } + before { diff_for_path(id: commit.id.succ, old_path: existing_path, new_path: existing_path) } it 'returns a 404' do expect(response).to have_http_status(404) diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb index 1dd144a7b72..4058d5e2453 100644 --- a/spec/controllers/projects/compare_controller_spec.rb +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -81,7 +81,7 @@ describe Projects::CompareController do context 'when the user has access to the project' do context 'when the path exists in the diff' do it 'disables diff notes' do - diff_for_path(from: ref_from, to: ref_to, path: existing_path) + diff_for_path(from: ref_from, to: ref_to, old_path: existing_path, new_path: existing_path) expect(assigns(:diff_notes_disabled)).to be_truthy end @@ -92,12 +92,12 @@ describe Projects::CompareController do meth.call(diffs, diff_refs, project) end - diff_for_path(from: ref_from, to: ref_to, path: existing_path) + diff_for_path(from: ref_from, to: ref_to, old_path: existing_path, new_path: existing_path) end end context 'when the path does not exist in the diff' do - before { diff_for_path(from: ref_from, to: ref_to, path: existing_path.succ) } + before { diff_for_path(from: ref_from, to: ref_to, old_path: existing_path.succ, new_path: existing_path.succ) } it 'returns a 404' do expect(response).to have_http_status(404) @@ -108,7 +108,7 @@ describe Projects::CompareController do context 'when the user does not have access to the project' do before do project.team.truncate - diff_for_path(from: ref_from, to: ref_to, path: existing_path) + diff_for_path(from: ref_from, to: ref_to, old_path: existing_path, new_path: existing_path) end it 'returns a 404' do @@ -118,7 +118,7 @@ describe Projects::CompareController do end context 'when the from ref does not exist' do - before { diff_for_path(from: ref_from.succ, to: ref_to, path: existing_path) } + before { diff_for_path(from: ref_from.succ, to: ref_to, old_path: existing_path, new_path: existing_path) } it 'returns a 404' do expect(response).to have_http_status(404) @@ -126,7 +126,7 @@ describe Projects::CompareController do end context 'when the to ref does not exist' do - before { diff_for_path(from: ref_from, to: ref_to.succ, path: existing_path) } + before { diff_for_path(from: ref_from, to: ref_to.succ, old_path: existing_path, new_path: existing_path) } it 'returns a 404' do expect(response).to have_http_status(404) diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index ff160f51329..210085e3b1a 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -384,7 +384,7 @@ describe Projects::MergeRequestsController do context 'when the user can view the merge request' do context 'when the path exists in the diff' do it 'enables diff notes' do - diff_for_path(id: merge_request.iid, path: existing_path) + diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path) expect(assigns(:diff_notes_disabled)).to be_falsey expect(assigns(:comments_target)).to eq(noteable_type: 'MergeRequest', @@ -397,12 +397,12 @@ describe Projects::MergeRequestsController do meth.call(diffs, diff_refs, project) end - diff_for_path(id: merge_request.iid, path: existing_path) + diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path) end end context 'when the path does not exist in the diff' do - before { diff_for_path(id: merge_request.iid, path: 'files/ruby/nopen.rb') } + before { diff_for_path(id: merge_request.iid, old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb') } it 'returns a 404' do expect(response).to have_http_status(404) @@ -413,7 +413,7 @@ describe Projects::MergeRequestsController do context 'when the user cannot view the merge request' do before do project.team.truncate - diff_for_path(id: merge_request.iid, path: existing_path) + diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path) end it 'returns a 404' do @@ -423,7 +423,7 @@ describe Projects::MergeRequestsController do end context 'when the merge request does not exist' do - before { diff_for_path(id: merge_request.iid.succ, path: existing_path) } + before { diff_for_path(id: merge_request.iid.succ, old_path: existing_path, new_path: existing_path) } it 'returns a 404' do expect(response).to have_http_status(404) @@ -435,7 +435,7 @@ describe Projects::MergeRequestsController do before do other_project.team << [user, :master] - diff_for_path(id: merge_request.iid, path: existing_path, project_id: other_project.to_param) + diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path, project_id: other_project.to_param) end it 'returns a 404' do @@ -449,7 +449,7 @@ describe Projects::MergeRequestsController do context 'when both branches are in the same project' do it 'disables diff notes' do - diff_for_path(path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' }) + diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' }) expect(assigns(:diff_notes_disabled)).to be_truthy end @@ -460,7 +460,7 @@ describe Projects::MergeRequestsController do meth.call(diffs, diff_refs, project) end - diff_for_path(path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' }) + diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' }) end end @@ -471,7 +471,7 @@ describe Projects::MergeRequestsController do context 'when the path exists in the diff' do it 'disables diff notes' do - diff_for_path(path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' }) + diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' }) expect(assigns(:diff_notes_disabled)).to be_truthy end @@ -482,12 +482,12 @@ describe Projects::MergeRequestsController do meth.call(diffs, diff_refs, project) end - diff_for_path(path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' }) + diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' }) end end context 'when the path does not exist in the diff' do - before { diff_for_path(path: 'files/ruby/nopen.rb', merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' }) } + before { diff_for_path(old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb', merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' }) } it 'returns a 404' do expect(response).to have_http_status(404) @@ -497,7 +497,7 @@ describe Projects::MergeRequestsController do end end - describe 'GET #commits' do + describe 'GET commits' do def go(format: 'html') get :commits, namespace_id: project.namespace.to_param, diff --git a/spec/features/merge_requests/expand_collapse_diffs_spec.rb b/spec/features/merge_requests/expand_collapse_diffs_spec.rb index f9c89c4ad96..7a05bb47979 100644 --- a/spec/features/merge_requests/expand_collapse_diffs_spec.rb +++ b/spec/features/merge_requests/expand_collapse_diffs_spec.rb @@ -5,7 +5,7 @@ feature 'Expand and collapse diffs', js: true, feature: true do before do login_as :admin - merge_request = create(:merge_request, source_branch: 'expand-collapse-diffs', target_branch: 'master') + merge_request = create(:merge_request, target_branch: 'expand-collapse-diffs-start', source_branch: 'expand-collapse-diffs') project = merge_request.source_project # Ensure that undiffable.md is in .gitattributes @@ -21,7 +21,12 @@ feature 'Expand and collapse diffs', js: true, feature: true do # Use define_method instead of let (which is memoized) so that this just works across a # reload. # - ['small_diff.md', 'large_diff.md', 'undiffable.md', 'too_large.md', 'too_large_image.jpg'].each do |file| + files = [ + 'small_diff.md', 'large_diff.md', 'large_diff_renamed.md', 'undiffable.md', + 'too_large.md', 'too_large_image.jpg' + ] + + files.each do |file| define_method(file.split('.').first) { file_container(file) } end @@ -31,11 +36,18 @@ feature 'Expand and collapse diffs', js: true, feature: true do expect(small_diff).not_to have_selector('.nothing-here-block') end - it 'collapses larges diffs by default' do + it 'collapses large diffs by default' do expect(large_diff).not_to have_selector('.code') expect(large_diff).to have_selector('.nothing-here-block') end + it 'collapses large diffs for renamed files by default' do + expect(large_diff_renamed).not_to have_selector('.code') + expect(large_diff_renamed).to have_selector('.nothing-here-block') + expect(large_diff_renamed).to have_selector('.file-title .deletion') + expect(large_diff_renamed).to have_selector('.file-title .addition') + end + it 'shows non-renderable diffs as such immediately, regardless of their size' do expect(undiffable).not_to have_selector('.code') expect(undiffable).to have_selector('.nothing-here-block') @@ -53,6 +65,25 @@ feature 'Expand and collapse diffs', js: true, feature: true do expect(too_large_image).to have_selector('.image') end + context 'expanding a diff for a renamed file' do + before do + large_diff_renamed.find('.nothing-here-block').click + wait_for_ajax + end + + it 'shows the old content' do + old_line = large_diff_renamed.find('.line_content.old') + + expect(old_line).to have_content('four copies') + end + + it 'shows the new content' do + new_line = large_diff_renamed.find('.line_content.new', match: :prefer_exact) + + expect(new_line).to have_content('six copies') + end + end + context 'expanding a large diff' do before do click_link('large_diff.md') diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index 3f5763b6408..9a637c94fbe 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -30,10 +30,10 @@ describe MergeRequestDiff, models: true do end context 'when the :paths option is set' do - let(:diffs) { mr_diff.diffs(paths: ['.gitignore', 'files/ruby/popen.rb', 'files/ruby/string.rb']) } + let(:diffs) { mr_diff.diffs(paths: ['files/ruby/popen.rb', 'files/ruby/popen.rb']) } - it 'only returns diffs that match the paths given' do - expect(diffs.map(&:new_path)).to contain_exactly('.gitignore', 'files/ruby/popen.rb') + it 'only returns diffs that match the (old path, new path) given' do + expect(diffs.map(&:new_path)).to contain_exactly('files/ruby/popen.rb') end it 'uses the diffs from the DB' do diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 6b99b0f24cb..311610c9911 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -5,19 +5,21 @@ module TestEnv # When developing the seed repository, comment out the branch you will modify. BRANCH_SHA = { - 'empty-branch' => '7efb185', - 'flatten-dir' => 'e56497b', - 'feature' => '0b4bc9a', - 'feature_conflict' => 'bb5206f', - 'fix' => '48f0be4', - 'improve/awesome' => '5937ac0', - 'markdown' => '0ed8c6c', - 'lfs' => 'be93687', - 'master' => '5937ac0', - "'test'" => 'e56497b', - 'orphaned-branch' => '45127a9', - 'binary-encoding' => '7b1cf43', - 'gitattributes' => '5a62481', + 'empty-branch' => '7efb185', + 'flatten-dir' => 'e56497b', + 'feature' => '0b4bc9a', + 'feature_conflict' => 'bb5206f', + 'fix' => '48f0be4', + 'improve/awesome' => '5937ac0', + 'markdown' => '0ed8c6c', + 'lfs' => 'be93687', + 'master' => '5937ac0', + "'test'" => 'e56497b', + 'orphaned-branch' => '45127a9', + 'binary-encoding' => '7b1cf43', + 'gitattributes' => '5a62481', + 'expand-collapse-diffs-start' => '65b04e4', + 'expand-collapse-diffs' => '865e6d5' } # gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily From 93ab68607922e0bd0e22c40528a9d58fc50f50cd Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Mon, 11 Jul 2016 10:58:01 +0100 Subject: [PATCH 066/335] Fix feature specs on CI MySQL's text column isn't big enough for the diffs in the expand-collapse-diffs branch. --- .../expand_collapse_diffs_spec.rb | 14 ++++----- spec/support/test_env.rb | 29 +++++++++---------- 2 files changed, 21 insertions(+), 22 deletions(-) rename spec/features/{merge_requests => }/expand_collapse_diffs_spec.rb (92%) diff --git a/spec/features/merge_requests/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb similarity index 92% rename from spec/features/merge_requests/expand_collapse_diffs_spec.rb rename to spec/features/expand_collapse_diffs_spec.rb index 7a05bb47979..7cff196c8d9 100644 --- a/spec/features/merge_requests/expand_collapse_diffs_spec.rb +++ b/spec/features/expand_collapse_diffs_spec.rb @@ -5,12 +5,12 @@ feature 'Expand and collapse diffs', js: true, feature: true do before do login_as :admin - merge_request = create(:merge_request, target_branch: 'expand-collapse-diffs-start', source_branch: 'expand-collapse-diffs') - project = merge_request.source_project + project = create(:project) + branch = 'expand-collapse-diffs' # Ensure that undiffable.md is in .gitattributes - project.repository.copy_gitattributes('expand-collapse-diffs') - visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request) + project.repository.copy_gitattributes(branch) + visit namespace_project_commit_path(project.namespace, project, project.commit(branch)) execute_script('window.ajaxUris = []; $(document).ajaxSend(function(event, xhr, settings) { ajaxUris.push(settings.url) });') end @@ -30,7 +30,7 @@ feature 'Expand and collapse diffs', js: true, feature: true do define_method(file.split('.').first) { file_container(file) } end - context 'visiting an existing merge request' do + context 'visiting a commit with collapsed diffs' do it 'shows small diffs immediately' do expect(small_diff).to have_selector('.code') expect(small_diff).not_to have_selector('.nothing-here-block') @@ -74,13 +74,13 @@ feature 'Expand and collapse diffs', js: true, feature: true do it 'shows the old content' do old_line = large_diff_renamed.find('.line_content.old') - expect(old_line).to have_content('four copies') + expect(old_line).to have_content('two copies') end it 'shows the new content' do new_line = large_diff_renamed.find('.line_content.new', match: :prefer_exact) - expect(new_line).to have_content('six copies') + expect(new_line).to have_content('three copies') end end diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 311610c9911..bb6c84262f6 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -5,21 +5,20 @@ module TestEnv # When developing the seed repository, comment out the branch you will modify. BRANCH_SHA = { - 'empty-branch' => '7efb185', - 'flatten-dir' => 'e56497b', - 'feature' => '0b4bc9a', - 'feature_conflict' => 'bb5206f', - 'fix' => '48f0be4', - 'improve/awesome' => '5937ac0', - 'markdown' => '0ed8c6c', - 'lfs' => 'be93687', - 'master' => '5937ac0', - "'test'" => 'e56497b', - 'orphaned-branch' => '45127a9', - 'binary-encoding' => '7b1cf43', - 'gitattributes' => '5a62481', - 'expand-collapse-diffs-start' => '65b04e4', - 'expand-collapse-diffs' => '865e6d5' + 'empty-branch' => '7efb185', + 'flatten-dir' => 'e56497b', + 'feature' => '0b4bc9a', + 'feature_conflict' => 'bb5206f', + 'fix' => '48f0be4', + 'improve/awesome' => '5937ac0', + 'markdown' => '0ed8c6c', + 'lfs' => 'be93687', + 'master' => '5937ac0', + "'test'" => 'e56497b', + 'orphaned-branch' => '45127a9', + 'binary-encoding' => '7b1cf43', + 'gitattributes' => '5a62481', + 'expand-collapse-diffs' => '4842455' } # gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily From d794c96adea80dfcb36e4b202123f0d051efeceb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Jul 2016 14:56:45 +0300 Subject: [PATCH 067/335] Lower case todya issue colors Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/pages/issues.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 05e1713d64a..0e4d8c140aa 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -63,8 +63,8 @@ form.edit-issue { .merge-request, .issue { &.today { - background: #F8FEEF; - border-color: #E1E8D5; + background: #f8feef; + border-color: #e1e8d5; } &.closed { From 8fa19571baa913a422aa8a7501e02c23c65e5402 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Jul 2016 14:58:58 +0300 Subject: [PATCH 068/335] Refactor box-shadow style for sidebar to satisfy css lint Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/sidebar.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 78eefa538c3..1a2220f3b40 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -17,7 +17,7 @@ height: 100%; overflow: hidden; transition: width $sidebar-transition-duration; - @include box-shadow(2px 0px 16px 0px #bbb); + @include box-shadow(2px 0 16px 0 #bbb); } } From 2b728ed3dabcced23370b39ce256a03cf30fe86d Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Mon, 11 Jul 2016 20:04:27 +0800 Subject: [PATCH 069/335] Just give regular 404, feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5094#note_12984211 --- app/controllers/projects/artifacts_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb index c6363999670..7241949393b 100644 --- a/app/controllers/projects/artifacts_controller.rb +++ b/app/controllers/projects/artifacts_controller.rb @@ -25,7 +25,7 @@ class Projects::ArtifactsController < Projects::ApplicationController if entry.exists? send_artifacts_entry(build, entry) else - render json: {}, status: 404 + render_404 end end From 1bfc2ed633b2086b547727acc4aa0abaaea7731f Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Mon, 11 Jul 2016 20:06:35 +0800 Subject: [PATCH 070/335] Just remove the prefix, feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5094#note_12987385 --- features/steps/project/builds/artifacts.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/steps/project/builds/artifacts.rb b/features/steps/project/builds/artifacts.rb index 4bc74688132..b4a32ed2e38 100644 --- a/features/steps/project/builds/artifacts.rb +++ b/features/steps/project/builds/artifacts.rb @@ -72,7 +72,8 @@ class Spinach::Features::ProjectBuildsArtifacts < Spinach::FeatureSteps expect(send_data).to start_with('artifacts-entry:') - params = JSON.parse(Base64.urlsafe_decode64(send_data[/(?<=:)(.+)/])) + base64_params = send_data.sub(/\Aartifacts\-entry:/, '') + params = JSON.parse(Base64.urlsafe_decode64(base64_params)) expect(params.keys).to eq(['Archive', 'Entry']) expect(params['Archive']).to end_with('build_artifacts.zip') From f2bf47f4dffacbb34ac3e4ed27f83176e29f9159 Mon Sep 17 00:00:00 2001 From: winniehell Date: Sat, 9 Jul 2016 03:06:12 +0200 Subject: [PATCH 071/335] Display tooltip for "Copy to Clipboard" button (!5164) --- CHANGELOG | 1 + app/assets/stylesheets/pages/commits.scss | 2 +- app/helpers/button_helper.rb | 22 +++---------------- app/views/projects/commits/_commit.html.haml | 2 +- .../show/_how_to_merge.html.haml | 6 ++--- 5 files changed, 9 insertions(+), 24 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3e4a10bb5a3..16a297af4a1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,7 @@ v 8.10.0 (unreleased) - Add Application Setting to configure default Repository Path for new projects - Wrap code blocks on Activies and Todos page. !4783 (winniehell) - Align flash messages with left side of page content !4959 (winniehell) + - Display tooltip for "Copy to Clipboard" button !5164 (winniehell) - Display last commit of deleted branch in push events !4699 (winniehell) - Escape file extension when parsing search results !5141 (winniehell) - Apply the trusted_proxies config to the rack request object for use with rack_attack diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 85bbf70e188..0298577c494 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -61,7 +61,7 @@ font-size: 0; } - .btn-transparent { + .btn-clipboard, .btn-transparent { padding-left: 0; padding-right: 0; } diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb index 0f097f86816..b478580978b 100644 --- a/app/helpers/button_helper.rb +++ b/app/helpers/button_helper.rb @@ -15,29 +15,13 @@ module ButtonHelper # # See http://clipboardjs.com/#usage def clipboard_button(data = {}) + data = { toggle: 'tooltip', placement: 'bottom', container: 'body' }.merge(data) content_tag :button, icon('clipboard'), class: "btn btn-clipboard", data: data, - type: :button - end - - # Output a "Copy to Clipboard" button with a custom CSS class - # - # data - Data attributes passed to `content_tag` - # css_class - Class passed to the `content_tag` - # - # Examples: - # - # # Define the target element - # clipboard_button_with_class({clipboard_target: "div#foo"}, css_class: "btn-clipboard") - # # => "" - def clipboard_button_with_class(data = {}, css_class: 'btn-clipboard') - content_tag :button, - icon('clipboard'), - class: "btn #{css_class}", - data: data, - type: :button + type: :button, + title: "Copy to Clipboard" end def http_clone_button(project, placement = 'right', append_link: true) diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index 929496f81d8..c8c7b858baa 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -25,7 +25,7 @@ .commit-actions.hidden-xs - if commit.status = render_commit_status(commit, cssclass: 'btn btn-transparent') - = clipboard_button_with_class({ clipboard_text: commit.id }, css_class: 'btn-transparent') + = clipboard_button(clipboard_text: commit.id) = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit-short-id btn btn-transparent" = link_to_browse_code(project, commit) diff --git a/app/views/projects/merge_requests/show/_how_to_merge.html.haml b/app/views/projects/merge_requests/show/_how_to_merge.html.haml index b3bea900d42..b727efaa6a6 100644 --- a/app/views/projects/merge_requests/show/_how_to_merge.html.haml +++ b/app/views/projects/merge_requests/show/_how_to_merge.html.haml @@ -8,7 +8,7 @@ %p %strong Step 1. Fetch and check out the branch for this merge request - = clipboard_button_with_class({clipboard_target: "pre#merge-info-1"}, css_class: "btn-clipboard") + = clipboard_button(clipboard_target: "pre#merge-info-1") %pre.dark#merge-info-1 - if @merge_request.for_fork? :preserve @@ -25,7 +25,7 @@ %p %strong Step 3. Merge the branch and fix any conflicts that come up - = clipboard_button_with_class({clipboard_target: "pre#merge-info-3"}, css_class: "btn-clipboard") + = clipboard_button(clipboard_target: "pre#merge-info-3") %pre.dark#merge-info-3 - if @merge_request.for_fork? :preserve @@ -38,7 +38,7 @@ %p %strong Step 4. Push the result of the merge to GitLab - = clipboard_button_with_class({clipboard_target: "pre#merge-info-4"}, css_class: "btn-clipboard") + = clipboard_button(clipboard_target: "pre#merge-info-4") %pre.dark#merge-info-4 :preserve git push origin #{h @merge_request.target_branch} From 552f54b9f3d80fd49a3c381046cc95426b38b6ba Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 27 Jun 2016 18:01:56 -0400 Subject: [PATCH 072/335] entities: remove :description from MergeRequest It is already part of ProjectEntity. --- CHANGELOG | 1 + lib/api/entities.rb | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index a977fc3fdbf..b905203bcc4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -63,6 +63,7 @@ v 8.10.0 (unreleased) - Added setting to set new users by default as external !4545 (Dravere) - Add min value for project limit field on user's form !3622 (jastkand) - Add reminder to not paste private SSH keys !4399 (Ingo Blechschmidt) + - Remove duplicate `description` field in `MergeRequest` entities (Ben Boeckel) v 8.9.5 - Add more debug info to import/export and memory killer. !5108 diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 9076a0c3831..8edb80177da 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -199,7 +199,6 @@ module API expose :author, :assignee, using: Entities::UserBasic expose :source_project_id, :target_project_id expose :label_names, as: :labels - expose :description expose :work_in_progress?, as: :work_in_progress expose :milestone, using: Entities::Milestone expose :merge_when_build_succeeds From d85dde198b309ab62847d1f58d9373cb3509d4aa Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Mon, 11 Jul 2016 16:05:06 +0100 Subject: [PATCH 073/335] adds test to check json fields on simple request and changes the url request format --- app/assets/javascripts/api.js.coffee | 2 +- app/assets/javascripts/gl_dropdown.js.coffee | 1 - lib/api/projects.rb | 2 +- spec/javascripts/project_title_spec.js.coffee | 2 +- spec/requests/api/projects_spec.rb | 10 ++++++++++ 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee index 8028e66f089..89b0ac697ed 100644 --- a/app/assets/javascripts/api.js.coffee +++ b/app/assets/javascripts/api.js.coffee @@ -3,7 +3,7 @@ groupPath: "/api/:version/groups/:id.json" namespacesPath: "/api/:version/namespaces.json" groupProjectsPath: "/api/:version/groups/:id/projects.json" - projectsPath: "/api/:version/projects.json?format=simple" + projectsPath: "/api/:version/projects.json?simple=true" labelsPath: "/api/:version/projects/:id/labels" licensePath: "/api/:version/licenses/:key" gitignorePath: "/api/:version/gitignores/:key" diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 233a3873ce9..ed9dfcc917e 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -399,7 +399,6 @@ class GitLabDropdown selected = true # Set URL - console.log(data) if @options.url? url = @options.url(data) else diff --git a/lib/api/projects.rb b/lib/api/projects.rb index c46764c4897..7aea553bdca 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -25,7 +25,7 @@ module API @projects = current_user.authorized_projects @projects = filter_projects(@projects) @projects = paginate @projects - if params["format"] + if params["simple"] present @projects, with: Entities::BasicProjectWithAccess, user: current_user else present @projects, with: Entities::ProjectWithAccess, user: current_user diff --git a/spec/javascripts/project_title_spec.js.coffee b/spec/javascripts/project_title_spec.js.coffee index e49dfbf1ba4..0244119fa0e 100644 --- a/spec/javascripts/project_title_spec.js.coffee +++ b/spec/javascripts/project_title_spec.js.coffee @@ -22,7 +22,7 @@ describe 'Project Title', -> @projects_data = fixture.load('projects.json')[0] spyOn(jQuery, 'ajax').and.callFake (req) => - expect(req.url).toBe('/api/v3/projects.json?format=simple') + expect(req.url).toBe('/api/v3/projects.json?simple=true') d = $.Deferred() d.resolve @projects_data d.promise() diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 611dd2a2a88..6176ef69d7b 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -81,6 +81,16 @@ describe API::API, api: true do expect(json_response.first.keys).not_to include('open_issues_count') end + context 'GET /projects?simple=true' do + let(:keys) { ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace", "permissions"] } + it 'should return a simplified version of all the projects' do + get api('/projects?simple=true', user) + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first.keys).to match_array keys + end + end + context 'and using search' do it 'should return searched project' do get api('/projects', user), { search: project.name } From 359ec42754d74206140e8e0c4bb0129e15f824d7 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Thu, 9 Jun 2016 17:56:15 +0100 Subject: [PATCH 074/335] Added shortcut to focus all search tags apart from the top nav search Updated CHANGELOG Added docs for filter shortcut Moved CHANGELOG entry Added phils fixes Fixed search form submitting with empty input Added review fixes Readability and selector perf fix --- CHANGELOG | 1 + app/assets/javascripts/issuable.js.coffee | 4 +--- app/assets/javascripts/projects_list.js.coffee | 11 +++++------ app/assets/javascripts/shortcuts.js.coffee | 6 ++++++ app/views/help/_shortcuts.html.haml | 4 ++++ 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0eb7595fbfa..15a94a3b8cb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -222,6 +222,7 @@ v 8.9.0 - Add rake task 'gitlab:db:configure' for conditionally seeding or migrating the database - Changed the Slack build message to use the singular duration if necessary (Aran Koning) - Fix race condition on merge when build succeeds + - Added shortcut to focus filter search fields and added documentation #18120 - Links from a wiki page to other wiki pages should be rewritten as expected - Add option to project to only allow merge requests to be merged if the build succeeds (Rui Santos) - Added navigation shortcuts to the project pipelines, milestones, builds and forks page. !4393 diff --git a/app/assets/javascripts/issuable.js.coffee b/app/assets/javascripts/issuable.js.coffee index c71d4ecf505..7f795f8096b 100644 --- a/app/assets/javascripts/issuable.js.coffee +++ b/app/assets/javascripts/issuable.js.coffee @@ -32,13 +32,11 @@ issuable_created = false $search = $('#issue_search') $form = $('.js-filter-form') $input = $("input[name='#{$search.attr('name')}']", $form) - if $input.length is 0 $form.append "" else $input.val $search.val() - - Issuable.filterResults $form + Issuable.filterResults $form if $search.val() isnt '' , 500) initLabelFilterRemove: -> diff --git a/app/assets/javascripts/projects_list.js.coffee b/app/assets/javascripts/projects_list.js.coffee index e4c4bf3b273..9d34aebbf02 100644 --- a/app/assets/javascripts/projects_list.js.coffee +++ b/app/assets/javascripts/projects_list.js.coffee @@ -5,13 +5,12 @@ this.initPagination() initSearch: -> - @timer = null - $(".projects-list-filter").on('keyup', -> - clearTimeout(@timer) - @timer = setTimeout(ProjectsList.filterResults, 500) - ) + projectsListFilter = $('.projects-list-filter') + projectsListFilter.on 'keyup', (e) => + clearTimeout(@timer) if @timer + @timer = setTimeout(ProjectsList.filterResults, 500) if projectsListFilter.val() isnt '' - filterResults: => + filterResults: -> $('.projects-list-holder').fadeTo(250, 0.5) form = null diff --git a/app/assets/javascripts/shortcuts.js.coffee b/app/assets/javascripts/shortcuts.js.coffee index 3319a67a79d..04eba43d54c 100644 --- a/app/assets/javascripts/shortcuts.js.coffee +++ b/app/assets/javascripts/shortcuts.js.coffee @@ -4,6 +4,7 @@ class @Shortcuts Mousetrap.reset() if not skipResetBindings Mousetrap.bind('?', @onToggleHelp) Mousetrap.bind('s', Shortcuts.focusSearch) + Mousetrap.bind 'f', @focusFilter Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], @toggleMarkdownPreview) Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL? @@ -32,10 +33,15 @@ class @Shortcuts $('.js-more-help-button').remove() ) + focusFilter: (e) -> + $('input[type=search]', '.nav-controls .block-controls').focus() + e.preventDefault() + @focusSearch: (e) -> $('#search').focus() e.preventDefault() + $(document).on 'click.more_help', '.js-more-help-button', (e) -> $(@).remove() $('.hidden-shortcut').show() diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml index 8cc0b59edeb..ce4536ebdc6 100644 --- a/app/views/help/_shortcuts.html.haml +++ b/app/views/help/_shortcuts.html.haml @@ -18,6 +18,10 @@ %td.shortcut .key s %td Focus Search + %tr + %td.shortcut + .key f + %td Focus Filter %tr %td.shortcut .key ? From 0e5f0276eae25c975078f825ea10ff2c8d05563c Mon Sep 17 00:00:00 2001 From: James Lopez Date: Fri, 8 Jul 2016 17:21:28 +0200 Subject: [PATCH 075/335] squashed - refactor to cope with sub sub N relations probably using the sub_relations method recursively. --- CHANGELOG | 25 +++++++++++++++++++ .../import_export/project_tree_restorer.rb | 9 +++++++ spec/lib/gitlab/import_export/project.json | 13 +++++++++- .../project_tree_restorer_spec.rb | 18 ++++++++++++- 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a019f56c0fa..f895f05ca70 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -32,6 +32,31 @@ v 8.10.0 (unreleased) - Add basic system information like memory and disk usage to the admin panel v 8.9.5 (unreleased) + - Don't garbage collect commits that have related DB records like comments + - More descriptive message for git hooks and file locks + - Handle custom Git hook result in GitLab UI + - Allow '?', or '&' for label names + - Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests + - Add date when user joined the team on the member page + - Fix 404 redirect after validation fails importing a GitLab project + - Added setting to set new users by default as external !4545 (Dravere) + +v 8.9.6 + - Fix importing of events under notes for GitLab projects + +v 8.9.5 + - Add more debug info to import/export and memory killer. !5108 + - Fixed avatar alignment in new MR view. !5095 + - Fix diff comments not showing up in activity feed. !5069 + - Add index on both Award Emoji user and name. !5061 + - Downgrade to Redis 3.2.2 due to massive memory leak with Sidekiq. !5056 + - Re-enable import button when import process fails due to namespace already being taken. !5053 + - Fix snippets comments not displayed. !5045 + - Fix emoji paths in relative root configurations. !5027 + - Fix issues importing events in Import/Export. !4987 + - Fixed 'use shortcuts' button on docs. !4979 + - Admin should be able to turn shared runners into specific ones. !4961 + - Update RedCloth to 4.3.2 for CVE-2012-6684. !4929 (Takuya Noguchi) - Improve the request / withdraw access button. !4860 - Fix assigning shared runners as admins. !4961 - Show "locked" label for locked runners on runners admin. !4961 diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb index dd71b92c522..e2413b082b2 100644 --- a/lib/gitlab/import_export/project_tree_restorer.rb +++ b/lib/gitlab/import_export/project_tree_restorer.rb @@ -70,10 +70,19 @@ module Gitlab # Example: # +relation_key+ issues, loops through the list of *issues* and for each individual # issue, finds any subrelations such as notes, creates them and assign them back to the hash + # + # Recursively calls this method if the sub-relation is a hash containing more sub-relations def create_sub_relations(relation, tree_hash) relation_key = relation.keys.first.to_s + return if tree_hash[relation_key].blank? + tree_hash[relation_key].each do |relation_item| relation.values.flatten.each do |sub_relation| + # We just use author to get the user ID, do not attempt to create an instance. + next if sub_relation == :author + + create_sub_relations(sub_relation, relation_item) if sub_relation.is_a?(Hash) + relation_hash, sub_relation = assign_relation_hash(relation_item, sub_relation) relation_item[sub_relation.to_s] = create_relation(sub_relation, relation_hash) unless relation_hash.blank? end diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index 0b30e8c9b04..7286b0c39c0 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -4208,7 +4208,18 @@ "name": "User 4" }, "events": [ - + { + "id": 529, + "target_type": "Note", + "target_id": 2521, + "title": "test levels", + "data": null, + "project_id": 4, + "created_at": "2016-07-07T14:35:12.128Z", + "updated_at": "2016-07-07T14:35:12.128Z", + "action": 6, + "author_id": 1 + } ] }, { diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index e401ca99077..d2d0a05ad5c 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -25,11 +25,27 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do expect(Ci::Pipeline.first.notes).not_to be_empty end - it 'restores the correct event' do + it 'restores the correct event with symbolised data' do restored_project_json expect(Event.where.not(data: nil).first.data[:ref]).not_to be_empty end + + context 'event at forth level of the tree' do + let(:event) { Event.where(title: 'test levels').first } + + before do + restored_project_json + end + + it 'restores the event' do + expect(event).not_to be_nil + end + + it 'event belongs to note, belongs to merge request, belongs to a project' do + expect(event.note.noteable.project).not_to be_nil + end + end end end end From e0f3b66c38e574e084e0448a7fdd5430ba58fbda Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Mon, 11 Jul 2016 17:06:31 +0100 Subject: [PATCH 076/335] Review changes --- app/assets/javascripts/projects_list.js.coffee | 6 +++--- app/assets/javascripts/shortcuts.js.coffee | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/projects_list.js.coffee b/app/assets/javascripts/projects_list.js.coffee index 9d34aebbf02..a7d78d9e461 100644 --- a/app/assets/javascripts/projects_list.js.coffee +++ b/app/assets/javascripts/projects_list.js.coffee @@ -6,9 +6,9 @@ initSearch: -> projectsListFilter = $('.projects-list-filter') - projectsListFilter.on 'keyup', (e) => - clearTimeout(@timer) if @timer - @timer = setTimeout(ProjectsList.filterResults, 500) if projectsListFilter.val() isnt '' + debounceFilter = _.debounce ProjectsList.filterResults, 500 + projectsListFilter.on 'keyup', (e) -> + debounceFilter() if projectsListFilter.val() isnt '' filterResults: -> $('.projects-list-holder').fadeTo(250, 0.5) diff --git a/app/assets/javascripts/shortcuts.js.coffee b/app/assets/javascripts/shortcuts.js.coffee index 04eba43d54c..8c8689bacee 100644 --- a/app/assets/javascripts/shortcuts.js.coffee +++ b/app/assets/javascripts/shortcuts.js.coffee @@ -2,10 +2,10 @@ class @Shortcuts constructor: (skipResetBindings) -> @enabledHelp = [] Mousetrap.reset() if not skipResetBindings - Mousetrap.bind('?', @onToggleHelp) - Mousetrap.bind('s', Shortcuts.focusSearch) - Mousetrap.bind 'f', @focusFilter - Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], @toggleMarkdownPreview) + Mousetrap.bind '?', @onToggleHelp + Mousetrap.bind 's', Shortcuts.focusSearch + Mousetrap.bind 'f', (e) => @focusFilter e + Mousetrap.bind ['ctrl+shift+p', 'command+shift+p'], @toggleMarkdownPreview Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL? onToggleHelp: (e) => @@ -34,7 +34,8 @@ class @Shortcuts ) focusFilter: (e) -> - $('input[type=search]', '.nav-controls .block-controls').focus() + @filterInput ?= $('input[type=search]', '.nav-controls') + @filterInput.focus() e.preventDefault() @focusSearch: (e) -> From 95fe316f5d5cad06ed3457dd6c6f8263dfabd058 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 11 Jul 2016 18:09:19 +0200 Subject: [PATCH 077/335] fix changelog... --- CHANGELOG | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ce17040614e..eaa0ae2de0c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -53,8 +53,6 @@ v 8.10.0 (unreleased) - Memoize MR merged/closed events retrieval - Don't render discussion notes when requesting diff tab through AJAX - Add basic system information like memory and disk usage to the admin panel - -v 8.9.5 (unreleased) - Don't garbage collect commits that have related DB records like comments - More descriptive message for git hooks and file locks - Handle custom Git hook result in GitLab UI @@ -63,12 +61,12 @@ v 8.9.5 (unreleased) - Add date when user joined the team on the member page - Fix 404 redirect after validation fails importing a GitLab project - Added setting to set new users by default as external !4545 (Dravere) - -v 8.9.6 - - Fix importing of events under notes for GitLab projects - Add min value for project limit field on user's form !3622 (jastkand) - Add reminder to not paste private SSH keys !4399 (Ingo Blechschmidt) +v 8.9.6 (unreleased) + - Fix importing of events under notes for GitLab projects + v 8.9.5 - Add more debug info to import/export and memory killer. !5108 - Fixed avatar alignment in new MR view. !5095 From d2f003a344e6f29a0ad5115c7d8dec5727b87895 Mon Sep 17 00:00:00 2001 From: DJ Mountney Date: Mon, 11 Jul 2016 09:06:36 -0700 Subject: [PATCH 078/335] Update the health_check gem to the latest release This allows us to drop our disable email config override --- CHANGELOG | 1 + Gemfile | 2 +- Gemfile.lock | 6 +++--- config/initializers/health_check.rb | 13 ------------- 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a977fc3fdbf..8bd7b388daa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,7 @@ v 8.10.0 (unreleased) - Exclude email check from the standard health check - Updated layout for Projects, Groups, Users on Admin area !4424 - Fix changing issue state columns in milestone view + - Update health_check gem to version 2.1.0 - Add notification settings dropdown for groups - Wildcards for protected branches. !4665 - Allow importing from Github using Personal Access Tokens. (Eric K Idema) diff --git a/Gemfile b/Gemfile index f1fef4caf76..5c43015e52c 100644 --- a/Gemfile +++ b/Gemfile @@ -344,7 +344,7 @@ gem 'oauth2', '~> 1.2.0' gem 'paranoia', '~> 2.0' # Health check -gem 'health_check', '~> 1.5.1' +gem 'health_check', '~> 2.1.0' # System information gem 'vmstat', '~> 2.1.0' diff --git a/Gemfile.lock b/Gemfile.lock index 721ab9ddc5d..f8018e58a5e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -322,8 +322,8 @@ GEM thor tilt hashie (3.4.3) - health_check (1.5.1) - rails (>= 2.3.0) + health_check (2.1.0) + rails (>= 4.0) hipchat (1.5.2) httparty mimemagic @@ -870,7 +870,7 @@ DEPENDENCIES grape (~> 0.13.0) grape-entity (~> 0.4.2) hamlit (~> 2.5) - health_check (~> 1.5.1) + health_check (~> 2.1.0) hipchat (~> 1.5.0) html-pipeline (~> 1.11.0) httparty (~> 0.13.3) diff --git a/config/initializers/health_check.rb b/config/initializers/health_check.rb index 6796407d4e6..4c91a61fb4a 100644 --- a/config/initializers/health_check.rb +++ b/config/initializers/health_check.rb @@ -1,16 +1,3 @@ -# Email forcibly included in the standard checks, but the email health check -# doesn't support the full range of SMTP options, which can result in failures -# for valid SMTP configurations. -# Overwrite the HealthCheck's detection of whether email is configured -# in order to avoid the email check during standard checks -module HealthCheck - class Utils - def self.mailer_configured? - false - end - end -end - HealthCheck.setup do |config| config.standard_checks = ['database', 'migrations', 'cache'] config.full_checks = ['database', 'migrations', 'cache'] From 7040c1ba3e79cd68d6084aba88d670067835b2f3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Jul 2016 19:37:28 +0300 Subject: [PATCH 079/335] Rename profile navigation tab 'Personal Access Tokes' to 'Access Tokens' Signed-off-by: Dmitriy Zaporozhets --- app/views/layouts/nav/_profile.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml index 96fe62c39c3..6e3c9ab9778 100644 --- a/app/views/layouts/nav/_profile.html.haml +++ b/app/views/layouts/nav/_profile.html.haml @@ -20,7 +20,7 @@ = nav_link(controller: :personal_access_tokens) do = link_to profile_personal_access_tokens_path, title: 'Personal Access Tokens' do %span - Personal Access Tokens + Access Tokens = nav_link(controller: :emails) do = link_to profile_emails_path, title: 'Emails' do %span From 4765a3414e90d1bdfbbd1f9d42decedef9d137cd Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Jul 2016 19:51:20 +0300 Subject: [PATCH 080/335] Add rule about adding new header tab to the ui guide Signed-off-by: Dmitriy Zaporozhets --- doc/development/ui_guide.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/development/ui_guide.md b/doc/development/ui_guide.md index ce0aaa2fd25..b018a8c66d3 100644 --- a/doc/development/ui_guide.md +++ b/doc/development/ui_guide.md @@ -27,6 +27,8 @@ We try to keep the amount of tabs in the header navigation between 5 and 10 so t tab should represent separate functionality. Everything related to the issue tracker should be under the 'Issues' tab while everything related to the wiki should be under 'Wiki' tab and so on and so forth. +When add new tab to the header don't use more than 2 words for text in the link. +We want to keep links short and easy to remmeber and fit all of them in the small screen. ## Mobile screen size From c4fb58ef35183fa8eeb4eee2d065f2d66ea75454 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Jul 2016 16:54:24 +0000 Subject: [PATCH 081/335] Fix typo in UI guide --- doc/development/ui_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/development/ui_guide.md b/doc/development/ui_guide.md index b018a8c66d3..3c44affdd76 100644 --- a/doc/development/ui_guide.md +++ b/doc/development/ui_guide.md @@ -28,7 +28,7 @@ tab should represent separate functionality. Everything related to the issue tracker should be under the 'Issues' tab while everything related to the wiki should be under 'Wiki' tab and so on and so forth. When add new tab to the header don't use more than 2 words for text in the link. -We want to keep links short and easy to remmeber and fit all of them in the small screen. +We want to keep links short and easy to remember and fit all of them in the small screen. ## Mobile screen size From 8ee3c28bcde45e0719e0ef76731b9c92edfcddd9 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Mon, 11 Jul 2016 18:17:00 +0100 Subject: [PATCH 082/335] Handle more than two paths in MergeRequest#diffs --- app/controllers/concerns/diff_for_path.rb | 4 +++- app/models/merge_request_diff.rb | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/controllers/concerns/diff_for_path.rb b/app/controllers/concerns/diff_for_path.rb index 5ca8d3af0c9..e09b8789eb2 100644 --- a/app/controllers/concerns/diff_for_path.rb +++ b/app/controllers/concerns/diff_for_path.rb @@ -2,7 +2,9 @@ module DiffForPath extend ActiveSupport::Concern def render_diff_for_path(diffs, diff_refs, project) - diff_file = safe_diff_files(diffs, diff_refs: diff_refs, repository: project.repository).first + diff_file = safe_diff_files(diffs, diff_refs: diff_refs, repository: project.repository).find do |diff| + diff.old_path == params[:old_path] && diff.new_path == params[:new_path] + end return render_404 unless diff_file diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index d54369c3483..feaba925bad 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -145,10 +145,9 @@ class MergeRequestDiff < ActiveRecord::Base def load_diffs(raw, options) if raw.respond_to?(:each) - if options[:paths] - old_path, new_path = options[:paths] + if paths = options[:paths] raw = raw.select do |diff| - old_path == diff[:old_path] && new_path == diff[:new_path] + paths.include?(diff[:old_path]) || paths.include?(diff[:new_path]) end end From ea40c08d5f313defade9a939e5d5d841aa3ba902 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 11 Jul 2016 12:21:05 -0500 Subject: [PATCH 083/335] Allow SentNotification#position to be set as string or hash --- app/models/sent_notification.rb | 13 ++++++++++++ spec/services/notification_service_spec.rb | 24 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb index 016172c6d7e..f4bcb49b34d 100644 --- a/app/models/sent_notification.rb +++ b/app/models/sent_notification.rb @@ -72,6 +72,19 @@ class SentNotification < ActiveRecord::Base end end + def position=(new_position) + if new_position.is_a?(String) + new_position = JSON.parse(new_position) rescue nil + end + + if new_position.is_a?(Hash) + new_position = new_position.with_indifferent_access + new_position = Gitlab::Diff::Position.new(new_position) + end + + super(new_position) + end + def to_param self.reply_key end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 54719cbb8d8..d3dddfb4817 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -293,6 +293,30 @@ describe NotificationService, services: true do end end end + + context "merge request diff note" do + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:merge_request) { create(:merge_request, source_project: project, assignee: user) } + let(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request) } + + before do + build_team(note.project) + project.team << [merge_request.author, :master] + project.team << [merge_request.assignee, :master] + end + + describe :new_note do + it "records sent notifications" do + # Ensure create SentNotification by noteable = merge_request 6 times, not noteable = note + expect(SentNotification).to receive(:record_note).with(note, any_args).exactly(4).times.and_call_original + + notification.new_note(note) + + expect(SentNotification.last.position).to eq(note.position) + end + end + end end describe 'Issues' do From 24cf6b9f62a312c010c9479fd6155f7c72099979 Mon Sep 17 00:00:00 2001 From: Patricio Cano Date: Mon, 11 Jul 2016 12:41:02 -0500 Subject: [PATCH 084/335] Refactor `mock_auth_hash` --- spec/support/login_helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index 2e400dd825a..ba08733e48d 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -39,7 +39,6 @@ module LoginHelpers def login_via(provider, user, uid) mock_auth_hash(provider, uid, user.email) - Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[:saml] visit new_user_session_path click_link provider end @@ -69,6 +68,7 @@ module LoginHelpers } } }) + Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[:saml] end # Requires Javascript driver. From a5cf953deda76398715abe2654530d0dea9f6a3a Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Mon, 11 Jul 2016 18:42:23 +0100 Subject: [PATCH 085/335] moves let variable to it statement by using a local variable --- spec/requests/api/projects_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 6176ef69d7b..6ded6b40178 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -82,12 +82,12 @@ describe API::API, api: true do end context 'GET /projects?simple=true' do - let(:keys) { ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace", "permissions"] } it 'should return a simplified version of all the projects' do + expected_keys = ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace", "permissions"] get api('/projects?simple=true', user) expect(response).to have_http_status(200) expect(json_response).to be_an Array - expect(json_response.first.keys).to match_array keys + expect(json_response.first.keys).to match_array expected_keys end end From eac19b289384a6281c75781e79bad21408063c1c Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 11 Jul 2016 11:25:01 -0400 Subject: [PATCH 086/335] api: expose {should,force}_remove_source_branch Workflows which use a bot to merge should remove branches if requested. Expose the flag so that bots can request know this. --- CHANGELOG | 1 + doc/api/merge_requests.md | 30 ++++++++++++++++++------ lib/api/entities.rb | 2 ++ spec/requests/api/merge_requests_spec.rb | 4 ++++ 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a977fc3fdbf..41c6884a2a0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.10.0 (unreleased) + - Expose {should,force}_remove_source_branch (Ben Boeckel) - Fix commit builds API, return all builds for all pipelines for given commit. !4849 - Replace Haml with Hamlit to make view rendering faster. !3666 - Refactor repository paths handling to allow multiple git mount points diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 816f09e1007..a8c3b068d22 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -68,7 +68,9 @@ Parameters: "merge_when_build_succeeds": true, "merge_status": "can_be_merged", "subscribed" : false, - "user_notes_count": 1 + "user_notes_count": 1, + "should_remove_source_branch": true, + "force_remove_source_branch": false } ] ``` @@ -132,7 +134,9 @@ Parameters: "merge_when_build_succeeds": true, "merge_status": "can_be_merged", "subscribed" : true, - "user_notes_count": 1 + "user_notes_count": 1, + "should_remove_source_branch": true, + "force_remove_source_branch": false } ``` @@ -233,6 +237,8 @@ Parameters: "merge_status": "can_be_merged", "subscribed" : true, "user_notes_count": 1, + "should_remove_source_branch": true, + "force_remove_source_branch": false, "changes": [ { "old_path": "VERSION", @@ -312,7 +318,9 @@ Parameters: "merge_when_build_succeeds": true, "merge_status": "can_be_merged", "subscribed" : true, - "user_notes_count": 0 + "user_notes_count": 0, + "should_remove_source_branch": true, + "force_remove_source_branch": false } ``` @@ -383,7 +391,9 @@ Parameters: "merge_when_build_succeeds": true, "merge_status": "can_be_merged", "subscribed" : true, - "user_notes_count": 1 + "user_notes_count": 1, + "should_remove_source_branch": true, + "force_remove_source_branch": false } ``` @@ -481,7 +491,9 @@ Parameters: "merge_when_build_succeeds": true, "merge_status": "can_be_merged", "subscribed" : true, - "user_notes_count": 1 + "user_notes_count": 1, + "should_remove_source_branch": true, + "force_remove_source_branch": false } ``` @@ -547,7 +559,9 @@ Parameters: "merge_when_build_succeeds": true, "merge_status": "can_be_merged", "subscribed" : true, - "user_notes_count": 1 + "user_notes_count": 1, + "should_remove_source_branch": true, + "force_remove_source_branch": false } ``` @@ -866,7 +880,9 @@ Example response: "merge_when_build_succeeds": false, "merge_status": "unchecked", "subscribed": true, - "user_notes_count": 7 + "user_notes_count": 7, + "should_remove_source_branch": true, + "force_remove_source_branch": false }, "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ci/merge_requests/7", "body": "Et voluptas laudantium minus nihil recusandae ut accusamus earum aut non.", diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 9076a0c3831..d8e987ee8d4 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -208,6 +208,8 @@ module API merge_request.subscribed?(options[:current_user]) end expose :user_notes_count + expose :should_remove_source_branch?, as: :should_remove_source_branch + expose :force_remove_source_branch?, as: :force_remove_source_branch end class MergeRequestChanges < MergeRequest diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 4a1b5600bdf..651b91e9f68 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -138,6 +138,8 @@ describe API::API, api: true do expect(json_response['work_in_progress']).to be_falsy expect(json_response['merge_when_build_succeeds']).to be_falsy expect(json_response['merge_status']).to eq('can_be_merged') + expect(json_response['should_close_merge_request']).to be_falsy + expect(json_response['force_close_merge_request']).to be_falsy end it "should return merge_request" do @@ -147,6 +149,8 @@ describe API::API, api: true do expect(json_response['iid']).to eq(merge_request.iid) expect(json_response['work_in_progress']).to eq(false) expect(json_response['merge_status']).to eq('can_be_merged') + expect(json_response['should_close_merge_request']).to be_falsy + expect(json_response['force_close_merge_request']).to be_falsy end it 'should return merge_request by iid' do From ad7cca067cc3c6ace8da2433bee9d8cecd2b6f42 Mon Sep 17 00:00:00 2001 From: Rasim Demirbay Date: Mon, 11 Jul 2016 17:32:01 +0300 Subject: [PATCH 087/335] Style of import project buttons were fixed in the new project page. --- app/assets/stylesheets/pages/projects.scss | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index bce4aac3334..5be911dc562 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -340,23 +340,30 @@ a.deploy-project-label { .project-import { .form-group { - margin-bottom: 0; + margin-bottom: 5px; } + .import-buttons { padding-left: 0; display: -webkit-flex; display: flex; -webkit-flex-wrap: wrap; flex-wrap: wrap; + .btn { - margin-right: 10px; - padding: 8px 12px; + margin: 0 10px 10px 0; + padding: 8px; } - &> div { - margin-bottom: 14px; + + > div { padding-left: 0; + &:last-child { margin-bottom: 0; + + .btn { + margin-right: 0; + } } } } From 3d16a50ee3d67c49ecfd4b997829c029c958105d Mon Sep 17 00:00:00 2001 From: Rasim Demirbay Date: Mon, 11 Jul 2016 18:12:25 +0300 Subject: [PATCH 088/335] CHANGELOG was updated. --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 0000e288b19..d1bf5d0ef9e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -66,6 +66,7 @@ v 8.10.0 (unreleased) - Add min value for project limit field on user's form !3622 (jastkand) - Add reminder to not paste private SSH keys !4399 (Ingo Blechschmidt) - Remove duplicate `description` field in `MergeRequest` entities (Ben Boeckel) + - Style of import project buttons were fixed in the new project page. !5183 (rdemirbay) v 8.9.5 - Add more debug info to import/export and memory killer. !5108 From 61f0e89484be5aca5d22ab63c72b08575f7e3f6d Mon Sep 17 00:00:00 2001 From: connorshea Date: Tue, 5 Apr 2016 21:54:57 -0600 Subject: [PATCH 089/335] Make "Get started with Builds" Help Page link work properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is probably a horrible way of fixing this issue, but it does work. I can’t find much information on linking this deeply with Rails routes. Resolves #14872. --- app/views/projects/_builds_settings.html.haml | 2 +- config/routes.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/projects/_builds_settings.html.haml b/app/views/projects/_builds_settings.html.haml index 0568c2d305e..d411da85ab0 100644 --- a/app/views/projects/_builds_settings.html.haml +++ b/app/views/projects/_builds_settings.html.haml @@ -4,7 +4,7 @@ - unless @repository.gitlab_ci_yml .form-group %p Builds need to be configured before you can begin using Continuous Integration. - = link_to 'Get started with Builds', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info' + = link_to 'Get started with Builds', help_page_path('ci', 'quick_start', 'README'), class: 'btn btn-info' .form-group %p Get recent application code using the following command: .radio diff --git a/config/routes.rb b/config/routes.rb index b4f83c58bbd..5ee0bd422fa 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -91,6 +91,7 @@ Rails.application.routes.draw do # Help get 'help' => 'help#index' get 'help/:category/:file' => 'help#show', as: :help_page, constraints: { category: /.*/, file: /[^\/\.]+/ } + get 'help/:category/:subcategory/:file' => 'help#show', as: :deep_help_page, constraints: { category: /.*/, subcategory: /.*/, file: /[^\/\.]+/ } get 'help/shortcuts' get 'help/ui' => 'help#ui' From 3358afa758c7db96ea8fce2a10cdf9c0abe85216 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Mon, 16 May 2016 17:06:26 -0500 Subject: [PATCH 090/335] Update the help_page_path route to accept paths directly instead of using parameters. --- app/controllers/help_controller.rb | 10 ++++------ app/helpers/search_helper.rb | 18 +++++++++--------- app/views/admin/appearances/_form.html.haml | 2 +- .../admin/application_settings/_form.html.haml | 6 +++--- app/views/admin/deploy_keys/new.html.haml | 2 +- app/views/admin/groups/show.html.haml | 2 +- app/views/admin/hooks/index.html.haml | 2 +- app/views/admin/projects/show.html.haml | 2 +- app/views/errors/access_denied.html.haml | 2 +- .../group_members/_new_group_member.html.haml | 2 +- app/views/help/show.html.haml | 2 +- app/views/help/ui.html.haml | 2 +- app/views/import/github/new.html.haml | 2 +- app/views/profiles/keys/index.html.haml | 2 +- app/views/profiles/preferences/show.html.haml | 4 ++-- .../profiles/two_factor_auths/show.html.haml | 2 +- .../projects/_bitbucket_import_modal.html.haml | 2 +- app/views/projects/_builds_settings.html.haml | 2 +- .../projects/_gitlab_import_modal.html.haml | 2 +- .../projects/_merge_request_settings.html.haml | 2 +- app/views/projects/builds/index.html.haml | 2 +- app/views/projects/deploy_keys/_form.html.haml | 2 +- app/views/projects/edit.html.haml | 2 +- .../projects/environments/index.html.haml | 2 +- app/views/projects/environments/new.html.haml | 2 +- app/views/projects/environments/show.html.haml | 2 +- app/views/projects/new.html.haml | 2 +- app/views/projects/notes/_hints.html.haml | 2 +- app/views/projects/pipelines/index.html.haml | 2 +- .../_new_project_member.html.haml | 2 +- .../protected_branches/index.html.haml | 4 ++-- app/views/shared/_visibility_level.html.haml | 2 +- app/views/shared/web_hooks/_form.html.haml | 2 +- config/routes.rb | 4 ++-- features/steps/dashboard/help.rb | 2 +- spec/features/help_pages_spec.rb | 2 +- 36 files changed, 52 insertions(+), 54 deletions(-) diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index 9b5c43b17e2..d5dc894e0bd 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -12,13 +12,12 @@ class HelpController < ApplicationController end def show - @category = clean_path_info(path_params[:category]) - @file = path_params[:file] + @path = path_params[:path] respond_to do |format| format.any(:markdown, :md, :html) do # Note: We are purposefully NOT using `Rails.root.join` - path = File.join(Rails.root, 'doc', @category, "#{@file}.md") + path = File.join(Rails.root, 'doc', "#{@path}.md") if File.exist?(path) @markdown = File.read(path) @@ -33,7 +32,7 @@ class HelpController < ApplicationController # Allow access to images in the doc folder format.any(:png, :gif, :jpeg) do # Note: We are purposefully NOT using `Rails.root.join` - path = File.join(Rails.root, 'doc', @category, "#{@file}.#{params[:format]}") + path = File.join(Rails.root, 'doc', "#{@path}.#{params[:format]}") if File.exist?(path) send_file(path, disposition: 'inline') @@ -57,8 +56,7 @@ class HelpController < ApplicationController private def path_params - params.require(:category) - params.require(:file) + params.require(:path) params end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index f9fc525df6f..b165b569372 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -43,15 +43,15 @@ module SearchHelper # Autocomplete results for internal help pages def help_autocomplete [ - { category: "Help", label: "API Help", url: help_page_path("api", "README") }, - { category: "Help", label: "Markdown Help", url: help_page_path("markdown", "markdown") }, - { category: "Help", label: "Permissions Help", url: help_page_path("permissions", "permissions") }, - { category: "Help", label: "Public Access Help", url: help_page_path("public_access", "public_access") }, - { category: "Help", label: "Rake Tasks Help", url: help_page_path("raketasks", "README") }, - { category: "Help", label: "SSH Keys Help", url: help_page_path("ssh", "README") }, - { category: "Help", label: "System Hooks Help", url: help_page_path("system_hooks", "system_hooks") }, - { category: "Help", label: "Webhooks Help", url: help_page_path("web_hooks", "web_hooks") }, - { category: "Help", label: "Workflow Help", url: help_page_path("workflow", "README") }, + { category: "Help", label: "API Help", url: help_page_path("api/README") }, + { category: "Help", label: "Markdown Help", url: help_page_path("markdown/markdown") }, + { category: "Help", label: "Permissions Help", url: help_page_path("permissions/permissions") }, + { category: "Help", label: "Public Access Help", url: help_page_path("public_access/public_access") }, + { category: "Help", label: "Rake Tasks Help", url: help_page_path("raketasks/README") }, + { category: "Help", label: "SSH Keys Help", url: help_page_path("ssh/README") }, + { category: "Help", label: "System Hooks Help", url: help_page_path("system_hooks/system_hooks") }, + { category: "Help", label: "Webhooks Help", url: help_page_path("web_hooks/web_hooks") }, + { category: "Help", label: "Workflow Help", url: help_page_path("workflow/README") }, ] end diff --git a/app/views/admin/appearances/_form.html.haml b/app/views/admin/appearances/_form.html.haml index dc083e50178..92e2dae4842 100644 --- a/app/views/admin/appearances/_form.html.haml +++ b/app/views/admin/appearances/_form.html.haml @@ -13,7 +13,7 @@ .col-sm-10 = f.text_area :description, class: "form-control", rows: 10 .hint - Description parsed with #{link_to "GitLab Flavored Markdown", help_page_path('markdown', 'markdown'), target: '_blank'}. + Description parsed with #{link_to "GitLab Flavored Markdown", help_page_path('markdown/markdown'), target: '_blank'}. .form-group = f.label :logo, class: 'control-label' .col-sm-10 diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 8de28528cda..538d8176ce7 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -38,11 +38,11 @@ = source %span.help-block#import-sources-help Enabled sources for code import during project creation. OmniAuth must be configured for GitHub - = link_to "(?)", help_page_path("integration", "github") + = link_to "(?)", help_page_path("integration/github") , Bitbucket - = link_to "(?)", help_page_path("integration", "bitbucket") + = link_to "(?)", help_page_path("integration/bitbucket") and GitLab.com - = link_to "(?)", help_page_path("integration", "gitlab") + = link_to "(?)", help_page_path("integration/gitlab") .form-group %label.control-label.col-sm-2 Enabled Git access protocols .col-sm-10 diff --git a/app/views/admin/deploy_keys/new.html.haml b/app/views/admin/deploy_keys/new.html.haml index 15aa059c93d..5c410a695bf 100644 --- a/app/views/admin/deploy_keys/new.html.haml +++ b/app/views/admin/deploy_keys/new.html.haml @@ -14,7 +14,7 @@ .col-sm-10 %p.light Paste a machine public key here. Read more about how to generate it - = link_to "here", help_page_path("ssh", "README") + = link_to "here", help_page_path("ssh/README") = f.text_area :key, class: "form-control thin_area", rows: 5 .form-actions diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 522153b37e3..40c8169ad9d 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -79,7 +79,7 @@ .panel-body.form-holder %p.light Read more about project permissions - %strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink" + %strong= link_to "here", help_page_path("permissions/permissions"), class: "vlink" = form_tag members_update_admin_group_path(@group), id: "new_project_member", class: "bulk_import", method: :put do %div diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml index 7b388cf7862..c217490963f 100644 --- a/app/views/admin/hooks/index.html.haml +++ b/app/views/admin/hooks/index.html.haml @@ -3,7 +3,7 @@ System hooks %p.light - #{link_to "System hooks ", help_page_path("system_hooks", "system_hooks"), class: "vlink"} can be + #{link_to "System hooks ", help_page_path("system_hooks/system_hooks"), class: "vlink"} can be used for binding events when GitLab creates a User or Project. %hr diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 2c5aba71699..b2c607361b3 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -132,7 +132,7 @@ - else passed. - = link_to icon('question-circle'), help_page_path('administration', 'repository_checks') + = link_to icon('question-circle'), help_page_path('administration/repository_checks') .form-group = f.submit 'Trigger repository check', class: 'btn btn-primary' diff --git a/app/views/errors/access_denied.html.haml b/app/views/errors/access_denied.html.haml index 012e9857642..2febeef99d3 100644 --- a/app/views/errors/access_denied.html.haml +++ b/app/views/errors/access_denied.html.haml @@ -3,4 +3,4 @@ %h3 Access Denied %hr %p You are not allowed to access this page. -%p Read more about project permissions #{link_to "here", help_page_path("permissions", "permissions"), class: "vlink"} +%p Read more about project permissions #{link_to "here", help_page_path("permissions/permissions"), class: "vlink"} diff --git a/app/views/groups/group_members/_new_group_member.html.haml b/app/views/groups/group_members/_new_group_member.html.haml index e7ab4f2409b..13ded2bc455 100644 --- a/app/views/groups/group_members/_new_group_member.html.haml +++ b/app/views/groups/group_members/_new_group_member.html.haml @@ -12,7 +12,7 @@ = select_tag :access_level, options_for_select(GroupMember.access_level_roles, @group_member.access_level), class: "project-access-select select2" .help-block Read more about role permissions - %strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink" + %strong= link_to "here", help_page_path("permissions/permissions"), class: "vlink" .form-actions = f.submit 'Add users to group', class: "btn btn-create" diff --git a/app/views/help/show.html.haml b/app/views/help/show.html.haml index 0398afb4c1d..be257b51b9e 100644 --- a/app/views/help/show.html.haml +++ b/app/views/help/show.html.haml @@ -1,3 +1,3 @@ -- page_title @file.humanize, *@category.split("/").reverse.map(&:humanize) +- page_title @path.split("/").reverse.map(&:humanize) .documentation.wiki = markdown @markdown.gsub('$your_email', current_user.try(:email) || "email@example.com") diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index d676bc28c89..431d312b4ca 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -549,4 +549,4 @@ %li wiki page %li help page - You can check how markdown rendered at #{link_to 'Markdown help page', help_page_path("markdown", "markdown")}. + You can check how markdown rendered at #{link_to 'Markdown help page', help_page_path("markdown/markdown")}. diff --git a/app/views/import/github/new.html.haml b/app/views/import/github/new.html.haml index 435ed7bd4cb..4c6af0b7908 100644 --- a/app/views/import/github/new.html.haml +++ b/app/views/import/github/new.html.haml @@ -38,6 +38,6 @@ As an administrator you may like to configure - else Consider asking your GitLab administrator to configure - = link_to 'GitHub integration', help_page_path("integration", "github") + = link_to 'GitHub integration', help_page_path("integration/github") which will allow login via GitHub and allow importing projects without generating a Personal Access Token. diff --git a/app/views/profiles/keys/index.html.haml b/app/views/profiles/keys/index.html.haml index 6a067a03535..a42b3b8eb38 100644 --- a/app/views/profiles/keys/index.html.haml +++ b/app/views/profiles/keys/index.html.haml @@ -11,7 +11,7 @@ Add an SSH key %p.profile-settings-content Before you can add an SSH key you need to - = link_to "generate it.", help_page_path("ssh", "README") + = link_to "generate it.", help_page_path("ssh/README") = render 'form' %hr %h5 diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml index b4d35dc9a3e..2afa026847a 100644 --- a/app/views/profiles/preferences/show.html.haml +++ b/app/views/profiles/preferences/show.html.haml @@ -43,12 +43,12 @@ .form-group = f.label :dashboard, class: 'label-light' do Default Dashboard - = link_to('(?)', help_page_path('profile', 'preferences') + '#default-dashboard', target: '_blank') + = link_to('(?)', help_page_path('profile/preferences') + '#default-dashboard', target: '_blank') = f.select :dashboard, dashboard_choices, {}, class: 'form-control' .form-group = f.label :project_view, class: 'label-light' do Project view - = link_to('(?)', help_page_path('profile', 'preferences') + '#default-project-view', target: '_blank') + = link_to('(?)', help_page_path('profile/preferences') + '#default-project-view', target: '_blank') = f.select :project_view, project_view_choices, {}, class: 'form-control' .help-block Choose what content you want to see on a project's home page. diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml index 5890456bee2..8780da1dec4 100644 --- a/app/views/profiles/two_factor_auths/show.html.haml +++ b/app/views/profiles/two_factor_auths/show.html.haml @@ -14,7 +14,7 @@ - else %p Download the Google Authenticator application from App Store or Google Play Store and scan this code. - More information is available in the #{link_to('documentation', help_page_path('profile', 'two_factor_authentication'))}. + More information is available in the #{link_to('documentation', help_page_path('profile/two_factor_authentication'))}. .row.append-bottom-10 .col-md-3 = raw @qr_code diff --git a/app/views/projects/_bitbucket_import_modal.html.haml b/app/views/projects/_bitbucket_import_modal.html.haml index 2987f6b5b22..e74fd5b93ea 100644 --- a/app/views/projects/_bitbucket_import_modal.html.haml +++ b/app/views/projects/_bitbucket_import_modal.html.haml @@ -10,4 +10,4 @@ as administrator you need to configure - else ask your GitLab administrator to configure - == #{link_to 'OAuth integration', help_page_path("integration", "bitbucket")}. + == #{link_to 'OAuth integration', help_page_path("integration/bitbucket")}. diff --git a/app/views/projects/_builds_settings.html.haml b/app/views/projects/_builds_settings.html.haml index d411da85ab0..fff30f11d82 100644 --- a/app/views/projects/_builds_settings.html.haml +++ b/app/views/projects/_builds_settings.html.haml @@ -4,7 +4,7 @@ - unless @repository.gitlab_ci_yml .form-group %p Builds need to be configured before you can begin using Continuous Integration. - = link_to 'Get started with Builds', help_page_path('ci', 'quick_start', 'README'), class: 'btn btn-info' + = link_to 'Get started with Builds', help_page_path('ci/quick_start/README'), class: 'btn btn-info' .form-group %p Get recent application code using the following command: .radio diff --git a/app/views/projects/_gitlab_import_modal.html.haml b/app/views/projects/_gitlab_import_modal.html.haml index 377cf0187b8..e9f39b16aa7 100644 --- a/app/views/projects/_gitlab_import_modal.html.haml +++ b/app/views/projects/_gitlab_import_modal.html.haml @@ -10,4 +10,4 @@ as administrator you need to configure - else ask your GitLab administrator to configure - == #{link_to 'OAuth integration', help_page_path("integration", "gitlab")}. + == #{link_to 'OAuth integration', help_page_path("integration/gitlab")}. diff --git a/app/views/projects/_merge_request_settings.html.haml b/app/views/projects/_merge_request_settings.html.haml index 771a2e0df7d..19b4249374b 100644 --- a/app/views/projects/_merge_request_settings.html.haml +++ b/app/views/projects/_merge_request_settings.html.haml @@ -8,4 +8,4 @@ %strong Only allow merge requests to be merged if the build succeeds .help-block Builds need to be configured to enable this feature. - = link_to icon('question-circle'), help_page_path('workflow', 'merge_requests', anchor: 'only-allow-merge-requests-to-be-merged-if-the-build-succeeds') + = link_to icon('question-circle'), help_page_path('workflow/merge_requests', anchor: 'only-allow-merge-requests-to-be-merged-if-the-build-succeeds') diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml index a131289ee97..381b3754cd5 100644 --- a/app/views/projects/builds/index.html.haml +++ b/app/views/projects/builds/index.html.haml @@ -31,7 +31,7 @@ data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post - unless @repository.gitlab_ci_yml - = link_to 'Get started with Builds', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info' + = link_to 'Get started with Builds', help_page_path('ci/quick_start/README'), class: 'btn btn-info' = link_to ci_lint_path, class: 'btn btn-default' do %span CI Lint diff --git a/app/views/projects/deploy_keys/_form.html.haml b/app/views/projects/deploy_keys/_form.html.haml index 894c36a96df..901605f7ca3 100644 --- a/app/views/projects/deploy_keys/_form.html.haml +++ b/app/views/projects/deploy_keys/_form.html.haml @@ -9,5 +9,5 @@ .form-group %p.light.append-bottom-0 Paste a machine public key here. Read more about how to generate it - = link_to "here", help_page_path("ssh", "README") + = link_to "here", help_page_path("ssh/README") = f.submit "Add key", class: "btn-create btn" diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 27a94fe02dc..57af167180b 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -23,7 +23,7 @@ .form-group.project-visibility-level-holder = f.label :visibility_level, class: 'label-light' do Visibility Level - = link_to "(?)", help_page_path("public_access", "public_access") + = link_to "(?)", help_page_path("public_access/public_access") - if can_change_visibility_level?(@project, current_user) = render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: @project.visibility_level, form_model: @project) - else diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 5242021243e..303d7c23d01 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -17,7 +17,7 @@ Environments are places where code gets deployed, such as staging or production. %br = succeed "." do - = link_to "Read more about environments", help_page_path("ci", "environments") + = link_to "Read more about environments", help_page_path("ci/environments") - if can?(current_user, :create_environment, @project) = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do New environment diff --git a/app/views/projects/environments/new.html.haml b/app/views/projects/environments/new.html.haml index da325efecd2..89e06567196 100644 --- a/app/views/projects/environments/new.html.haml +++ b/app/views/projects/environments/new.html.haml @@ -7,6 +7,6 @@ %p Environments allow you to track deployments of your application = succeed "." do - = link_to "Read more about environments", help_page_path("ci", "environments") + = link_to "Read more about environments", help_page_path("ci/environments") = render 'form' diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml index 53c62ef234d..b17aba2431f 100644 --- a/app/views/projects/environments/show.html.haml +++ b/app/views/projects/environments/show.html.haml @@ -20,7 +20,7 @@ Define environments in the deploy stage(s) in %code .gitlab-ci.yml to track deployments here. - = link_to "Read more", help_page_path("ci", "environments"), class: "btn btn-success" + = link_to "Read more", help_page_path("ci/environments"), class: "btn btn-success" - else .table-holder %table.table.environments diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 05f33b78a47..9b00bdedc27 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -107,7 +107,7 @@ .form-group.project-visibility-level-holder = f.label :visibility_level, class: 'label-light' do Visibility Level - = link_to "(?)", help_page_path("public_access", "public_access") + = link_to "(?)", help_page_path("public_access/public_access") = render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: @project.visibility_level, form_model: @project) = f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4 diff --git a/app/views/projects/notes/_hints.html.haml b/app/views/projects/notes/_hints.html.haml index 7d1cbc62e86..25466e7562e 100644 --- a/app/views/projects/notes/_hints.html.haml +++ b/app/views/projects/notes/_hints.html.haml @@ -1,7 +1,7 @@ .comment-toolbar.clearfix .toolbar-text Styling with - = link_to 'Markdown', help_page_path('markdown', 'markdown'), target: '_blank', tabindex: -1 + = link_to 'Markdown', help_page_path('markdown/markdown'), target: '_blank', tabindex: -1 is supported %button.toolbar-button.markdown-selector{ type: 'button', tabindex: '-1' } = icon('file-image-o', class: 'toolbar-button-icon') diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml index 6a127afa410..7c225e2b282 100644 --- a/app/views/projects/pipelines/index.html.haml +++ b/app/views/projects/pipelines/index.html.haml @@ -31,7 +31,7 @@ New pipeline - unless @repository.gitlab_ci_yml - = link_to 'Get started with Pipelines', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info' + = link_to 'Get started with Pipelines', help_page_path('ci/quick_start/README'), class: 'btn btn-info' = link_to ci_lint_path, class: 'btn btn-default' do %span CI Lint diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml index 82892a33358..ea3d82d858e 100644 --- a/app/views/projects/project_members/_new_project_member.html.haml +++ b/app/views/projects/project_members/_new_project_member.html.haml @@ -12,7 +12,7 @@ = select_tag :access_level, options_for_select(ProjectMember.access_level_roles, @project_member.access_level), class: "project-access-select select2" .help-block Read more about role permissions - %strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink" + %strong= link_to "here", help_page_path("permissions/permissions"), class: "vlink" .form-actions = f.submit 'Add users to project', class: "btn btn-create" diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml index 5669713d9a1..4da43488dac 100644 --- a/app/views/projects/protected_branches/index.html.haml +++ b/app/views/projects/protected_branches/index.html.haml @@ -8,10 +8,10 @@ %p.prepend-top-20 Protected branches are designed to: %ul - %li prevent pushes from everybody except #{link_to "masters", help_page_path("permissions", "permissions"), class: "vlink"} + %li prevent pushes from everybody except #{link_to "masters", help_page_path("permissions/permissions"), class: "vlink"} %li prevent anyone from force pushing to the branch %li prevent anyone from deleting the branch - %p.append-bottom-0 Read more about #{link_to "project permissions", help_page_path("permissions", "permissions"), class: "underlined-link"} + %p.append-bottom-0 Read more about #{link_to "project permissions", help_page_path("permissions/permissions"), class: "underlined-link"} .col-lg-9 %h5.prepend-top-0 Protect a branch diff --git a/app/views/shared/_visibility_level.html.haml b/app/views/shared/_visibility_level.html.haml index 1c6ec198d3d..107ad19177c 100644 --- a/app/views/shared/_visibility_level.html.haml +++ b/app/views/shared/_visibility_level.html.haml @@ -1,7 +1,7 @@ .form-group.project-visibility-level-holder = f.label :visibility_level, class: 'control-label' do Visibility Level - = link_to "(?)", help_page_path("public_access", "public_access") + = link_to "(?)", help_page_path("public_access/public_access") .col-sm-10 - if can_change_visibility_level = render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model) diff --git a/app/views/shared/web_hooks/_form.html.haml b/app/views/shared/web_hooks/_form.html.haml index d1e861ca80c..2585ed9360b 100644 --- a/app/views/shared/web_hooks/_form.html.haml +++ b/app/views/shared/web_hooks/_form.html.haml @@ -6,7 +6,7 @@ %h4.prepend-top-0 = page_title %p - #{link_to "Webhooks", help_page_path("web_hooks", "web_hooks")} can be + #{link_to "Webhooks", help_page_path("web_hooks/web_hooks")} can be used for binding events when something is happening within the project. .col-lg-9.append-bottom-default = form_for hook, as: :hook, url: polymorphic_path(url_components + [:hooks]) do |f| diff --git a/config/routes.rb b/config/routes.rb index 5ee0bd422fa..3160fd767b8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -89,9 +89,9 @@ Rails.application.routes.draw do mount Grack::AuthSpawner, at: '/', constraints: lambda { |request| /[-\/\w\.]+\.git\/(info\/lfs|gitlab-lfs)/.match(request.path_info) }, via: [:get, :post, :put] # Help + get 'help' => 'help#index' - get 'help/:category/:file' => 'help#show', as: :help_page, constraints: { category: /.*/, file: /[^\/\.]+/ } - get 'help/:category/:subcategory/:file' => 'help#show', as: :deep_help_page, constraints: { category: /.*/, subcategory: /.*/, file: /[^\/\.]+/ } + get 'help/*path' => 'help#show', as: :help_page get 'help/shortcuts' get 'help/ui' => 'help#ui' diff --git a/features/steps/dashboard/help.rb b/features/steps/dashboard/help.rb index 800e869533e..9c94dc70df0 100644 --- a/features/steps/dashboard/help.rb +++ b/features/steps/dashboard/help.rb @@ -8,7 +8,7 @@ class Spinach::Features::DashboardHelp < Spinach::FeatureSteps end step 'I visit the "Rake Tasks" help page' do - visit help_page_path("raketasks", "maintenance") + visit help_page_path("raketasks/maintenance") end step 'I should see "Rake Tasks" page markdown rendered' do diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb index 8c6b669ce78..1e2306d7f59 100644 --- a/spec/features/help_pages_spec.rb +++ b/spec/features/help_pages_spec.rb @@ -6,7 +6,7 @@ describe 'Help Pages', feature: true do login_as :user end it 'replace the variable $your_email with the email of the user' do - visit help_page_path('ssh', 'README') + visit help_page_path('ssh/README') expect(page).to have_content("ssh-keygen -t rsa -C \"#{@user.email}\"") end end From bd09b2d563d7190ab26f820401e4d981022022c8 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Mon, 11 Jul 2016 13:12:55 -0600 Subject: [PATCH 091/335] Clean path info --- app/controllers/help_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index d5dc894e0bd..d3dd98c8a4e 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -12,7 +12,7 @@ class HelpController < ApplicationController end def show - @path = path_params[:path] + @path = clean_path_info(path_params[:path]) respond_to do |format| format.any(:markdown, :md, :html) do From edc2792557d143aab09966e37f1ac694fb24796d Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 11 Jul 2016 15:32:58 -0500 Subject: [PATCH 092/335] Normalize spacing for version numbers in CHANGELOG [ci skip] --- CHANGELOG | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 79ee72e330c..4e385f5d515 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2617,13 +2617,13 @@ v 6.5.0 - Files API supports base64 encoded content (sponsored by O'Reilly Media) - Added support for Go's repository retrieval (Bruno Albuquerque) -v6.4.3 +v 6.4.3 - Don't use unicorn worker killer if PhusionPassenger is defined -v6.4.2 +v 6.4.2 - Fixed wrong behaviour of script/upgrade.rb -v6.4.1 +v 6.4.1 - Fixed bug with repository rename - Fixed bug with project transfer From 7690513495d02d14af8a1a0cb3bf00f243ec0419 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Mon, 11 Jul 2016 16:50:48 -0400 Subject: [PATCH 093/335] Add space to kick target branch error in butt --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 757bb3f1670..2c58a312208 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -53,7 +53,7 @@ v 8.10.0 (unreleased) - Allow '?', or '&' for label names - Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests - Add date when user joined the team on the member page - - Fix 404 redirect after validation fails importing a GitLab project + - Fix 404 redirect after validation fails importing a GitLab project v 8.9.5 - Add more debug info to import/export and memory killer. !5108 From 05109ed8eaa4872a89be987d3a080489241a23c8 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 11 Jul 2016 16:16:57 -0500 Subject: [PATCH 094/335] Update header block class on snippets page --- app/views/projects/snippets/index.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml index 6c994ae486b..1646bcf4b8a 100644 --- a/app/views/projects/snippets/index.html.haml +++ b/app/views/projects/snippets/index.html.haml @@ -1,6 +1,6 @@ - page_title "Snippets" -.row-content-block.top-block +.sub-header-block .pull-right - if can?(current_user, :create_project_snippet, @project) = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New Snippet" do From ce5a5f75e428bd9de7de0b126d16b922a157646f Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 11 Jul 2016 16:42:25 -0500 Subject: [PATCH 095/335] Add margin to filter labels --- app/assets/stylesheets/pages/labels.scss | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss index 47bfd144930..3b1e38fc07d 100644 --- a/app/assets/stylesheets/pages/labels.scss +++ b/app/assets/stylesheets/pages/labels.scss @@ -162,9 +162,15 @@ } .filtered-labels { + font-size: 0; + padding: 12px 16px; + .label-row { + margin-top: 4px; + margin-bottom: 4px; + &:not(:last-child) { - margin-right: 5px; + margin-right: 8px; } } From af3727b34a3e61668ffca8dc4db85e3c57ff2cc8 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 3 Jul 2016 22:31:43 -0700 Subject: [PATCH 096/335] Optimize system note visibility checking by hiding notes that have been fully redacted and contain cross-project references. The previous implementation relied on Note#cross_reference_not_visible_for?, which essentially tries to render all the Markdown references in a system note and only displays the note if the user can see the referring project. But this duplicated the work that Banzai::NotesRenderer was doing already. Instead, for each note we render, we memoize the number of visible user references and use it later if it is available. Improves #19273 --- CHANGELOG | 1 + app/models/note.rb | 14 ++++++- lib/banzai/object_renderer.rb | 10 ++--- lib/banzai/redactor.rb | 37 +++++++++++++------ spec/features/notes_on_merge_requests_spec.rb | 22 +++++++++++ spec/lib/banzai/object_renderer_spec.rb | 8 +++- spec/lib/banzai/redactor_spec.rb | 24 +++++++++++- spec/models/note_spec.rb | 14 +++++++ 8 files changed, 107 insertions(+), 23 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 79ee72e330c..41fd3c8d22b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ v 8.10.0 (unreleased) - Fix commit builds API, return all builds for all pipelines for given commit. !4849 - Replace Haml with Hamlit to make view rendering faster. !3666 - Refactor repository paths handling to allow multiple git mount points + - Optimize system note visibility checking by memoizing the visible reference count !5070 - Add Application Setting to configure default Repository Path for new projects - Wrap code blocks on Activies and Todos page. !4783 (winniehell) - Align flash messages with left side of page content !4959 (winniehell) diff --git a/app/models/note.rb b/app/models/note.rb index ffffd0c0838..8dca2ef09a8 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -10,6 +10,10 @@ class Note < ActiveRecord::Base # Banzai::ObjectRenderer. attr_accessor :note_html + # An Array containing the number of visible references as generated by + # Banzai::ObjectRenderer + attr_accessor :user_visible_reference_count + default_value_for :system, false attr_mentionable :note, pipeline: :note @@ -193,7 +197,15 @@ class Note < ActiveRecord::Base end def cross_reference_not_visible_for?(user) - cross_reference? && referenced_mentionables(user).empty? + cross_reference? && !has_referenced_mentionables?(user) + end + + def has_referenced_mentionables?(user) + if user_visible_reference_count.present? + user_visible_reference_count > 0 + else + referenced_mentionables(user).any? + end end def award_emoji? diff --git a/lib/banzai/object_renderer.rb b/lib/banzai/object_renderer.rb index f0e4f28bf12..dc83b87a6c1 100644 --- a/lib/banzai/object_renderer.rb +++ b/lib/banzai/object_renderer.rb @@ -31,10 +31,10 @@ module Banzai redacted = redact_documents(documents) objects.each_with_index do |object, index| - object.__send__("#{attribute}_html=", redacted.fetch(index)) + redacted_data = redacted[index] + object.__send__("#{attribute}_html=", redacted_data[:document].to_html.html_safe) + object.user_visible_reference_count = redacted_data[:visible_reference_count] end - - objects end # Renders the attribute of every given object. @@ -50,9 +50,7 @@ module Banzai def redact_documents(documents) redactor = Redactor.new(project, user) - redactor.redact(documents).map do |document| - document.to_html.html_safe - end + redactor.redact(documents) end # Returns a Banzai context for the given object and attribute. diff --git a/lib/banzai/redactor.rb b/lib/banzai/redactor.rb index ffd267d5e9a..0df3a72d1c4 100644 --- a/lib/banzai/redactor.rb +++ b/lib/banzai/redactor.rb @@ -19,29 +19,36 @@ module Banzai # # Returns the documents passed as the first argument. def redact(documents) - nodes = documents.flat_map do |document| - Querying.css(document, 'a.gfm[data-reference-type]') - end + all_document_nodes = document_nodes(documents) - redact_nodes(nodes) - - documents + redact_document_nodes(all_document_nodes) end - # Redacts the given nodes + # Redacts the given node documents # - # nodes - An Array of HTML nodes to redact. - def redact_nodes(nodes) - visible = nodes_visible_to_user(nodes) + # data - An Array of a Hashes mapping an HTML document to nodes to redact. + def redact_document_nodes(all_document_nodes) + all_nodes = all_document_nodes.map { |x| x[:nodes] }.flatten + visible = nodes_visible_to_user(all_nodes) + metadata = [] - nodes.each do |node| - unless visible.include?(node) + all_document_nodes.each do |entry| + nodes_for_document = entry[:nodes] + doc_data = { document: entry[:document], visible_reference_count: nodes_for_document.count } + metadata << doc_data + + nodes_for_document.each do |node| + next if visible.include?(node) + + doc_data[:visible_reference_count] -= 1 # The reference should be replaced by the original text, # which is not always the same as the rendered text. text = node.attr('data-original') || node.text node.replace(text) end end + + metadata end # Returns the nodes visible to the current user. @@ -65,5 +72,11 @@ module Banzai visible end + + def document_nodes(documents) + documents.map do |document| + { document: document, nodes: Querying.css(document, 'a.gfm[data-reference-type]') } + end + end end end diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index 5174168713c..64c6d9416f6 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -135,6 +135,28 @@ describe 'Comments', feature: true do end end + describe 'Handles cross-project system notes', js: true, feature: true do + let(:user) { create(:user) } + let(:project) { create(:project, :public) } + let(:project2) { create(:project, :private) } + let(:issue) { create(:issue, project: project2) } + let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'markdown') } + let!(:note) { create(:note_on_merge_request, :system, noteable: merge_request, project: project, note: "mentioned in #{issue.to_reference(project)}") } + + it 'shows the system note' do + login_as :admin + visit namespace_project_merge_request_path(project.namespace, project, merge_request) + + expect(page).to have_css('.system-note') + end + + it 'hides redacted system note' do + visit namespace_project_merge_request_path(project.namespace, project, merge_request) + + expect(page).not_to have_css('.system-note') + end + end + describe 'On a merge request diff', js: true, feature: true do let(:merge_request) { create(:merge_request) } let(:project) { merge_request.source_project } diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb index 44256b32bdc..d99175967af 100644 --- a/spec/lib/banzai/object_renderer_spec.rb +++ b/spec/lib/banzai/object_renderer_spec.rb @@ -17,6 +17,7 @@ describe Banzai::ObjectRenderer do and_call_original expect(object).to receive(:note_html=).with('

    hello

    ') + expect(object).to receive(:user_visible_reference_count=).with(0) renderer.render([object], :note) end @@ -25,6 +26,7 @@ describe Banzai::ObjectRenderer do describe '#render_objects' do it 'renders an Array of objects' do object = double(:object, note: 'hello') + renderer = described_class.new(project, user) expect(renderer).to receive(:render_attribute).with(object, :note). @@ -38,7 +40,7 @@ describe Banzai::ObjectRenderer do end describe '#redact_documents' do - it 'redacts a set of documents and returns them as an Array of Strings' do + it 'redacts a set of documents and returns them as an Array of Hashes' do doc = Nokogiri::HTML.fragment('

    hello

    ') renderer = described_class.new(project, user) @@ -48,7 +50,9 @@ describe Banzai::ObjectRenderer do redacted = renderer.redact_documents([doc]) - expect(redacted).to eq(['

    hello

    ']) + expect(redacted.count).to eq(1) + expect(redacted.first[:visible_reference_count]).to eq(0) + expect(redacted.first[:document].to_html).to eq('

    hello

    ') end end diff --git a/spec/lib/banzai/redactor_spec.rb b/spec/lib/banzai/redactor_spec.rb index 488f465bcda..254657a881d 100644 --- a/spec/lib/banzai/redactor_spec.rb +++ b/spec/lib/banzai/redactor_spec.rb @@ -15,11 +15,31 @@ describe Banzai::Redactor do expect(redactor).to receive(:nodes_visible_to_user).and_return([]) - expect(redactor.redact([doc1, doc2])).to eq([doc1, doc2]) + redacted_data = redactor.redact([doc1, doc2]) + expect(redacted_data.map { |data| data[:document] }).to eq([doc1, doc2]) + expect(redacted_data.map { |data| data[:visible_reference_count] }).to eq([0, 0]) expect(doc1.to_html).to eq('foo') expect(doc2.to_html).to eq('bar') end + + it 'does not redact an Array of documents' do + doc1_html = '
    foo' + doc1 = Nokogiri::HTML.fragment(doc1_html) + + doc2_html = 'bar' + doc2 = Nokogiri::HTML.fragment(doc2_html) + + nodes = redactor.document_nodes([doc1, doc2]).map { |x| x[:nodes] } + expect(redactor).to receive(:nodes_visible_to_user).and_return(nodes.flatten) + + redacted_data = redactor.redact([doc1, doc2]) + + expect(redacted_data.map { |data| data[:document] }).to eq([doc1, doc2]) + expect(redacted_data.map { |data| data[:visible_reference_count] }).to eq([1, 1]) + expect(doc1.to_html).to eq(doc1_html) + expect(doc2.to_html).to eq(doc2_html) + end end describe '#redact_nodes' do @@ -31,7 +51,7 @@ describe Banzai::Redactor do with([node]). and_return(Set.new) - redactor.redact_nodes([node]) + redactor.redact_document_nodes([{ document: doc, nodes: [node] }]) expect(doc.to_html).to eq('foo') end diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 6549791f675..7d0697dab42 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -226,6 +226,20 @@ describe Note, models: true do it "returns false" do expect(note.cross_reference_not_visible_for?(private_user)).to be_falsy end + + it "returns false if user visible reference count set" do + note.user_visible_reference_count = 1 + + expect(note).not_to receive(:reference_mentionables) + expect(note.cross_reference_not_visible_for?(ext_issue.author)).to be_falsy + end + + it "returns true if ref count is 0" do + note.user_visible_reference_count = 0 + + expect(note).not_to receive(:reference_mentionables) + expect(note.cross_reference_not_visible_for?(ext_issue.author)).to be_truthy + end end describe 'clear_blank_line_code!' do From c30b3257818b6106c08e5d454e14b972d95450fa Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Mon, 11 Jul 2016 16:11:33 -0600 Subject: [PATCH 097/335] Fix failing tests. --- .../protected_branches/index.html.haml | 2 +- spec/controllers/help_controller_spec.rb | 13 +++++------ spec/routing/routing_spec.rb | 22 ++++++++----------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml index 4da43488dac..3fab95751e0 100644 --- a/app/views/projects/protected_branches/index.html.haml +++ b/app/views/projects/protected_branches/index.html.haml @@ -23,7 +23,7 @@ = f.label :name, "Branch", class: "label-light" = render partial: "dropdown", locals: { f: f } %p.help-block - = link_to "Wildcards", help_page_path(category: 'workflow', file: 'protected_branches', format: 'md', anchor: "wildcard-protected-branches") + = link_to "Wildcards", help_page_path('workflow/protected_branches', anchor: "wildcard-protected-branches") such as %code *-stable or diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb index 1f7fd517342..267d511c2db 100644 --- a/spec/controllers/help_controller_spec.rb +++ b/spec/controllers/help_controller_spec.rb @@ -11,7 +11,7 @@ describe HelpController do context 'for Markdown formats' do context 'when requested file exists' do before do - get :show, category: 'ssh', file: 'README', format: :md + get :show, path: 'ssh/README', format: :md end it 'assigns to @markdown' do @@ -26,7 +26,7 @@ describe HelpController do context 'when requested file is missing' do it 'renders not found' do - get :show, category: 'foo', file: 'bar', format: :md + get :show, path: 'foo/bar', format: :md expect(response).to be_not_found end end @@ -36,8 +36,7 @@ describe HelpController do context 'when requested file exists' do it 'renders the raw file' do get :show, - category: 'workflow/protected_branches', - file: 'protected_branches1', + path: 'workflow/protected_branches/protected_branches1', format: :png expect(response).to be_success expect(response.content_type).to eq 'image/png' @@ -48,8 +47,7 @@ describe HelpController do context 'when requested file is missing' do it 'renders not found' do get :show, - category: 'foo', - file: 'bar', + path: 'foo/bar', format: :png expect(response).to be_not_found end @@ -59,8 +57,7 @@ describe HelpController do context 'for other formats' do it 'always renders not found' do get :show, - category: 'ssh', - file: 'README', + path: 'ssh/README', format: :foo expect(response).to be_not_found end diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index 8a8e131c57b..2c755919456 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -98,7 +98,7 @@ describe SnippetsController, "routing" do end # help GET /help(.:format) help#index -# help_page GET /help/:category/:file(.:format) help#show {:category=>/.*/, :file=>/[^\/\.]+/} +# help_page GET /help/*path(.:format) help#show # help_shortcuts GET /help/shortcuts(.:format) help#shortcuts # help_ui GET /help/ui(.:format) help#ui describe HelpController, "routing" do @@ -109,23 +109,19 @@ describe HelpController, "routing" do it 'to #show' do path = '/help/markdown/markdown.md' expect(get(path)).to route_to('help#show', - category: 'markdown', - file: 'markdown', + path: 'markdown/markdown', format: 'md') path = '/help/workflow/protected_branches/protected_branches1.png' expect(get(path)).to route_to('help#show', - category: 'workflow/protected_branches', - file: 'protected_branches1', + path: 'workflow/protected_branches/protected_branches1', format: 'png') - end - - it 'to #shortcuts' do - expect(get('/help/shortcuts')).to route_to('help#shortcuts') - end - - it 'to #ui' do - expect(get('/help/ui')).to route_to('help#ui') + path = '/help/shortcuts' + expect(get(path)).to route_to('help#show', + path: 'shortcuts') + path = '/help/ui' + expect(get(path)).to route_to('help#show', + path: 'ui') end end From f5cc3f63a8a6a44e755aa81ac6cba8e544b848e6 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 11 Jul 2016 00:08:01 -0500 Subject: [PATCH 098/335] Render inline diffs for multiple changed lines following eachother --- CHANGELOG | 1 + lib/gitlab/diff/inline_diff.rb | 50 ++++++++++++++++++------ spec/lib/gitlab/diff/inline_diff_spec.rb | 28 ++++++++----- 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3e4a10bb5a3..02cbd9bb295 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -25,6 +25,7 @@ v 8.10.0 (unreleased) - Updated layout for Projects, Groups, Users on Admin area !4424 - Fix changing issue state columns in milestone view - Add notification settings dropdown for groups + - Render inline diffs for multiple changed lines following eachother - Wildcards for protected branches. !4665 - Allow importing from Github using Personal Access Tokens. (Eric K Idema) - API: Todos !3188 (Robert Schilling) diff --git a/lib/gitlab/diff/inline_diff.rb b/lib/gitlab/diff/inline_diff.rb index 789c14518b0..72d9abeefcc 100644 --- a/lib/gitlab/diff/inline_diff.rb +++ b/lib/gitlab/diff/inline_diff.rb @@ -1,16 +1,30 @@ module Gitlab module Diff class InlineDiff + # Regex to find a run of deleted lines followed by the same number of added lines + REGEX = %r{ + # Runs start at the beginning of the string (the first line) or after a space (for an unchanged line) + (?:\A| ) + + # This matches a number of `-`s followed by the same number of `+`s through recursion + (? + - + \g? + \+ + ) + + # Runs end at the end of the string (the last line) or before a space (for an unchanged line) + (?= |\z) + }x.freeze + attr_accessor :old_line, :new_line, :offset def self.for_lines(lines) - local_edit_indexes = self.find_local_edits(lines) + changed_line_pairs = self.find_changed_line_pairs(lines) inline_diffs = [] - local_edit_indexes.each do |index| - old_index = index - new_index = index + 1 + changed_line_pairs.each do |old_index, new_index| old_line = lines[old_index] new_line = lines[new_index] @@ -51,18 +65,28 @@ module Gitlab private - def self.find_local_edits(lines) - line_prefixes = lines.map { |line| line.match(/\A([+-])/) ? $1 : ' ' } - joined_line_prefixes = " #{line_prefixes.join} " + # Finds pairs of old/new line pairs that represent the same line that changed + def self.find_changed_line_pairs(lines) + # Prefixes of all diff lines, indicating their types + # For example: `" - + -+ ---+++ --+ -++"` + line_prefixes = lines.each_with_object("") { |line, s| s << line[0] }.gsub(/[^ +-]/, ' ') - offset = 0 - local_edit_indexes = [] - while index = joined_line_prefixes.index(" -+ ", offset) - local_edit_indexes << index - offset = index + 1 + changed_line_pairs = [] + line_prefixes.scan(REGEX) do + # For `"---+++"`, `begin_index == 0`, `end_index == 6` + begin_index, end_index = Regexp.last_match.offset(:del_ins) + + # For `"---+++"`, `changed_line_count == 3` + changed_line_count = (end_index - begin_index) / 2 + + halfway_index = begin_index + changed_line_count + (begin_index...halfway_index).each do |i| + # For `"---+++"`, index 1 maps to 1 + 3 = 4 + changed_line_pairs << [i, i + changed_line_count] + end end - local_edit_indexes + changed_line_pairs end def longest_common_prefix(a, b) diff --git a/spec/lib/gitlab/diff/inline_diff_spec.rb b/spec/lib/gitlab/diff/inline_diff_spec.rb index 95a993d26cf..8ca3f73509e 100644 --- a/spec/lib/gitlab/diff/inline_diff_spec.rb +++ b/spec/lib/gitlab/diff/inline_diff_spec.rb @@ -3,14 +3,19 @@ require 'spec_helper' describe Gitlab::Diff::InlineDiff, lib: true do describe '.for_lines' do let(:diff) do - < Date: Tue, 12 Jul 2016 13:24:51 +0800 Subject: [PATCH 099/335] Bump gitlab-workhorse version for !5094 --- GITLAB_WORKHORSE_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index 879be8a98fc..e7c7d3cc3c8 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -0.7.7 +0.7.8 From cdc031b65b52f280defe46d278ce60432be895e1 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Tue, 12 Jul 2016 08:57:18 +0100 Subject: [PATCH 100/335] Fix expandable diffs --- app/assets/javascripts/diff.js.coffee | 1 + spec/features/expand_collapse_diffs_spec.rb | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/diff.js.coffee b/app/assets/javascripts/diff.js.coffee index 83516f97552..c132cc8c542 100644 --- a/app/assets/javascripts/diff.js.coffee +++ b/app/assets/javascripts/diff.js.coffee @@ -1,6 +1,7 @@ class @Diff UNFOLD_COUNT = 20 constructor: -> + $('.files .diff-file').singleFileDiff() @filesCommentButton = $('.files .diff-file').filesCommentButton() $(document).off('click', '.js-unfold') diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb index 7cff196c8d9..78bc888f2a6 100644 --- a/spec/features/expand_collapse_diffs_spec.rb +++ b/spec/features/expand_collapse_diffs_spec.rb @@ -106,7 +106,7 @@ feature 'Expand and collapse diffs', js: true, feature: true do let(:comment_text) { 'A comment' } before do - large_diff.find('.line_holder', match: :prefer_exact).hover + large_diff.find('.diff-line-num', match: :prefer_exact).hover large_diff.find('.add-diff-note').click large_diff.find('.note-textarea').send_keys comment_text large_diff.find_button('Comment').click @@ -161,7 +161,7 @@ feature 'Expand and collapse diffs', js: true, feature: true do end it 'does not make a new HTTP request' do - expect(evaluate_script('ajaxUris')).to be_empty + expect(evaluate_script('ajaxUris')).not_to include(a_string_matching('small_diff.md')) end end end @@ -199,7 +199,7 @@ feature 'Expand and collapse diffs', js: true, feature: true do end it 'does not make a new HTTP request' do - expect(evaluate_script('ajaxUris')).to be_empty + expect(evaluate_script('ajaxUris')).not_to include(a_string_matching('small_diff.md')) end end end From 3ee328dcc3203aeaa2cdf619ac95d7dac07a84eb Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Tue, 12 Jul 2016 10:43:08 +0100 Subject: [PATCH 101/335] changes string to symbol in param --- lib/api/projects.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 7aea553bdca..844547665ef 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -25,7 +25,7 @@ module API @projects = current_user.authorized_projects @projects = filter_projects(@projects) @projects = paginate @projects - if params["simple"] + if params[:simple] present @projects, with: Entities::BasicProjectWithAccess, user: current_user else present @projects, with: Entities::ProjectWithAccess, user: current_user From 7b43749e69fac0f50f5b17511c7caf1d819bb767 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 12 Jul 2016 17:53:50 +0800 Subject: [PATCH 102/335] Prefer string for describe as of: https://gitlab.com/gitlab-org/gitlab-ce/blob/b7ba5fa06bfb434c9227a2175f936fc31fd3444f/doc/development/gotchas.md#dont-describe-symbols --- spec/models/project_spec.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 5a27ccbab0a..d2269854354 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -296,7 +296,7 @@ describe Project, models: true do end end - describe :update_merge_requests do + describe '#update_merge_requests' do let(:project) { create(:project) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let(:key) { create(:key, user_id: project.owner.id) } @@ -345,7 +345,7 @@ describe Project, models: true do end end - describe :to_param do + describe '#to_param' do context 'with namespace' do before do @group = create :group, name: 'gitlab' @@ -356,7 +356,7 @@ describe Project, models: true do end end - describe :repository do + describe '#repository' do let(:project) { create(:project) } it 'should return valid repo' do @@ -364,7 +364,7 @@ describe Project, models: true do end end - describe :default_issues_tracker? do + describe '#default_issues_tracker?' do let(:project) { create(:project) } let(:ext_project) { create(:redmine_project) } @@ -377,7 +377,7 @@ describe Project, models: true do end end - describe :external_issue_tracker do + describe '#external_issue_tracker' do let(:project) { create(:project) } let(:ext_project) { create(:redmine_project) } @@ -418,7 +418,7 @@ describe Project, models: true do end end - describe :cache_has_external_issue_tracker do + describe '#cache_has_external_issue_tracker' do let(:project) { create(:project) } it 'stores true if there is any external_issue_tracker' do @@ -440,7 +440,7 @@ describe Project, models: true do end end - describe :open_branches do + describe '#open_branches' do let(:project) { create(:project) } before do @@ -517,7 +517,7 @@ describe Project, models: true do end end - describe :avatar_type do + describe '#avatar_type' do let(:project) { create(:project) } it 'should be true if avatar is image' do @@ -531,7 +531,7 @@ describe Project, models: true do end end - describe :avatar_url do + describe '#avatar_url' do subject { project.avatar_url } let(:project) { create(:project) } @@ -568,7 +568,7 @@ describe Project, models: true do end end - describe :pipeline do + describe '#pipeline' do let(:project) { create :project } let(:pipeline) { create :ci_pipeline, project: project, ref: 'master' } @@ -588,7 +588,7 @@ describe Project, models: true do end end - describe :builds_enabled do + describe '#builds_enabled' do let(:project) { create :project } before { project.builds_enabled = true } @@ -690,7 +690,7 @@ describe Project, models: true do end end - describe :any_runners do + describe '#any_runners' do let(:project) { create(:empty_project, shared_runners_enabled: shared_runners_enabled) } let(:specific_runner) { create(:ci_runner) } let(:shared_runner) { create(:ci_runner, :shared) } From 5d742a308c7b2e79a4da4c209e6c0f401d9921a6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Jul 2016 10:55:18 +0000 Subject: [PATCH 103/335] Improve wording in UI guide --- doc/development/ui_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/development/ui_guide.md b/doc/development/ui_guide.md index 3c44affdd76..8d02c52c477 100644 --- a/doc/development/ui_guide.md +++ b/doc/development/ui_guide.md @@ -27,7 +27,7 @@ We try to keep the amount of tabs in the header navigation between 5 and 10 so t tab should represent separate functionality. Everything related to the issue tracker should be under the 'Issues' tab while everything related to the wiki should be under 'Wiki' tab and so on and so forth. -When add new tab to the header don't use more than 2 words for text in the link. +When adding a new tab to the header don't use more than 2 words for text in the link. We want to keep links short and easy to remember and fit all of them in the small screen. ## Mobile screen size From 3d2c540db6bb33f1a7be6c1ba375d4f604544862 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Tue, 5 Jul 2016 17:21:13 +0200 Subject: [PATCH 104/335] Object renderer read_multi rendered entries from Cache --- CHANGELOG | 1 + lib/banzai.rb | 4 ++ lib/banzai/object_renderer.rb | 23 +++++----- lib/banzai/renderer.rb | 56 ++++++++++++++++++++++++- spec/lib/banzai/object_renderer_spec.rb | 25 +++++++---- 5 files changed, 91 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 84bfc27b151..a5bd9e0daf2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -51,6 +51,7 @@ v 8.10.0 (unreleased) - Don't instantiate a git tree on Projects show default view - Bump Rinku to 2.0.0 - Remove unused front-end variable -> default_issues_tracker + - ObjectRenderer retrieve renderer content using Rails.cache.read_multi - Better caching of git calls on ProjectsController#show. - Avoid to retrieve MR closes_issues as much as possible. - Add API endpoint for a group issues !4520 (mahcsig) diff --git a/lib/banzai.rb b/lib/banzai.rb index 093382261ae..9ebe379f454 100644 --- a/lib/banzai.rb +++ b/lib/banzai.rb @@ -3,6 +3,10 @@ module Banzai Renderer.render(text, context) end + def self.cache_collection_render(texts_and_contexts) + Renderer.cache_collection_render(texts_and_contexts) + end + def self.render_result(text, context = {}) Renderer.render_result(text, context) end diff --git a/lib/banzai/object_renderer.rb b/lib/banzai/object_renderer.rb index dc83b87a6c1..9aef807c152 100644 --- a/lib/banzai/object_renderer.rb +++ b/lib/banzai/object_renderer.rb @@ -39,9 +39,7 @@ module Banzai # Renders the attribute of every given object. def render_objects(objects, attribute) - objects.map do |object| - render_attribute(object, attribute) - end + render_attributes(objects, attribute) end # Redacts the list of documents. @@ -64,16 +62,21 @@ module Banzai context end - # Renders the attribute of an object. + # Renders the attributes of a set of objects. # - # Returns a `Nokogiri::HTML::Document`. - def render_attribute(object, attribute) - context = context_for(object, attribute) + # Returns an Array of `Nokogiri::HTML::Document`. + def render_attributes(objects, attribute) + strings_and_contexts = objects.map do |object| + context = context_for(object, attribute) - string = object.__send__(attribute) - html = Banzai.render(string, context) + string = object.__send__(attribute) - Banzai::Pipeline[:relative_link].to_document(html, context) + { text: string, context: context } + end + + Banzai.cache_collection_render(strings_and_contexts).each_with_index.map do |html, index| + Banzai::Pipeline[:relative_link].to_document(html, strings_and_contexts[index][:context]) + end end def base_context diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb index 6718acdef7e..ea10b06439b 100644 --- a/lib/banzai/renderer.rb +++ b/lib/banzai/renderer.rb @@ -10,7 +10,7 @@ module Banzai # requiring XHTML, such as Atom feeds, need to call `post_process` on the # result, providing the appropriate `pipeline` option. # - # markdown - Markdown String + # text - Markdown String # context - Hash of context options passed to our HTML Pipeline # # Returns an HTML-safe String @@ -29,6 +29,52 @@ module Banzai end end + # Perform multiple render from an Array of Markdown String into an + # Array of HTML-safe String of HTML. + # + # As the rendered Markdown String can be already cached read all the data + # from the cache using Rails.cache.read_multi operation. If the Markdown String + # is not in the cache or it's not cacheable (no cache_key entry is provided in + # the context) the Markdown String is rendered and stored in the cache so the + # next render call gets the rendered HTML-safe String from the cache. + # + # For further explanation see #render method comments. + # + # texts_and_contexts - An Array of Hashes that contains the Markdown String (:text) + # an options passed to our HTML Pipeline (:context) + # + # If on the :context you specify a :cache_key entry will be used to retrieve it + # and cache the result of rendering the Markdown String. + # + # Returns an Array containing HTML-safe String instances. + # + # Example: + # texts_and_contexts + # => [{ text: '### Hello', + # context: { cache_key: [note, :note] } }] + def self.cache_collection_render(texts_and_contexts) + items_collection = texts_and_contexts.each_with_index do |item, index| + context = item[:context] + cache_key = full_cache_multi_key(context.delete(:cache_key), context[:pipeline]) + + item[:cache_key] = cache_key if cache_key + end + + cacheable_items, non_cacheable_items = items_collection.partition { |item| item.key?(:cache_key) } + items_in_cache = Rails.cache.read_multi(*cacheable_items.map { |item| item[:cache_key] }) + items_not_in_cache = cacheable_items.reject do |item| + item[:rendered] = items_in_cache[item[:cache_key]] + items_in_cache.key?(item[:cache_key]) + end + + (items_not_in_cache + non_cacheable_items).each do |item| + item[:rendered] = render(item[:text], item[:context]) + Rails.cache.write(item[:cache_key], item[:rendered]) if item[:cache_key] + end + + items_collection.map { |item| item[:rendered] } + end + def self.render_result(text, context = {}) text = Pipeline[:pre_process].to_html(text, context) if text @@ -78,5 +124,13 @@ module Banzai return unless cache_key ["banzai", *cache_key, pipeline_name || :full] end + + # To map Rails.cache.read_multi results we need to know the Rails.cache.expanded_key. + # Other option will be to generate stringified keys on our side and don't delegate to Rails.cache.expanded_key + # method. + def self.full_cache_multi_key(cache_key, pipeline_name) + return unless cache_key + Rails.cache.send(:expanded_key, full_cache_key(cache_key, pipeline_name)) + end end end diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb index d99175967af..cf6cdd33ebb 100644 --- a/spec/lib/banzai/object_renderer_spec.rb +++ b/spec/lib/banzai/object_renderer_spec.rb @@ -29,7 +29,7 @@ describe Banzai::ObjectRenderer do renderer = described_class.new(project, user) - expect(renderer).to receive(:render_attribute).with(object, :note). + expect(renderer).to receive(:render_attributes).with([object], :note). and_call_original rendered = renderer.render_objects([object], :note) @@ -89,14 +89,25 @@ describe Banzai::ObjectRenderer do end end - describe '#render_attribute' do - it 'renders the attribute of an object' do - object = double(:doc, note: 'hello') + describe '#render_attributes' do + it 'renders the attribute of a list of objects' do + objects = [double(:doc, note: 'hello'), double(:doc, note: 'bye')] renderer = described_class.new(project, user, pipeline: :note) - doc = renderer.render_attribute(object, :note) - expect(doc).to be_an_instance_of(Nokogiri::HTML::DocumentFragment) - expect(doc.to_html).to eq('

    hello

    ') + expect(Banzai).to receive(:cache_collection_render). + with([ + { text: 'hello', context: renderer.context_for(objects[0], :note) }, + { text: 'bye', context: renderer.context_for(objects[1], :note) } + ]). + and_call_original + + docs = renderer.render_attributes(objects, :note) + + expect(docs[0]).to be_an_instance_of(Nokogiri::HTML::DocumentFragment) + expect(docs[0].to_html).to eq('

    hello

    ') + + expect(docs[1]).to be_an_instance_of(Nokogiri::HTML::DocumentFragment) + expect(docs[1].to_html).to eq('

    bye

    ') end end From f1f9b5e2f0f7ab8515f263b79c09d9f98b0d302f Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Tue, 12 Jul 2016 14:29:26 +0200 Subject: [PATCH 105/335] Be explicit on merge request discussion variables --- CHANGELOG | 1 + .../projects/merge_requests_controller.rb | 25 +++++++++++-------- spec/features/merge_requests/diffs_spec.rb | 25 +++++++++++++++++++ 3 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 spec/features/merge_requests/diffs_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 84bfc27b151..6c9affcdf1d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -56,6 +56,7 @@ v 8.10.0 (unreleased) - Add API endpoint for a group issues !4520 (mahcsig) - Add Bugzilla integration !4930 (iamtjg) - Instrument Rinku usage + - Be explicit to define merge request discussion variables - Metrics for Rouge::Plugins::Redcarpet and Rouge::Formatters::HTMLGitlab - RailsCache metris now includes fetch_hit/fetch_miss and read_hit/read_miss info. - Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 941d68cda17..df659bb8c3b 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -56,7 +56,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController def show respond_to do |format| - format.html + format.html { define_discussion_vars } format.json do render json: @merge_request @@ -82,7 +82,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request_diff = @merge_request.merge_request_diff respond_to do |format| - format.html + format.html { define_discussion_vars } format.json { render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") } } end end @@ -108,7 +108,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController def commits respond_to do |format| - format.html { render 'show' } + format.html do + define_discussion_vars + + render 'show' + end format.json do # Get commits from repository # or from cache if already merged @@ -123,7 +127,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController def builds respond_to do |format| - format.html { render 'show' } + format.html do + define_discussion_vars + + render 'show' + end format.json { render json: { html: view_to_html_string('projects/merge_requests/show/_builds') } } end end @@ -353,14 +361,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request.unlock_mr @merge_request.close end - - if request.format == :html || action_name == 'show' - define_show_html_vars - end end - # Discussion tab data is only required on html requests - def define_show_html_vars + # Discussion tab data is rendered on html responses of actions + # :show, :diff, :commits, :builds. but not when request the data through AJAX + def define_discussion_vars # Build a note object for comment form @note = @project.notes.new(noteable: @noteable) diff --git a/spec/features/merge_requests/diffs_spec.rb b/spec/features/merge_requests/diffs_spec.rb new file mode 100644 index 00000000000..c9a0059645d --- /dev/null +++ b/spec/features/merge_requests/diffs_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +feature 'Diffs URL', js: true, feature: true do + before do + login_as :admin + @merge_request = create(:merge_request) + @project = @merge_request.source_project + end + + context 'when visit with */* as accept header' do + before(:each) do + page.driver.add_header('Accept', '*/*') + end + + it 'renders the notes' do + create :note_on_merge_request, project: @project, noteable: @merge_request, note: 'Rebasing with master' + + visit diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request) + + # Load notes and diff through AJAX + expect(page).to have_css('.note-text', visible: false, text: 'Rebasing with master') + expect(page).to have_css('.diffs.tab-pane.active') + end + end +end From 3dc6bf2b71f995a3b6ca40ebbf9abb5c11397b8b Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 8 Jul 2016 12:32:58 -0700 Subject: [PATCH 106/335] Expire the branch cache after `git gc` runs Due to a stale NFS cache, it's possible that a branch lookup fails while `git gc` is running and causes missing branches in merge requests. Possible workaround for #15392 --- CHANGELOG | 1 + app/services/projects/housekeeping_service.rb | 4 +--- app/workers/git_garbage_collect_worker.rb | 14 +++++++++++ app/workers/gitlab_shell_one_shot_worker.rb | 10 -------- .../projects/housekeeping_service_spec.rb | 4 ++-- .../git_garbage_collect_worker_spec.rb | 24 +++++++++++++++++++ 6 files changed, 42 insertions(+), 15 deletions(-) create mode 100644 app/workers/git_garbage_collect_worker.rb delete mode 100644 app/workers/gitlab_shell_one_shot_worker.rb create mode 100644 spec/workers/git_garbage_collect_worker_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 84bfc27b151..d77d02f82c3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ v 8.10.0 (unreleased) - Expose {should,force}_remove_source_branch (Ben Boeckel) - Fix commit builds API, return all builds for all pipelines for given commit. !4849 - Replace Haml with Hamlit to make view rendering faster. !3666 + - Expire the branch cache after `git gc` runs - Refactor repository paths handling to allow multiple git mount points - Optimize system note visibility checking by memoizing the visible reference count !5070 - Add Application Setting to configure default Repository Path for new projects diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb index 752c11d7ae6..c9ad710b7bf 100644 --- a/app/services/projects/housekeeping_service.rb +++ b/app/services/projects/housekeeping_service.rb @@ -7,8 +7,6 @@ # module Projects class HousekeepingService < BaseService - include Gitlab::ShellAdapter - LEASE_TIMEOUT = 3600 class LeaseTaken < StandardError @@ -24,7 +22,7 @@ module Projects def execute raise LeaseTaken unless try_obtain_lease - GitlabShellOneShotWorker.perform_async(:gc, @project.repository_storage_path, @project.path_with_namespace) + GitGarbageCollectWorker.perform_async(@project.id) ensure Gitlab::Metrics.measure(:reset_pushes_since_gc) do update_pushes_since_gc(0) diff --git a/app/workers/git_garbage_collect_worker.rb b/app/workers/git_garbage_collect_worker.rb new file mode 100644 index 00000000000..2fa3c838f55 --- /dev/null +++ b/app/workers/git_garbage_collect_worker.rb @@ -0,0 +1,14 @@ +class GitGarbageCollectWorker + include Sidekiq::Worker + include Gitlab::ShellAdapter + + sidekiq_options queue: :gitlab_shell, retry: false + + def perform(project_id) + project = Project.find(project_id) + + gitlab_shell.gc(project.repository_storage_path, project.path_with_namespace) + # Expire the branch cache in case garbage collection caused a ref lookup to fail + project.repository.after_create_branch + end +end diff --git a/app/workers/gitlab_shell_one_shot_worker.rb b/app/workers/gitlab_shell_one_shot_worker.rb deleted file mode 100644 index 4ddbcf574d5..00000000000 --- a/app/workers/gitlab_shell_one_shot_worker.rb +++ /dev/null @@ -1,10 +0,0 @@ -class GitlabShellOneShotWorker - include Sidekiq::Worker - include Gitlab::ShellAdapter - - sidekiq_options queue: :gitlab_shell, retry: false - - def perform(action, *arg) - gitlab_shell.send(action, *arg) - end -end diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb index bd4dc6a0f79..7ab95e042ce 100644 --- a/spec/services/projects/housekeeping_service_spec.rb +++ b/spec/services/projects/housekeeping_service_spec.rb @@ -12,7 +12,7 @@ describe Projects::HousekeepingService do it 'enqueues a sidekiq job' do expect(subject).to receive(:try_obtain_lease).and_return(true) - expect(GitlabShellOneShotWorker).to receive(:perform_async).with(:gc, project.repository_storage_path, project.path_with_namespace) + expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id) subject.execute expect(project.pushes_since_gc).to eq(0) @@ -20,7 +20,7 @@ describe Projects::HousekeepingService do it 'does not enqueue a job when no lease can be obtained' do expect(subject).to receive(:try_obtain_lease).and_return(false) - expect(GitlabShellOneShotWorker).not_to receive(:perform_async) + expect(GitGarbageCollectWorker).not_to receive(:perform_async) expect { subject.execute }.to raise_error(Projects::HousekeepingService::LeaseTaken) expect(project.pushes_since_gc).to eq(0) diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb new file mode 100644 index 00000000000..a9cce8b8b59 --- /dev/null +++ b/spec/workers/git_garbage_collect_worker_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +describe GitGarbageCollectWorker do + let(:project) { create(:project) } + let(:shell) { Gitlab::Shell.new } + + subject { GitGarbageCollectWorker.new } + + before do + allow(subject).to receive(:gitlab_shell).and_return(shell) + end + + describe "#perform" do + it "runs `git gc`" do + expect(shell).to receive(:gc).with( + project.repository_storage_path, + project.path_with_namespace). + and_return(true) + expect_any_instance_of(Repository).to receive(:after_create_branch) + + subject.perform(project.id) + end + end +end From d6e43f1f76f63d0a9e7ffe2b2130105c86b7a9fa Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Jul 2016 13:52:24 +0000 Subject: [PATCH 107/335] Update Access Tokens link title to match the text --- app/views/layouts/nav/_profile.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml index 6e3c9ab9778..6d514f669db 100644 --- a/app/views/layouts/nav/_profile.html.haml +++ b/app/views/layouts/nav/_profile.html.haml @@ -18,7 +18,7 @@ %span Applications = nav_link(controller: :personal_access_tokens) do - = link_to profile_personal_access_tokens_path, title: 'Personal Access Tokens' do + = link_to profile_personal_access_tokens_path, title: 'Access Tokens' do %span Access Tokens = nav_link(controller: :emails) do From 0736397e0849333053390a24aa3938cda45707cf Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Tue, 12 Jul 2016 11:58:06 +0200 Subject: [PATCH 108/335] Reset project pushes_since_gc when we enqueue the git gc call --- CHANGELOG | 1 + app/services/projects/housekeeping_service.rb | 24 ++++++----- .../projects/housekeeping_service_spec.rb | 42 +++++++++++++++---- 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ee3ee4c37d6..2527290f0fd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -75,6 +75,7 @@ v 8.10.0 (unreleased) - Fix 404 redirect after validation fails importing a GitLab project - Added setting to set new users by default as external !4545 (Dravere) - Add min value for project limit field on user's form !3622 (jastkand) + - Reset project pushes_since_gc when we enqueue the git gc call - Add reminder to not paste private SSH keys !4399 (Ingo Blechschmidt) - Remove duplicate `description` field in `MergeRequest` entities (Ben Boeckel) - Style of import project buttons were fixed in the new project page. !5183 (rdemirbay) diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb index c9ad710b7bf..29b3981f49f 100644 --- a/app/services/projects/housekeeping_service.rb +++ b/app/services/projects/housekeeping_service.rb @@ -22,11 +22,7 @@ module Projects def execute raise LeaseTaken unless try_obtain_lease - GitGarbageCollectWorker.perform_async(@project.id) - ensure - Gitlab::Metrics.measure(:reset_pushes_since_gc) do - update_pushes_since_gc(0) - end + execute_gitlab_shell_gc end def needed? @@ -34,19 +30,27 @@ module Projects end def increment! - Gitlab::Metrics.measure(:increment_pushes_since_gc) do - update_pushes_since_gc(@project.pushes_since_gc + 1) + if Gitlab::ExclusiveLease.new("project_housekeeping:increment!:#{@project.id}", timeout: 60).try_obtain + Gitlab::Metrics.measure(:increment_pushes_since_gc) do + update_pushes_since_gc(@project.pushes_since_gc + 1) + end end end private - def update_pushes_since_gc(new_value) - if Gitlab::ExclusiveLease.new("project_housekeeping:update_pushes_since_gc:#{project.id}", timeout: 60).try_obtain - @project.update_column(:pushes_since_gc, new_value) + def execute_gitlab_shell_gc + GitGarbageCollectWorker.perform_async(@project.id) + ensure + Gitlab::Metrics.measure(:reset_pushes_since_gc) do + update_pushes_since_gc(0) end end + def update_pushes_since_gc(new_value) + @project.update_column(:pushes_since_gc, new_value) + end + def try_obtain_lease Gitlab::Metrics.measure(:obtain_housekeeping_lease) do lease = ::Gitlab::ExclusiveLease.new("project_housekeeping:#{@project.id}", timeout: LEASE_TIMEOUT) diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb index 7ab95e042ce..ad0d58672b3 100644 --- a/spec/services/projects/housekeeping_service_spec.rb +++ b/spec/services/projects/housekeeping_service_spec.rb @@ -15,15 +15,25 @@ describe Projects::HousekeepingService do expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id) subject.execute - expect(project.pushes_since_gc).to eq(0) + expect(project.reload.pushes_since_gc).to eq(0) end - it 'does not enqueue a job when no lease can be obtained' do - expect(subject).to receive(:try_obtain_lease).and_return(false) - expect(GitGarbageCollectWorker).not_to receive(:perform_async) + context 'when no lease can be obtained' do + before(:each) do + expect(subject).to receive(:try_obtain_lease).and_return(false) + end - expect { subject.execute }.to raise_error(Projects::HousekeepingService::LeaseTaken) - expect(project.pushes_since_gc).to eq(0) + it 'does not enqueue a job' do + expect(GitGarbageCollectWorker).not_to receive(:perform_async) + + expect { subject.execute }.to raise_error(Projects::HousekeepingService::LeaseTaken) + end + + it 'does not reset pushes_since_gc' do + expect do + expect { subject.execute }.to raise_error(Projects::HousekeepingService::LeaseTaken) + end.not_to change { project.pushes_since_gc }.from(3) + end end end @@ -39,10 +49,24 @@ describe Projects::HousekeepingService do end describe 'increment!' do + let(:lease_key) { "project_housekeeping:increment!:#{project.id}" } + it 'increments the pushes_since_gc counter' do - expect(project.pushes_since_gc).to eq(0) - subject.increment! - expect(project.pushes_since_gc).to eq(1) + lease = double(:lease, try_obtain: true) + expect(Gitlab::ExclusiveLease).to receive(:new).with(lease_key, anything).and_return(lease) + + expect do + subject.increment! + end.to change { project.pushes_since_gc }.from(0).to(1) + end + + it 'does not increment when no lease can be obtained' do + lease = double(:lease, try_obtain: false) + expect(Gitlab::ExclusiveLease).to receive(:new).with(lease_key, anything).and_return(lease) + + expect do + subject.increment! + end.not_to change { project.pushes_since_gc } end end end From 20d8de8f673e040282ad0811fb8af8fa97aa3e92 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 12 Jul 2016 22:17:00 +0800 Subject: [PATCH 109/335] We're not using them (and look at the typo) --- spec/spec_helper.rb | 1 - spec/support/relative_url.rb | 8 -------- 2 files changed, 9 deletions(-) delete mode 100644 spec/support/relative_url.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 606da1b7605..3638dcbb2d3 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -33,7 +33,6 @@ RSpec.configure do |config| config.include LoginHelpers, type: :request config.include StubConfiguration config.include EmailHelpers - config.include RelativeUrl, type: feature config.include TestEnv config.include ActiveJob::TestHelper config.include StubGitlabCalls diff --git a/spec/support/relative_url.rb b/spec/support/relative_url.rb deleted file mode 100644 index 72e3ccce75b..00000000000 --- a/spec/support/relative_url.rb +++ /dev/null @@ -1,8 +0,0 @@ -# Fix route helpers in tests (e.g. root_path, ...) -module RelativeUrl - extend ActiveSupport::Concern - - included do - default_url_options[:script_name] = Rails.application.config.relative_url_root - end -end From ad6ff2238045d6b7873144eb302aa953c9f1fc66 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 12 Jul 2016 16:21:28 +0200 Subject: [PATCH 110/335] fixes a few issues to do with import_url not being saved correctly for imports. This should prevent the import_data to be created when it should not and output an error properly validating before creating it. --- app/models/project.rb | 4 ++-- app/services/projects/import_service.rb | 2 +- spec/models/project_spec.rb | 22 ++++++++++++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index a66b750cd48..57ea948390b 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -162,7 +162,7 @@ class Project < ActiveRecord::Base validates :namespace, presence: true validates_uniqueness_of :name, scope: :namespace_id validates_uniqueness_of :path, scope: :namespace_id - validates :import_url, addressable_url: true, if: :external_import? + validates :import_url, addressable_url: true, if: :import_url validates :star_count, numericality: { greater_than_or_equal_to: 0 } validate :check_limit, on: :create validate :avatar_type, @@ -464,8 +464,8 @@ class Project < ActiveRecord::Base return super(value) unless Gitlab::UrlSanitizer.valid?(value) import_url = Gitlab::UrlSanitizer.new(value) - create_or_update_import_data(credentials: import_url.credentials) super(import_url.sanitized_url) + create_or_update_import_data(credentials: import_url.credentials) if valid? end def import_url diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb index 163ebf26c84..cdad0426b02 100644 --- a/app/services/projects/import_service.rb +++ b/app/services/projects/import_service.rb @@ -43,7 +43,7 @@ module Projects def import_repository begin gitlab_shell.import_repository(project.repository_storage_path, project.path_with_namespace, project.import_url) - rescue Gitlab::Shell::Error => e + rescue => e raise Error, "Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}" end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 5a27ccbab0a..d6bb8d0d54f 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -130,17 +130,35 @@ describe Project, models: true do end end - it 'should not allow an invalid URI as import_url' do + it 'does not allow an invalid URI as import_url' do project2 = build(:project, import_url: 'invalid://') expect(project2).not_to be_valid end - it 'should allow a valid URI as import_url' do + it 'does allow a valid URI as import_url' do project2 = build(:project, import_url: 'ssh://test@gitlab.com/project.git') expect(project2).to be_valid end + + it 'does not allow to introduce an empty URI' do + project2 = build(:project, import_url: '') + + expect(project2).not_to be_valid + end + + it 'does not produce import data on an empty URI' do + project2 = build(:project, import_url: '') + + expect(project2.import_data).to be_nil + end + + it 'does not produce import data on an invalid URI' do + project2 = build(:project, import_url: 'test://') + + expect(project2.import_data).to be_nil + end end describe 'default_scope' do From 3d1a75781260d394a13a30e0d267bcd79f3015dd Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 12 Jul 2016 17:35:39 +0300 Subject: [PATCH 111/335] Small refactor and addition of CI permissions --- doc/permissions/permissions.md | 53 +++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md index 44f3f6d3b12..8fc10a13f91 100644 --- a/doc/permissions/permissions.md +++ b/doc/permissions/permissions.md @@ -1,19 +1,21 @@ # Permissions -Users have different abilities depending on the access level they have in a particular group or project. +Users have different abilities depending on the access level they have in a +particular group or project. If a user is both in a group's project and the +project itself, the highest permission level is used. -If a user is both in a project group and in the project itself, the highest permission level is used. +On public and internal projects the Guest role is not enforced. All users will +be able to create issues, leave comments, and pull or download the project code. -If a user is a GitLab administrator they receive all permissions. - -On public and internal projects the Guest role is not enforced. -All users will be able to create issues, leave comments, and pull or download the project code. +GitLab administrators receive all permissions. To add or import a user, you can follow the [project users and members documentation](../workflow/add-user/add-user.md). ## Project +The following table depicts the various user permission levels in a project. + | Action | Guest | Reporter | Developer | Master | Owner | |---------------------------------------|---------|------------|-------------|----------|--------| | Create new issue | ✓ | ✓ | ✓ | ✓ | ✓ | @@ -46,8 +48,8 @@ documentation](../workflow/add-user/add-user.md). | Add new team members | | | | ✓ | ✓ | | Push to protected branches | | | | ✓ | ✓ | | Enable/disable branch protection | | | | ✓ | ✓ | -| Turn on/off prot. branch push for devs| | | | ✓ | ✓ | -| Rewrite/remove git tags | | | | ✓ | ✓ | +| Turn on/off protected branch push for devs| | | | ✓ | ✓ | +| Rewrite/remove Git tags | | | | ✓ | ✓ | | Edit project | | | | ✓ | ✓ | | Add deploy keys to project | | | | ✓ | ✓ | | Configure project hooks | | | | ✓ | ✓ | @@ -66,10 +68,9 @@ documentation](../workflow/add-user/add-user.md). ## Group -In order for a group to appear as public and be browsable, it must contain at -least one public project. - -Any user can remove themselves from a group, unless they are the last Owner of the group. +Any user can remove themselves from a group, unless they are the last Owner of +the group. The following table depicts the various user permission levels in a +group. | Action | Guest | Reporter | Developer | Master | Owner | |-------------------------|-------|----------|-----------|--------|-------| @@ -101,4 +102,30 @@ to **Admin > Users** to create a new user or edit an existing one. There, you will find the option to flag the user as external. By default new users are not set as external users. This behavior can be changed -by an administrator under **Admin > Application Settings**. \ No newline at end of file +by an administrator under **Admin > Application Settings**. + +## GitLab CI + +GitLab CI permissions rely on the role the user has in GitLab. There are four +permission levels it total: + +- admin +- master +- developer +- guest/reporter + +The admin user can perform any action on GitLab CI in scope of the GitLab +instance and project. In addition, all admins can use the admin interface under +`/admin/runners`. + +| Action | Guest, Reporter | Developer | Master | Admin | +|---------------------------------------|-----------------|-------------|----------|--------| +| See commits and builds | ✓ | ✓ | ✓ | ✓ | +| Retry or cancel build | | ✓ | ✓ | ✓ | +| Remove project | | | ✓ | ✓ | +| Create project | | | ✓ | ✓ | +| Change project configuration | | | ✓ | ✓ | +| Add specific runners | | | ✓ | ✓ | +| Add shared runners | | | | ✓ | +| See events in the system | | | | ✓ | +| Admin interface | | | | ✓ | From 429ab4a0b7683dd2e855e0299907ef9061f1c654 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Mon, 11 Jul 2016 16:29:25 -0600 Subject: [PATCH 112/335] Remove the group avatar link. For group pages, e.g. https://gitlab.com/groups/gitlab-org, I see no reason to link to the avatar image itself when clicking on the avatar. If the user really wants to open the image, they can do so by right clicking and opening the image in a new tab. --- app/views/groups/show.html.haml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index a83eb7e88bb..eddeae98bc4 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -6,8 +6,7 @@ .cover-block.groups-cover-block %div{ class: container_class } - = link_to group_icon(@group), target: '_blank' do - = image_tag group_icon(@group), class: "avatar group-avatar s70" + = image_tag group_icon(@group), class: "avatar group-avatar s70" .group-info .cover-title %h1 From da42b1bb5345ce8b890b1d27bc3a62d339323c84 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 12 Jul 2016 15:46:28 +0100 Subject: [PATCH 113/335] Added author username tooltip in issuable header Closes #13771 --- app/helpers/issuables_helper.rb | 2 +- app/helpers/projects_helper.rb | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 294b7e92b8d..47d174361db 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -61,7 +61,7 @@ module IssuablesHelper output = content_tag :strong, "#{text} #{issuable.to_reference}", class: "identifier" output << " opened #{time_ago_with_tooltip(issuable.created_at)} by ".html_safe output << content_tag(:strong) do - author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "hidden-xs") + author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "hidden-xs", tooltip: true) author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "hidden-sm hidden-md hidden-lg") end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 3bbbb26cff2..e64aa56d5e4 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -19,7 +19,7 @@ module ProjectsHelper end def link_to_member(project, author, opts = {}, &block) - default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name" } + default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name", tooltip: false } opts = default_opts.merge(opts) return "(deleted)" unless author @@ -33,7 +33,9 @@ module ProjectsHelper if opts[:by_username] author_html << content_tag(:span, sanitize("@#{author.username}"), class: opts[:author_class]) if opts[:name] else - author_html << content_tag(:span, sanitize(author.name), class: opts[:author_class]) if opts[:name] + tooltip_data = { placement: 'top' } + author_html << content_tag(:span, sanitize(author.name), class: [opts[:author_class], ('has-tooltip' if opts[:tooltip])], + title: (author.to_reference if opts[:tooltip]), data: (tooltip_data if opts[:tooltip])) if opts[:name] end author_html << capture(&block) if block From 1d849129f73f72e3f8693f9f2a8267e228f2b9e2 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 12 Jul 2016 16:48:56 +0200 Subject: [PATCH 114/335] added changelog --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index aed0d041ea6..2b68226a054 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -74,6 +74,9 @@ v 8.10.0 (unreleased) - Add reminder to not paste private SSH keys !4399 (Ingo Blechschmidt) - Remove duplicate `description` field in `MergeRequest` entities (Ben Boeckel) +v 8.9.7 (unreleased) + - Fix import_data wrongly saved as a result of an invalid import_url + v 8.9.6 (unreleased) - Fix importing of events under notes for GitLab projects From c6735f9f2068ba618165d8719405eda7899fa772 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 12 Jul 2016 17:49:03 +0300 Subject: [PATCH 115/335] Move permissions/permissions.md to user/permissions.md --- doc/permissions/permissions.md | 130 +------------------------------- doc/user/permissions.md | 131 +++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 129 deletions(-) create mode 100644 doc/user/permissions.md diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md index 8fc10a13f91..78d67aeec78 100644 --- a/doc/permissions/permissions.md +++ b/doc/permissions/permissions.md @@ -1,131 +1,3 @@ # Permissions -Users have different abilities depending on the access level they have in a -particular group or project. If a user is both in a group's project and the -project itself, the highest permission level is used. - -On public and internal projects the Guest role is not enforced. All users will -be able to create issues, leave comments, and pull or download the project code. - -GitLab administrators receive all permissions. - -To add or import a user, you can follow the [project users and members -documentation](../workflow/add-user/add-user.md). - -## Project - -The following table depicts the various user permission levels in a project. - -| Action | Guest | Reporter | Developer | Master | Owner | -|---------------------------------------|---------|------------|-------------|----------|--------| -| Create new issue | ✓ | ✓ | ✓ | ✓ | ✓ | -| Leave comments | ✓ | ✓ | ✓ | ✓ | ✓ | -| See a list of builds | ✓ [^1] | ✓ | ✓ | ✓ | ✓ | -| See a build log | ✓ [^1] | ✓ | ✓ | ✓ | ✓ | -| Download and browse build artifacts | ✓ [^1] | ✓ | ✓ | ✓ | ✓ | -| Pull project code | | ✓ | ✓ | ✓ | ✓ | -| Download project | | ✓ | ✓ | ✓ | ✓ | -| Create code snippets | | ✓ | ✓ | ✓ | ✓ | -| Manage issue tracker | | ✓ | ✓ | ✓ | ✓ | -| Manage labels | | ✓ | ✓ | ✓ | ✓ | -| See a commit status | | ✓ | ✓ | ✓ | ✓ | -| See a container registry | | ✓ | ✓ | ✓ | ✓ | -| See environments | | ✓ | ✓ | ✓ | ✓ | -| Manage merge requests | | | ✓ | ✓ | ✓ | -| Create new merge request | | | ✓ | ✓ | ✓ | -| Create new branches | | | ✓ | ✓ | ✓ | -| Push to non-protected branches | | | ✓ | ✓ | ✓ | -| Force push to non-protected branches | | | ✓ | ✓ | ✓ | -| Remove non-protected branches | | | ✓ | ✓ | ✓ | -| Add tags | | | ✓ | ✓ | ✓ | -| Write a wiki | | | ✓ | ✓ | ✓ | -| Cancel and retry builds | | | ✓ | ✓ | ✓ | -| Create or update commit status | | | ✓ | ✓ | ✓ | -| Update a container registry | | | ✓ | ✓ | ✓ | -| Remove a container registry image | | | ✓ | ✓ | ✓ | -| Create new environments | | | ✓ | ✓ | ✓ | -| Create new milestones | | | | ✓ | ✓ | -| Add new team members | | | | ✓ | ✓ | -| Push to protected branches | | | | ✓ | ✓ | -| Enable/disable branch protection | | | | ✓ | ✓ | -| Turn on/off protected branch push for devs| | | | ✓ | ✓ | -| Rewrite/remove Git tags | | | | ✓ | ✓ | -| Edit project | | | | ✓ | ✓ | -| Add deploy keys to project | | | | ✓ | ✓ | -| Configure project hooks | | | | ✓ | ✓ | -| Manage runners | | | | ✓ | ✓ | -| Manage build triggers | | | | ✓ | ✓ | -| Manage variables | | | | ✓ | ✓ | -| Delete environments | | | | ✓ | ✓ | -| Switch visibility level | | | | | ✓ | -| Transfer project to another namespace | | | | | ✓ | -| Remove project | | | | | ✓ | -| Force push to protected branches [^2] | | | | | | -| Remove protected branches [^2] | | | | | | - -[^1]: If **Allow guest to access builds** is enabled in CI settings -[^2]: Not allowed for Guest, Reporter, Developer, Master, or Owner - -## Group - -Any user can remove themselves from a group, unless they are the last Owner of -the group. The following table depicts the various user permission levels in a -group. - -| Action | Guest | Reporter | Developer | Master | Owner | -|-------------------------|-------|----------|-----------|--------|-------| -| Browse group | ✓ | ✓ | ✓ | ✓ | ✓ | -| Edit group | | | | | ✓ | -| Create project in group | | | | ✓ | ✓ | -| Manage group members | | | | | ✓ | -| Remove group | | | | | ✓ | - -## External Users - -In cases where it is desired that a user has access only to some internal or -private projects, there is the option of creating **External Users**. This -feature may be useful when for example a contractor is working on a given -project and should only have access to that project. - -External users can only access projects to which they are explicitly granted -access, thus hiding all other internal or private ones from them. Access can be -granted by adding the user as member to the project or group. - -They will, like usual users, receive a role in the project or group with all -the abilities that are mentioned in the table above. They cannot however create -groups or projects, and they have the same access as logged out users in all -other cases. - -An administrator can flag a user as external [through the API](../api/users.md) -or by checking the checkbox on the admin panel. As an administrator, navigate -to **Admin > Users** to create a new user or edit an existing one. There, you -will find the option to flag the user as external. - -By default new users are not set as external users. This behavior can be changed -by an administrator under **Admin > Application Settings**. - -## GitLab CI - -GitLab CI permissions rely on the role the user has in GitLab. There are four -permission levels it total: - -- admin -- master -- developer -- guest/reporter - -The admin user can perform any action on GitLab CI in scope of the GitLab -instance and project. In addition, all admins can use the admin interface under -`/admin/runners`. - -| Action | Guest, Reporter | Developer | Master | Admin | -|---------------------------------------|-----------------|-------------|----------|--------| -| See commits and builds | ✓ | ✓ | ✓ | ✓ | -| Retry or cancel build | | ✓ | ✓ | ✓ | -| Remove project | | | ✓ | ✓ | -| Create project | | | ✓ | ✓ | -| Change project configuration | | | ✓ | ✓ | -| Add specific runners | | | ✓ | ✓ | -| Add shared runners | | | | ✓ | -| See events in the system | | | | ✓ | -| Admin interface | | | | ✓ | +This document was moved to [user/permissions.md](../user/permissions.md). diff --git a/doc/user/permissions.md b/doc/user/permissions.md new file mode 100644 index 00000000000..8fc10a13f91 --- /dev/null +++ b/doc/user/permissions.md @@ -0,0 +1,131 @@ +# Permissions + +Users have different abilities depending on the access level they have in a +particular group or project. If a user is both in a group's project and the +project itself, the highest permission level is used. + +On public and internal projects the Guest role is not enforced. All users will +be able to create issues, leave comments, and pull or download the project code. + +GitLab administrators receive all permissions. + +To add or import a user, you can follow the [project users and members +documentation](../workflow/add-user/add-user.md). + +## Project + +The following table depicts the various user permission levels in a project. + +| Action | Guest | Reporter | Developer | Master | Owner | +|---------------------------------------|---------|------------|-------------|----------|--------| +| Create new issue | ✓ | ✓ | ✓ | ✓ | ✓ | +| Leave comments | ✓ | ✓ | ✓ | ✓ | ✓ | +| See a list of builds | ✓ [^1] | ✓ | ✓ | ✓ | ✓ | +| See a build log | ✓ [^1] | ✓ | ✓ | ✓ | ✓ | +| Download and browse build artifacts | ✓ [^1] | ✓ | ✓ | ✓ | ✓ | +| Pull project code | | ✓ | ✓ | ✓ | ✓ | +| Download project | | ✓ | ✓ | ✓ | ✓ | +| Create code snippets | | ✓ | ✓ | ✓ | ✓ | +| Manage issue tracker | | ✓ | ✓ | ✓ | ✓ | +| Manage labels | | ✓ | ✓ | ✓ | ✓ | +| See a commit status | | ✓ | ✓ | ✓ | ✓ | +| See a container registry | | ✓ | ✓ | ✓ | ✓ | +| See environments | | ✓ | ✓ | ✓ | ✓ | +| Manage merge requests | | | ✓ | ✓ | ✓ | +| Create new merge request | | | ✓ | ✓ | ✓ | +| Create new branches | | | ✓ | ✓ | ✓ | +| Push to non-protected branches | | | ✓ | ✓ | ✓ | +| Force push to non-protected branches | | | ✓ | ✓ | ✓ | +| Remove non-protected branches | | | ✓ | ✓ | ✓ | +| Add tags | | | ✓ | ✓ | ✓ | +| Write a wiki | | | ✓ | ✓ | ✓ | +| Cancel and retry builds | | | ✓ | ✓ | ✓ | +| Create or update commit status | | | ✓ | ✓ | ✓ | +| Update a container registry | | | ✓ | ✓ | ✓ | +| Remove a container registry image | | | ✓ | ✓ | ✓ | +| Create new environments | | | ✓ | ✓ | ✓ | +| Create new milestones | | | | ✓ | ✓ | +| Add new team members | | | | ✓ | ✓ | +| Push to protected branches | | | | ✓ | ✓ | +| Enable/disable branch protection | | | | ✓ | ✓ | +| Turn on/off protected branch push for devs| | | | ✓ | ✓ | +| Rewrite/remove Git tags | | | | ✓ | ✓ | +| Edit project | | | | ✓ | ✓ | +| Add deploy keys to project | | | | ✓ | ✓ | +| Configure project hooks | | | | ✓ | ✓ | +| Manage runners | | | | ✓ | ✓ | +| Manage build triggers | | | | ✓ | ✓ | +| Manage variables | | | | ✓ | ✓ | +| Delete environments | | | | ✓ | ✓ | +| Switch visibility level | | | | | ✓ | +| Transfer project to another namespace | | | | | ✓ | +| Remove project | | | | | ✓ | +| Force push to protected branches [^2] | | | | | | +| Remove protected branches [^2] | | | | | | + +[^1]: If **Allow guest to access builds** is enabled in CI settings +[^2]: Not allowed for Guest, Reporter, Developer, Master, or Owner + +## Group + +Any user can remove themselves from a group, unless they are the last Owner of +the group. The following table depicts the various user permission levels in a +group. + +| Action | Guest | Reporter | Developer | Master | Owner | +|-------------------------|-------|----------|-----------|--------|-------| +| Browse group | ✓ | ✓ | ✓ | ✓ | ✓ | +| Edit group | | | | | ✓ | +| Create project in group | | | | ✓ | ✓ | +| Manage group members | | | | | ✓ | +| Remove group | | | | | ✓ | + +## External Users + +In cases where it is desired that a user has access only to some internal or +private projects, there is the option of creating **External Users**. This +feature may be useful when for example a contractor is working on a given +project and should only have access to that project. + +External users can only access projects to which they are explicitly granted +access, thus hiding all other internal or private ones from them. Access can be +granted by adding the user as member to the project or group. + +They will, like usual users, receive a role in the project or group with all +the abilities that are mentioned in the table above. They cannot however create +groups or projects, and they have the same access as logged out users in all +other cases. + +An administrator can flag a user as external [through the API](../api/users.md) +or by checking the checkbox on the admin panel. As an administrator, navigate +to **Admin > Users** to create a new user or edit an existing one. There, you +will find the option to flag the user as external. + +By default new users are not set as external users. This behavior can be changed +by an administrator under **Admin > Application Settings**. + +## GitLab CI + +GitLab CI permissions rely on the role the user has in GitLab. There are four +permission levels it total: + +- admin +- master +- developer +- guest/reporter + +The admin user can perform any action on GitLab CI in scope of the GitLab +instance and project. In addition, all admins can use the admin interface under +`/admin/runners`. + +| Action | Guest, Reporter | Developer | Master | Admin | +|---------------------------------------|-----------------|-------------|----------|--------| +| See commits and builds | ✓ | ✓ | ✓ | ✓ | +| Retry or cancel build | | ✓ | ✓ | ✓ | +| Remove project | | | ✓ | ✓ | +| Create project | | | ✓ | ✓ | +| Change project configuration | | | ✓ | ✓ | +| Add specific runners | | | ✓ | ✓ | +| Add shared runners | | | | ✓ | +| See events in the system | | | | ✓ | +| Admin interface | | | | ✓ | From 523168c8bf29e0219620acce96ea07cadfdfcb13 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 12 Jul 2016 17:52:48 +0300 Subject: [PATCH 116/335] Move CI permissions to permissions.md --- doc/ci/README.md | 2 +- doc/ci/permissions/README.md | 23 +---------------------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/doc/ci/README.md b/doc/ci/README.md index a9d407528e8..0833027f91d 100644 --- a/doc/ci/README.md +++ b/doc/ci/README.md @@ -15,6 +15,6 @@ - [Use SSH keys in your build environment](ssh_keys/README.md) - [Trigger builds through the API](triggers/README.md) - [Build artifacts](build_artifacts/README.md) -- [User permissions](permissions/README.md) +- [User permissions](../user/permissions.md#gitlab-ci) - [API](../api/ci/README.md) - [CI services (linked docker containers)](services/README.md) diff --git a/doc/ci/permissions/README.md b/doc/ci/permissions/README.md index d77061c14cd..42eb59f84c8 100644 --- a/doc/ci/permissions/README.md +++ b/doc/ci/permissions/README.md @@ -1,24 +1,3 @@ # Users Permissions -GitLab CI relies on user's role on the GitLab. There are three permissions levels on GitLab CI: admin, master, developer, other. - -Admin user can perform any actions on GitLab CI in scope of instance and project. Also user with admin permission can use admin interface. - - - - -| Action | Guest, Reporter | Developer | Master | Admin | -|---------------------------------------|-----------------|-------------|----------|--------| -| See commits and builds | ✓ | ✓ | ✓ | ✓ | -| Retry or cancel build | | ✓ | ✓ | ✓ | -| Remove project | | | ✓ | ✓ | -| Create project | | | ✓ | ✓ | -| Change project configuration | | | ✓ | ✓ | -| Add specific runners | | | ✓ | ✓ | -| Add shared runners | | | | ✓ | -| See events in the system | | | | ✓ | -| Admin interface | | | | ✓ | - - - - +This document was moved to [user/permissions.md](../../user/permissions.md#gitlab-ci). From b2007676e7f88bf7bfa1bda14f6d9143f548183a Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 12 Jul 2016 14:52:52 +0000 Subject: [PATCH 117/335] Update CHANGELOG --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 2b68226a054..523fd2d6ba3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -77,7 +77,7 @@ v 8.10.0 (unreleased) v 8.9.7 (unreleased) - Fix import_data wrongly saved as a result of an invalid import_url -v 8.9.6 (unreleased) +v 8.9.6 - Fix importing of events under notes for GitLab projects v 8.9.5 From aa8a61cca9b2346212c19d365c2e60841fea6212 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 12 Jul 2016 17:53:54 +0300 Subject: [PATCH 118/335] Change permissions URL in main readme --- doc/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/README.md b/doc/README.md index cf7a828d91e..cc0b6e0c1e5 100644 --- a/doc/README.md +++ b/doc/README.md @@ -11,7 +11,7 @@ - [Importing and exporting projects between instances](user/project/settings/import_export.md). - [Markdown](markdown/markdown.md) GitLab's advanced formatting system. - [Migrating from SVN](workflow/importing/migrating_from_svn.md) Convert a SVN repository to Git and GitLab. -- [Permissions](permissions/permissions.md) Learn what each role in a project (external/guest/reporter/developer/master/owner) can do. +- [Permissions](user/permissions.md) Learn what each role in a project (external/guest/reporter/developer/master/owner) can do. - [Profile Settings](profile/README.md) - [Project Services](project_services/project_services.md) Integrate a project with external services, such as CI and chat. - [Public access](public_access/public_access.md) Learn how you can allow public and internal access to projects. From 801453297d29600d7c959e48e8b7020e4348c50c Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Tue, 12 Jul 2016 09:57:05 -0500 Subject: [PATCH 119/335] Remove icons from sidebar; remove darker theme color from pin & toggle buttons --- .../stylesheets/framework/gitlab-theme.scss | 1 - app/assets/stylesheets/framework/sidebar.scss | 2 +- app/views/layouts/nav/_dashboard.html.haml | 20 ------------------- 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss index d1ff63bd099..3673b81f183 100644 --- a/app/assets/stylesheets/framework/gitlab-theme.scss +++ b/app/assets/stylesheets/framework/gitlab-theme.scss @@ -11,7 +11,6 @@ .toggle-nav-collapse, .pin-nav-btn { color: $color-light; - background: $color; &:hover { color: $white-light; diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 1a2220f3b40..9aefc158d6e 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -76,7 +76,7 @@ } a { - padding: 7px 15px 7px 12px; + padding: 7px 15px; font-size: $gl-font-size; line-height: 24px; display: block; diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index 52e41b1a857..21668698814 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -1,64 +1,44 @@ %ul.nav.nav-sidebar = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do = link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do - .icon-container - = navbar_icon('project') %span Projects = nav_link(controller: :todos) do = link_to dashboard_todos_path, title: 'Todos' do - .icon-container - = icon('bell fw') %span Todos %span.count= number_with_delimiter(todos_pending_count) = nav_link(path: 'dashboard#activity') do = link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do - .icon-container - = navbar_icon('activity') %span Activity = nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do = link_to dashboard_groups_path, title: 'Groups' do - .icon-container - = navbar_icon('group') %span Groups = nav_link(controller: 'dashboard/milestones') do = link_to dashboard_milestones_path, title: 'Milestones' do - .icon-container - = navbar_icon('milestones') %span Milestones = nav_link(path: 'dashboard#issues') do = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do - .icon-container - = navbar_icon('issues') %span Issues %span.count= number_with_delimiter(current_user.assigned_issues.opened.count) = nav_link(path: 'dashboard#merge_requests') do = link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do - .icon-container - = navbar_icon('mr') %span Merge Requests %span.count= number_with_delimiter(current_user.assigned_merge_requests.opened.count) = nav_link(controller: :snippets) do = link_to dashboard_snippets_path, title: 'Snippets' do - .icon-container - = icon('clipboard fw') %span Snippets = nav_link(controller: :help) do = link_to help_path, title: 'Help' do - .icon-container - = icon('question-circle fw') %span Help = nav_link(html_options: {class: profile_tab_class}) do = link_to profile_path, title: 'Profile Settings', data: {placement: 'bottom'} do - .icon-container - = icon('user fw') %span Profile Settings From 42865bfe7ba43b2a8e3eebc82efc67782e21639c Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 12 Jul 2016 14:30:37 +0100 Subject: [PATCH 120/335] Aria labels on top header links Closes #12797 --- app/helpers/projects_helper.rb | 2 +- app/views/layouts/header/_default.html.haml | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 3bbbb26cff2..5c317cee5db 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -60,7 +60,7 @@ module ProjectsHelper project_link = link_to simple_sanitize(project.name), project_path(project), { class: "project-item-select-holder" } if current_user - project_link << icon("chevron-down", class: "dropdown-toggle-caret js-projects-dropdown-toggle", data: { target: ".js-dropdown-menu-projects", toggle: "dropdown" }) + project_link << icon("chevron-down", class: "dropdown-toggle-caret js-projects-dropdown-toggle", aria: { label: "Toggle switch project dropdown" }, data: { target: ".js-dropdown-menu-projects", toggle: "dropdown" }) end full_title = "#{namespace_link} / #{project_link}".html_safe diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 11cee421a99..94c53882623 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -1,7 +1,7 @@ %header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class } %div{ class: fluid_layout ? "container-fluid" : "container-fluid" } .header-content - %button.side-nav-toggle{type: 'button'} + %button.side-nav-toggle{ type: 'button', "aria-label" => "Toggle global navigation" } %span.sr-only Toggle navigation = icon('bars') %button.navbar-toggle{type: 'button'} @@ -13,25 +13,25 @@ %li.hidden-sm.hidden-xs = render 'layouts/search' unless current_controller?(:search) %li.visible-sm.visible-xs - = link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do + = link_to search_path, title: 'Search', aria: { label: "Search" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = icon('search') - if current_user - if session[:impersonator_id] %li.impersonation - = link_to admin_impersonation_path, method: :delete, title: 'Stop Impersonation', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do + = link_to admin_impersonation_path, method: :delete, title: "Stop Impersonation", aria: { label: 'Stop Impersonation' }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do = icon('user-secret fw') - if current_user.is_admin? %li - = link_to admin_root_path, title: 'Admin Area', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do + = link_to admin_root_path, title: 'Admin Area', aria: { label: "Admin Area" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = icon('wrench fw') %li - = link_to dashboard_todos_path, title: 'Todos', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do + = link_to dashboard_todos_path, title: 'Todos', aria: { label: "Todos" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = icon('bell fw') %span.badge.todos-pending-count{ class: ("hidden" if todos_pending_count == 0) } = todos_pending_count - if current_user.can_create_project? %li - = link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do + = link_to new_project_path, title: 'New project', aria: { label: "New project" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = icon('plus fw') - if Gitlab::Sherlock.enabled? %li @@ -45,12 +45,12 @@ .dropdown-menu-nav.dropdown-menu-align-right %ul %li - = link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username } + = link_to "Profile", current_user, class: 'profile-link', aria: { label: "Profile" }, data: { user: current_user.username } %li - = link_to "Profile Settings", profile_path + = link_to "Profile Settings", profile_path, aria: { label: "Profile Settings" } %li.divider %li - = link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link", title: 'Sign out' + = link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link", aria: { label: "Sign out" } - else %li %div From f031caf3aebb9550ec23fcdf7ec5e4080dfb5ce7 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 12 Jul 2016 18:03:29 +0300 Subject: [PATCH 121/335] Change URLs to new permissions.md location --- doc/integration/saml.md | 4 ++-- doc/public_access/public_access.md | 4 ++-- doc/workflow/add-user/add-user.md | 2 +- doc/workflow/forking_workflow.md | 2 +- doc/workflow/protected_branches.md | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/integration/saml.md b/doc/integration/saml.md index 8a7205caaa4..f3b2a288776 100644 --- a/doc/integration/saml.md +++ b/doc/integration/saml.md @@ -138,7 +138,7 @@ This setting is only available on GitLab 8.7 and above. SAML login includes support for external groups. You can define in the SAML settings which groups, to which your users belong in your IdP, you wish to be -marked as [external](../permissions/permissions.md). +marked as [external](../user/permissions.md). ### Requirements @@ -306,4 +306,4 @@ For this you need take the following into account: validators are optional Make sure that one of the above described scenarios is valid, or the requests will -fail with one of the mentioned errors. \ No newline at end of file +fail with one of the mentioned errors. diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md index 9a5c5a5c92a..a3921f1b89f 100644 --- a/doc/public_access/public_access.md +++ b/doc/public_access/public_access.md @@ -17,7 +17,7 @@ Public projects can be cloned **without any** authentication. They will also be listed on the public access directory (`/public`). -**Any logged in user** will have [Guest](../permissions/permissions.md) +**Any logged in user** will have [Guest](../user/permissions.md) permissions on the repository. ### Internal projects @@ -27,7 +27,7 @@ Internal projects can be cloned by any logged in user. They will also be listed on the public access directory (`/public`) for logged in users. -Any logged in user will have [Guest](../permissions/permissions.md) permissions +Any logged in user will have [Guest](../user/permissions.md) permissions on the repository. ### How to change project visibility diff --git a/doc/workflow/add-user/add-user.md b/doc/workflow/add-user/add-user.md index 4b551130255..0537ce0bcd4 100644 --- a/doc/workflow/add-user/add-user.md +++ b/doc/workflow/add-user/add-user.md @@ -23,7 +23,7 @@ want to add. --- -Select the user and the [permission level](../../permissions/permissions.md) +Select the user and the [permission level](../../user/permissions.md) that you'd like to give the user. Note that you can select more than one user. ![Give user permissions](img/add_user_give_permissions.png) diff --git a/doc/workflow/forking_workflow.md b/doc/workflow/forking_workflow.md index 217a4a4012f..733d079bd4a 100644 --- a/doc/workflow/forking_workflow.md +++ b/doc/workflow/forking_workflow.md @@ -38,7 +38,7 @@ Forking a project is in most cases a two-step process. --- After the forking is done, you can start working on the newly created -repository. There, you will have full [Owner](../permissions/permissions.md) +repository. There, you will have full [Owner](../user/permissions.md) access, so you can set it up as you please. ## Merging upstream diff --git a/doc/workflow/protected_branches.md b/doc/workflow/protected_branches.md index 67adfc2f43a..5c1c7b47c8a 100644 --- a/doc/workflow/protected_branches.md +++ b/doc/workflow/protected_branches.md @@ -12,7 +12,7 @@ A protected branch does three simple things: You can make any branch a protected branch. GitLab makes the master branch a protected branch by default. -To protect a branch, user needs to have at least a Master permission level, see [permissions document](../permissions/permissions.md). +To protect a branch, user needs to have at least a Master permission level, see [permissions document](../user/permissions.md). ![protected branches page](protected_branches/protected_branches1.png) From 38a58978aa7969908ef31f2eac99138da2be869b Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 11 Jul 2016 16:15:59 -0300 Subject: [PATCH 122/335] Fix GItHub client requests when rate limit is disabled --- lib/gitlab/github_import/client.rb | 5 +++++ spec/lib/gitlab/github_import/client_spec.rb | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb index 043f10d96a9..f57f5b74706 100644 --- a/lib/gitlab/github_import/client.rb +++ b/lib/gitlab/github_import/client.rb @@ -78,6 +78,11 @@ module Gitlab def rate_limit api.rate_limit! + # GitHub Rate Limit API returns 404 when the rate limit is + # disabled. In this case we just want to return gracefully + # instead of spitting out an error. + rescue Octokit::NotFound + OpenStruct.new(remaining: GITHUB_SAFE_REMAINING_REQUESTS + 1) end def rate_limit_exceed? diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb index 3b023a35446..efce10dbf15 100644 --- a/spec/lib/gitlab/github_import/client_spec.rb +++ b/spec/lib/gitlab/github_import/client_spec.rb @@ -61,4 +61,13 @@ describe Gitlab::GithubImport::Client, lib: true do expect(client.api.api_endpoint).to eq 'https://github.company.com/' end end + + context 'when rate limit is disabled' do + it 'does not raise error' do + stub_request(:get, /api.github.com/) + allow(client.api).to receive(:rate_limit!).and_raise(Octokit::NotFound) + + expect { client.issues }.not_to raise_error + end + end end From cfd584b2835bc1e15eeac29433593da5f16266f3 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 11 Jul 2016 16:16:08 -0300 Subject: [PATCH 123/335] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 2527290f0fd..be8dfb62245 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -79,6 +79,7 @@ v 8.10.0 (unreleased) - Add reminder to not paste private SSH keys !4399 (Ingo Blechschmidt) - Remove duplicate `description` field in `MergeRequest` entities (Ben Boeckel) - Style of import project buttons were fixed in the new project page. !5183 (rdemirbay) + - Fix GitHub client requests when rate limit is disabled v 8.9.6 (unreleased) - Fix importing of events under notes for GitLab projects From 3ddcd0d699153363359faf28ab9f53cfd46a1cf9 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 11 Jul 2016 16:23:23 -0300 Subject: [PATCH 124/335] Remove unnecessary context from GitHub client spec --- spec/lib/gitlab/github_import/client_spec.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb index efce10dbf15..613c47d55f1 100644 --- a/spec/lib/gitlab/github_import/client_spec.rb +++ b/spec/lib/gitlab/github_import/client_spec.rb @@ -62,12 +62,10 @@ describe Gitlab::GithubImport::Client, lib: true do end end - context 'when rate limit is disabled' do - it 'does not raise error' do - stub_request(:get, /api.github.com/) - allow(client.api).to receive(:rate_limit!).and_raise(Octokit::NotFound) + it 'does not raise error when rate limit is disabled' do + stub_request(:get, /api.github.com/) + allow(client.api).to receive(:rate_limit!).and_raise(Octokit::NotFound) - expect { client.issues }.not_to raise_error - end + expect { client.issues }.not_to raise_error end end From be9262dd951e056e832ec51f8b74a8cb7ce866b4 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 11 Jul 2016 18:53:39 -0300 Subject: [PATCH 125/335] Checks if rate limit is enabled instead of stubbing response --- lib/gitlab/github_import/client.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb index f57f5b74706..f2e220fcb3e 100644 --- a/lib/gitlab/github_import/client.rb +++ b/lib/gitlab/github_import/client.rb @@ -82,11 +82,15 @@ module Gitlab # disabled. In this case we just want to return gracefully # instead of spitting out an error. rescue Octokit::NotFound - OpenStruct.new(remaining: GITHUB_SAFE_REMAINING_REQUESTS + 1) + nil + end + + def has_rate_limit? + rate_limit.present? end def rate_limit_exceed? - rate_limit.remaining <= GITHUB_SAFE_REMAINING_REQUESTS + has_rate_limit? && rate_limit.remaining <= GITHUB_SAFE_REMAINING_REQUESTS end def rate_limit_sleep_time From 78a5de99e9686bce11ba386e5d59c3e8085e40be Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 12 Jul 2016 10:44:46 -0300 Subject: [PATCH 126/335] Memoize response from `has_rate_limit?` to avoid extra API call --- lib/gitlab/github_import/client.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb index f2e220fcb3e..084e514492c 100644 --- a/lib/gitlab/github_import/client.rb +++ b/lib/gitlab/github_import/client.rb @@ -86,7 +86,9 @@ module Gitlab end def has_rate_limit? - rate_limit.present? + return @has_rate_limit if defined?(@has_rate_limit) + + @has_rate_limit = rate_limit.present? end def rate_limit_exceed? From 461feb3ddf75eb175a138fc37385ad80b0bbda9f Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 12 Jul 2016 18:16:38 +0300 Subject: [PATCH 127/335] Add 'Accept merge request' to permissions table --- doc/user/permissions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 8fc10a13f91..66542861781 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -31,7 +31,7 @@ The following table depicts the various user permission levels in a project. | See a commit status | | ✓ | ✓ | ✓ | ✓ | | See a container registry | | ✓ | ✓ | ✓ | ✓ | | See environments | | ✓ | ✓ | ✓ | ✓ | -| Manage merge requests | | | ✓ | ✓ | ✓ | +| Manage/Accept merge requests | | | ✓ | ✓ | ✓ | | Create new merge request | | | ✓ | ✓ | ✓ | | Create new branches | | | ✓ | ✓ | ✓ | | Push to non-protected branches | | | ✓ | ✓ | ✓ | From 97606e7395be10de77a11ed2f0b03ebb14d1d9f6 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Tue, 12 Jul 2016 10:18:44 -0500 Subject: [PATCH 128/335] Remove toggle partial; Move pin link to top of side nav --- app/assets/stylesheets/framework/sidebar.scss | 57 ++++++++++--------- .../stylesheets/framework/variables.scss | 1 + app/views/layouts/_collapse_button.html.haml | 3 - app/views/layouts/_page.html.haml | 12 ++-- 4 files changed, 38 insertions(+), 35 deletions(-) delete mode 100644 app/views/layouts/_collapse_button.html.haml diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 9aefc158d6e..99833ef842a 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -17,7 +17,7 @@ height: 100%; overflow: hidden; transition: width $sidebar-transition-duration; - @include box-shadow(2px 0 16px 0 #bbb); + @include box-shadow(2px 0 16px 0 $box-shadow-gray); } } @@ -76,7 +76,7 @@ } a { - padding: 7px 15px; + padding: 7px 16px; font-size: $gl-font-size; line-height: 24px; display: block; @@ -108,7 +108,7 @@ } } -.toggle-nav-collapse { +.sidebar-action-buttons { width: $sidebar_width; position: absolute; top: 0; @@ -117,12 +117,37 @@ padding: 5px 0; font-size: 18px; line-height: 30px; + + .toggle-nav-collapse { + left: 0; + } + + .pin-nav-btn { + right: 0; + display: none; + + @media (min-width: $sidebar-breakpoint) { + display: block; + } + + .fa { + transition: transform .15s; + } + + &.is-active { + .fa { + transform: rotate(90deg); + } + } + } } .nav-header-btn { - padding: 10px 5px; + padding: 10px 16px; color: inherit; transition-duration: .3s; + position: absolute; + top: 0; &:hover, &:focus { @@ -131,30 +156,6 @@ } } -.pin-nav-btn { - display: none; - position: absolute; - left: 0; - bottom: 0; - height: 50px; - width: $sidebar_width; - line-height: 30px; - - @media (min-width: $sidebar-breakpoint) { - display: block; - } - - .fa { - transition: transform .15s; - } - - &.is-active { - .fa { - transform: rotate(90deg); - } - } -} - .page-sidebar-collapsed { padding-left: 0; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 4337fab5d87..230ed28438a 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -86,6 +86,7 @@ $todo-alert-blue: #428bca; $btn-side-margin: 10px; $btn-sm-side-margin: 7px; $btn-xs-side-margin: 5px; +$box-shadow-gray: #bbb; /* * Color schema diff --git a/app/views/layouts/_collapse_button.html.haml b/app/views/layouts/_collapse_button.html.haml deleted file mode 100644 index 8c140a5943e..00000000000 --- a/app/views/layouts/_collapse_button.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -= link_to '#', class: 'nav-header-btn text-center toggle-nav-collapse', title: "Open/Close" do - %span.sr-only Toggle navigation - = icon('bars') diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index 8596bbfdef6..90c1fa4c87c 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -1,6 +1,13 @@ .page-with-sidebar{ class: "#{page_sidebar_class} #{page_gutter_class}" } .sidebar-wrapper.nicescroll{ class: nav_sidebar_class } - = render partial: 'layouts/collapse_button' + .sidebar-action-buttons + = link_to '#', class: 'nav-header-btn toggle-nav-collapse', title: "Open/Close" do + %span.sr-only Toggle navigation + = icon('bars') + = link_to '#', class: "nav-header-btn pin-nav-btn has-tooltip #{'is-active' if pinned_nav?} js-nav-pin", title: pinned_nav? ? "Unpin navigation" : "Pin Navigation", data: {placement: 'right', container: 'body'} do + %span.sr-only Toggle navigation pinning + = icon('thumb-tack') + - if defined?(sidebar) && sidebar = render "layouts/nav/#{sidebar}" - elsif current_user @@ -8,9 +15,6 @@ - else = render 'layouts/nav/explore' - = link_to '#', class: "nav-header-btn text-center pin-nav-btn has-tooltip #{'is-active' if pinned_nav?} js-nav-pin", title: pinned_nav? ? "Unpin navigation" : "Pin Navigation", data: {placement: 'right', container: 'body'} do - %span.sr-only Toggle navigation pinning - = icon('thumb-tack') - if defined?(nav) && nav .layout-nav .container-fluid From adc6ec4a9c78029348ad65a18718f2a245714932 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 11 Jul 2016 17:12:31 -0500 Subject: [PATCH 129/335] Avoid `describe`-ing symbols in specs --- spec/finders/notes_finder_spec.rb | 2 +- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 4 ++-- spec/lib/gitlab/build_data_builder_spec.rb | 2 +- spec/lib/gitlab/diff/file_spec.rb | 4 ++-- spec/lib/gitlab/diff/parser_spec.rb | 2 +- spec/lib/gitlab/ldap/access_spec.rb | 2 +- spec/lib/gitlab/ldap/user_spec.rb | 2 +- spec/models/ci/pipeline_spec.rb | 10 ++++---- spec/models/ci/variable_spec.rb | 2 +- spec/models/commit_status_spec.rb | 14 +++++------ spec/models/concerns/mentionable_spec.rb | 2 +- spec/models/forked_project_link_spec.rb | 2 +- spec/models/generic_commit_status_spec.rb | 10 ++++---- spec/models/global_milestone_spec.rb | 6 ++--- spec/models/group_spec.rb | 10 ++++---- spec/models/members/project_member_spec.rb | 4 ++-- spec/models/milestone_spec.rb | 10 ++++---- spec/models/namespace_spec.rb | 8 +++---- spec/models/project_security_spec.rb | 2 +- .../buildkite_service_spec.rb | 6 ++--- spec/models/project_spec.rb | 24 +++++++++---------- spec/models/repository_spec.rb | 20 ++++++++-------- spec/models/service_spec.rb | 6 ++--- spec/models/user_spec.rb | 12 +++++----- .../ci/create_trigger_request_service_spec.rb | 2 +- .../ci/image_for_build_service_spec.rb | 2 +- .../ci/register_build_service_spec.rb | 2 +- .../create_commit_builds_service_spec.rb | 2 +- spec/services/event_create_service_spec.rb | 20 ++++++++-------- spec/services/issues/close_service_spec.rb | 2 +- .../merge_requests/close_service_spec.rb | 2 +- .../merge_requests/create_service_spec.rb | 2 +- .../merge_requests/merge_service_spec.rb | 2 +- .../merge_requests/refresh_service_spec.rb | 2 +- .../merge_requests/reopen_service_spec.rb | 2 +- .../services/milestones/close_service_spec.rb | 2 +- .../milestones/create_service_spec.rb | 2 +- spec/services/notes/create_service_spec.rb | 2 +- .../notes/post_process_service_spec.rb | 2 +- spec/services/notification_service_spec.rb | 4 ++-- spec/services/test_hook_service_spec.rb | 2 +- 41 files changed, 110 insertions(+), 110 deletions(-) diff --git a/spec/finders/notes_finder_spec.rb b/spec/finders/notes_finder_spec.rb index 1bd354815e4..8db897b1646 100644 --- a/spec/finders/notes_finder_spec.rb +++ b/spec/finders/notes_finder_spec.rb @@ -11,7 +11,7 @@ describe NotesFinder do project.team << [user, :master] end - describe :execute do + describe '#execute' do let(:params) { { target_id: commit.id, target_type: 'commit', last_fetched_at: 1.hour.ago.to_i } } before do diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index bad439bc489..bcbf409c8b0 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -31,7 +31,7 @@ module Ci }) end - describe :only do + describe 'only' do it "does not return builds if only has another branch" do config = YAML.dump({ before_script: ["pwd"], @@ -187,7 +187,7 @@ module Ci end end - describe :except do + describe 'except' do it "returns builds if except has another branch" do config = YAML.dump({ before_script: ["pwd"], diff --git a/spec/lib/gitlab/build_data_builder_spec.rb b/spec/lib/gitlab/build_data_builder_spec.rb index 38be9448794..23ae5cfacc4 100644 --- a/spec/lib/gitlab/build_data_builder_spec.rb +++ b/spec/lib/gitlab/build_data_builder_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'Gitlab::BuildDataBuilder' do let(:build) { create(:ci_build) } - describe :build do + describe '.build' do let(:data) do Gitlab::BuildDataBuilder.build(build) end diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index 1cb513d5229..0460dcf4658 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -8,14 +8,14 @@ describe Gitlab::Diff::File, lib: true do let(:diff) { commit.diffs.first } let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: commit.diff_refs, repository: project.repository) } - describe :diff_lines do + describe '#diff_lines' do let(:diff_lines) { diff_file.diff_lines } it { expect(diff_lines.size).to eq(30) } it { expect(diff_lines.first).to be_kind_of(Gitlab::Diff::Line) } end - describe :mode_changed? do + describe '#mode_changed?' do it { expect(diff_file.mode_changed?).to be_falsey } end diff --git a/spec/lib/gitlab/diff/parser_spec.rb b/spec/lib/gitlab/diff/parser_spec.rb index cdff063a9ed..c3359627652 100644 --- a/spec/lib/gitlab/diff/parser_spec.rb +++ b/spec/lib/gitlab/diff/parser_spec.rb @@ -8,7 +8,7 @@ describe Gitlab::Diff::Parser, lib: true do let(:diff) { commit.diffs.first } let(:parser) { Gitlab::Diff::Parser.new } - describe :parse do + describe '#parse' do let(:diff) do < Date: Wed, 6 Jul 2016 10:15:41 +0100 Subject: [PATCH 130/335] implements filter_params --- lib/api/entities.rb | 2 ++ lib/api/helpers.rb | 17 +++++++++++++++++ lib/api/projects.rb | 2 ++ 3 files changed, 21 insertions(+) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 301dbb688a7..f00a4ac2ed6 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -344,7 +344,9 @@ module API class ProjectWithAccess < Project expose :permissions do expose :project_access, using: Entities::ProjectAccess do |project, options| + project = Project.find_by(project[:id]) project.project_members.find_by(user_id: options[:user].id) + ] end expose :group_access, using: Entities::GroupAccess do |project, options| diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 77e407b54c5..3a1837effd8 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -287,6 +287,23 @@ module API # Projects helpers + def filter_params(projects) + project_entries = [] + + # Removes the redundant information of the object + projects.each do |project| + entry = { + id: project.id, + http_url_to_repo: project.http_url_to_repo, + name_with_namespace: project.name_with_namespace + } + + project_entries << entry + end + + project_entries + end + def filter_projects(projects) # If the archived parameter is passed, limit results accordingly if params[:archived].present? diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 0cc1edd65c8..deade7cad90 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -25,6 +25,8 @@ module API @projects = current_user.authorized_projects @projects = filter_projects(@projects) @projects = paginate @projects + @projects = filter_params(@projects) + puts present @projects, with: Entities::ProjectWithAccess, user: current_user present @projects, with: Entities::ProjectWithAccess, user: current_user end From a8cf4e13b33da8d71e16874ebf3dce9ca9d40b76 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Wed, 6 Jul 2016 17:53:40 +0100 Subject: [PATCH 131/335] adds basic functionality to the new endpoint of the api --- lib/api/entities.rb | 16 ++++++++++++++-- lib/api/helpers.rb | 17 ----------------- lib/api/projects.rb | 13 +++++++++++-- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index f00a4ac2ed6..951cca248a1 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -90,6 +90,12 @@ module API end end + class SimpleProject < Grape::Entity + expose :id + expose :name, :name_with_namespace + expose :http_url_to_repo + end + class ProjectMember < UserBasic expose :access_level do |user, options| options[:project].project_members.find_by(user_id: user.id).access_level @@ -341,12 +347,18 @@ module API end end + class SimpleProjectWithAccess < SimpleProject + expose :permissions do + expose :project_access, using: Entities::ProjectAccess do |project, options| + project.project_members.find_by(user_id: options[:user].id) + end + end + end + class ProjectWithAccess < Project expose :permissions do expose :project_access, using: Entities::ProjectAccess do |project, options| - project = Project.find_by(project[:id]) project.project_members.find_by(user_id: options[:user].id) - ] end expose :group_access, using: Entities::GroupAccess do |project, options| diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 3a1837effd8..77e407b54c5 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -287,23 +287,6 @@ module API # Projects helpers - def filter_params(projects) - project_entries = [] - - # Removes the redundant information of the object - projects.each do |project| - entry = { - id: project.id, - http_url_to_repo: project.http_url_to_repo, - name_with_namespace: project.name_with_namespace - } - - project_entries << entry - end - - project_entries - end - def filter_projects(projects) # If the archived parameter is passed, limit results accordingly if params[:archived].present? diff --git a/lib/api/projects.rb b/lib/api/projects.rb index deade7cad90..c1e66b239aa 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -25,11 +25,20 @@ module API @projects = current_user.authorized_projects @projects = filter_projects(@projects) @projects = paginate @projects - @projects = filter_params(@projects) - puts present @projects, with: Entities::ProjectWithAccess, user: current_user present @projects, with: Entities::ProjectWithAccess, user: current_user end + # Get a simplified project list for authenticated user + # + # Example Request: + # GET /projects/simple + get '/simple' do + @projects = current_user.authorized_projects + @projects = filter_projects(@projects) + @projects = paginate @projects + present @projects, with: Entities::SimpleProjectWithAccess, user: current_user + end + # Get an owned projects list for authenticated user # # Example Request: From 331f026acb3515ab64e4e7ec75ea16473b98fc2f Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Thu, 7 Jul 2016 11:55:31 +0100 Subject: [PATCH 132/335] gets the new object through /simple endpoint and renders on the dropdown --- app/assets/javascripts/api.js.coffee | 2 +- app/assets/javascripts/gl_dropdown.js.coffee | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee index cf46f15a156..45059ae4042 100644 --- a/app/assets/javascripts/api.js.coffee +++ b/app/assets/javascripts/api.js.coffee @@ -3,7 +3,7 @@ groupPath: "/api/:version/groups/:id.json" namespacesPath: "/api/:version/namespaces.json" groupProjectsPath: "/api/:version/groups/:id/projects.json" - projectsPath: "/api/:version/projects.json" + projectsPath: "/api/:version/projects/simple.json" labelsPath: "/api/:version/projects/:id/labels" licensePath: "/api/:version/licenses/:key" gitignorePath: "/api/:version/gitignores/:key" diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 1c65e833d47..e226943a4c1 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -123,6 +123,7 @@ class GitLabDropdownRemote # Fetch the data by calling the data funcfion @dataEndpoint "", (data) => + console.log(data) if @options.success @options.success(data) From 9840681025463e8187652d825e7ed556a95c4936 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Thu, 7 Jul 2016 11:55:58 +0100 Subject: [PATCH 133/335] removes debugging print --- app/assets/javascripts/gl_dropdown.js.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index e226943a4c1..1c65e833d47 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -123,7 +123,6 @@ class GitLabDropdownRemote # Fetch the data by calling the data funcfion @dataEndpoint "", (data) => - console.log(data) if @options.success @options.success(data) From 6715ea7dc8b92e54e728f155cc4edeb917585168 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Thu, 7 Jul 2016 12:20:51 +0100 Subject: [PATCH 134/335] adds entry to changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index ee3ee4c37d6..3db8fa142df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.10.0 (unreleased) - Expose {should,force}_remove_source_branch (Ben Boeckel) + - Fix projects dropdown loading performance with a simplified api cal. !5113 (tiagonbotelho) - Fix commit builds API, return all builds for all pipelines for given commit. !4849 - Replace Haml with Hamlit to make view rendering faster. !3666 - Expire the branch cache after `git gc` runs From f5d92d120edbd6bc730f10293a5847dd9b0e22fc Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 8 Jul 2016 09:47:09 +0100 Subject: [PATCH 135/335] changes the usage of simpleprojectdetails to already implemented basicprojectsdetails and changes the url to a more reader friendly format --- app/assets/javascripts/api.js.coffee | 2 +- lib/api/entities.rb | 8 +------- lib/api/projects.rb | 17 +++++------------ 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee index 45059ae4042..8028e66f089 100644 --- a/app/assets/javascripts/api.js.coffee +++ b/app/assets/javascripts/api.js.coffee @@ -3,7 +3,7 @@ groupPath: "/api/:version/groups/:id.json" namespacesPath: "/api/:version/namespaces.json" groupProjectsPath: "/api/:version/groups/:id/projects.json" - projectsPath: "/api/:version/projects/simple.json" + projectsPath: "/api/:version/projects.json?format=simple" labelsPath: "/api/:version/projects/:id/labels" licensePath: "/api/:version/licenses/:key" gitignorePath: "/api/:version/gitignores/:key" diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 951cca248a1..0def1ed2823 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -90,12 +90,6 @@ module API end end - class SimpleProject < Grape::Entity - expose :id - expose :name, :name_with_namespace - expose :http_url_to_repo - end - class ProjectMember < UserBasic expose :access_level do |user, options| options[:project].project_members.find_by(user_id: user.id).access_level @@ -347,7 +341,7 @@ module API end end - class SimpleProjectWithAccess < SimpleProject + class BasicProjectWithAccess < BasicProjectDetails expose :permissions do expose :project_access, using: Entities::ProjectAccess do |project, options| project.project_members.find_by(user_id: options[:user].id) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index c1e66b239aa..c46764c4897 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -25,18 +25,11 @@ module API @projects = current_user.authorized_projects @projects = filter_projects(@projects) @projects = paginate @projects - present @projects, with: Entities::ProjectWithAccess, user: current_user - end - - # Get a simplified project list for authenticated user - # - # Example Request: - # GET /projects/simple - get '/simple' do - @projects = current_user.authorized_projects - @projects = filter_projects(@projects) - @projects = paginate @projects - present @projects, with: Entities::SimpleProjectWithAccess, user: current_user + if params["format"] + present @projects, with: Entities::BasicProjectWithAccess, user: current_user + else + present @projects, with: Entities::ProjectWithAccess, user: current_user + end end # Get an owned projects list for authenticated user From 8a4f2d4db081575c14550d3adcf1bb7a809da595 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 8 Jul 2016 11:17:37 +0100 Subject: [PATCH 136/335] changes the project_title_spec accordingly --- spec/javascripts/project_title_spec.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/javascripts/project_title_spec.js.coffee b/spec/javascripts/project_title_spec.js.coffee index f0d26fb5446..e49dfbf1ba4 100644 --- a/spec/javascripts/project_title_spec.js.coffee +++ b/spec/javascripts/project_title_spec.js.coffee @@ -22,7 +22,7 @@ describe 'Project Title', -> @projects_data = fixture.load('projects.json')[0] spyOn(jQuery, 'ajax').and.callFake (req) => - expect(req.url).toBe('/api/v3/projects.json') + expect(req.url).toBe('/api/v3/projects.json?format=simple') d = $.Deferred() d.resolve @projects_data d.promise() From 87d4d76dc03b54a22cb29c71eaa962b7265f5319 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 8 Jul 2016 12:06:39 +0100 Subject: [PATCH 137/335] fixes missing field on basicprojectdetails --- .Gemfile.swm | Bin 0 -> 16384 bytes .Gemfile.swn | Bin 0 -> 16384 bytes app/assets/javascripts/gl_dropdown.js.coffee | 1 + lib/api/entities.rb | 1 + 4 files changed, 2 insertions(+) create mode 100644 .Gemfile.swm create mode 100644 .Gemfile.swn diff --git a/.Gemfile.swm b/.Gemfile.swm new file mode 100644 index 0000000000000000000000000000000000000000..c5905cff7932aba6a13e5bafc60086613e1d4416 GIT binary patch literal 16384 zcmeI3U5qS66~`M8L?>Z54KP8FvrKD&>Rj$b6uZO_8c16L}SG$jbfPJtVTB zOvNi#+Wy*FptZnjw7~hn(qeCcgy%Y!u?sJ_;WggZinSJKEznw^wLoiu)&i{sS_`xm zXf5#nV1cSQE4Tw4In#CKPWO4nj?b6>ZLbI1?|1DeKg<2S>OL=Z75IAG&+SKRfz|@8 z1zHQV7HBQdTA;N+Yk}4Rtp!>Ov=(SB@ISBsPlDiFw0k)v0Py_ZpZ{NcOA!14{0ck- z9t1VG8QcUe0e^aP5c~rC9DEmi4%`Ja_z>uT%fLC{h4X{pN8lbX1XqBIz)R-^!Oy_A zKmiVc^S~e96a+s8_kuCF3hV*P;O*drH=V3^`El?Q@ECXqJP5uBCg9_s2SPwT@qW-; zB2NOwMj~VLbuMF7=HWz@8=}P98fhxZ`ODe-?N_peXgOM(caj|^*|BBI(Sc}TJ{Xm% zF4&4IV~Gmp*lJOvGUk<3In$!t6lD;Ywh}oUZn?UbqJ?N_9@1<0Q9FTLZK#nfrIYDJ zd!v2y{mLtt`A*u*F`g%ETvdf$>2^)~IvOc8N<|c_tUFX?opt9ft5hN5ZdnhuLM`ID zl+{+q^SryZweKeR;X%JxUq@ZXg!nJ&;>QM~H8~k9F8dz993ugh{Y7T%MZF#@Mb_pz zmNHRsrO3w2Sh*MNp?;b2iQJHJs;aT8VtygoANiZ(QmAyMayvwO%rH>psvL#XU*Ehf zKM?hN?Il|Fg`^+^mZH6`>7ydKdZuNg+H$nis8)(3=4Bx&uNr!`gmMg`Q5~=TjO#&| z@p7XsAY*&J)M#IEz0pslp1r>ZCs>4RDNfX~6f11Lk?NLQrj-<~_HmV^VId2V%A8DK zYww`~@`!abny5)`T;tl~>xWrUs#s_(^O1F}jus*bhqd$GMJT?9?!@>fEa4URV)8a8 z0?lmYt93P2r95dI+KJWquo3G;%TyEmj`4|R8e_{x!g=&iVN7_up$i^+y%!>QgzFcT zt3u?uf{^PM%4bTgYd1yS+;n5AVxGQY38u7f4eHT6B?qB<_{q8{T4-FyluUF}*8$(7 z0o1As@7+nMijyiAw`z1src?QSq%!6*dTz#G4T9{3>zuXVH>DKigl~$e)lB1a>>9if zrWvo$|1rHU=9?PxES2OdG}4Q9u&!NQKkTa9;F-*MDN$d?M5^AtXrTiYj_?r*DE7D! zAnS*)2Px}j9L2Q-{5f?y66zWu=gcK9L9FeLst#=v$+#AXmw4$fl_y21yH=H`9I#4} zKvk-grHUs^l?kH#9K-8?>_)^gHwN~#z`n|I$uXP46xus&dYEQCd~e30vrUSI6jOH^ zqfL}CfnK6rnF!w9b^}H+D|jio8P_mS6h*f2@rf1ti`DKhAJB~5U=vh`7O+V1l*tTn zV^bJEq`qO=lQ*Gra!~SeD`MARmJjQce$f?ELl%!QU_#T#t*stm6fB&Jx=!Q6Iem|U z9R!b{4JgidOd*QeIb>d&Tv@@VZwhiBysd&?R`4DS1eDF}k~%C^#yCU0Fj}FsM8Mf{ zZ4OE`!IJA5T(s>Sv_GEaQT5``4FbhFA9FAj%f86tatjWYI00I%eH1BAl(E8Vq9y_? zH8u3GR9lb3+n-X4u$riF2>s1cN3+;fGRKZLC5+sGrkUL?ICtS2QfFqNv6H`PS;X*q zSbVA#zBQgRU;1*hcxbZqv4X=`*f4N365T4Db6DYhOj3FyKU#+OG(RZy8)MGgqV43$@fZYWVAZJ>3E8^Z}n3@`~ zts96^x%g-I9N2rA7+|(fD{RHf*a2*AwQEn*DtA!5Q)T?^GSD_0(skHJbUm zQ*gQ-HiGaRF;I%uL~~J%vtHN;#$1yVHkWN0VZ{w4Ij7oOaq+ zmIVDysi~1Xg(9iHY}1IZJDQ#mv7%ORx;IJ`?Y>1}0=ln_K5egkeRg7z6a{0*EBlsDvPmY$w~&C(^}67OL)@ku{|>yXvA) zCBg(-JLp?T#E{o%)!*c4E&2#ssDzeiGk6rv*Q@|D0^01GR*$j_Atm*TzozXQMv8pa zn!xz=j_tbfIkOa4_Y1KB_HUraqARtoh3@WM*n7YP0ujsM76NBeIYZFbbVx~RK~Y#D z=n1aT8w`Yrw|VUMaWG7wax89MCAT>|+Wd|-eJ&ZS^r$IzqQQ0iFMQI0s)(=VYA!{qy@% zINv`Feht0@J`HXF$H6{u0eBmr9Kd7XOW+gW7SIJR<81#lcnI7H1h@)Z3Em0b0se+_ z{tMuF@Emvw+y^G$X0Qx8;1cj&a4z^O&i<#spTU#hm*5fb1Mm&-b&!J$jKB(b54ady z2>yY7{vDhG&w$^6$HBwk+u+Nf1Z0mRpuJiPv=(SB&|09iKx={40<8sJ#RBGlr?+%S z|FVhCN@UG070Gya#M#V{xtylyTt4=g5ueRkxE=6V@U$BDzrd(yY$|?$dCi=BL|ai^^tNy-o+Vc0bSaU9lJeA z86l;pRhz2Z-*MKU=K%QkSa%mC+o83+D;JXzx$d}M7G7PP!H{SUrq6CV_Sn-$s)Q^w zkF+92#XgY10V=6Y`jDQ<%-l4uky-6iro%tjnXh1(J|7}I(MR$uYZTh{_-B411{n@z zjSnoEv35_9tSNLM==p*@-I^1dE7oIGBj<;Q1IXUYo}uxZT9+Ji+s?kk^SZ!wxZ5*)Zjl z72d5-jdm^6$S|gGvQ0>knQ#gxGwxQGj zTndCHG<<(s&1m%W%hqfrf|vG6hPQH!X9j*gBR7h!?i6x8K|YEKeQBXmOpcM5KD?rq zZCmCks8bBt$*loGR;ZCkfLo50A2{m3v^6icy$e(yPWqIO@(mA%9GN+%6!f)qAiXYf O8_b6w!5ou zSN9Hkqo81n3QAA|nh=l&6ZJt79>n+}`hW_G_$U~O=z~{c;;R}z{--{AX7{pz#0L}8 zo%}MhQ>Uv=ojP@@>U8g5;Um|rvwhKWfa}dc@MwO=jZg5$&b<2lX9ShxBb5(SCDO5? z@?Ea=gGa(dgvUudT#Qnlzr5h>+bZnpGVUIdRmun5k@-L+n<7<3Ch{uWkd^zndq`wM znTnUMwEeZUKx=_lX@T>DrN!O?3D0#dV;5dhcn6>BZfTA;N+Yk}4Rtp!>Ov=(SB z&|2XC!2(rrR&WP8a;EFdo$m9D9iRVp*Msi&yLObH<^EoEpO?A{d_C^x_M^2xYk}4R ztp!>Ov=(SB&|09iKx={40<8sF3$zyaA6S4VL2xeGy_^yNc>eFt|1Z8N2!0QK0Uibq zfg0QlZUUEpKfW;teg=LDz70ML?gAQo5Olz0;2iM6`9bgla4#5wE5JqIrSpQ|C*T{P z0EfVN;16#If**qWz!+Qw_JC#ZR`9~>(Jpurd>4EU2(Shs5Q2ArGe7`-{kkCd4)_wd z2Yed52mA(||2lX8+yhp@Mc}uu4T9&vli*(PW$<}02G@a$z=hx(@aJ=a;1qZfJPn=# z-vS2M55V;B4^H*+K9ucno|6+z0Le5{$t|!9lPJ_JE7QJHbC*69mtJ z2f-)7E#Q6NQt&S%V}1vI3?2b@g3o|G;1tIB3GgHEICvO51ik}XtR3YPTSr4{CE#kVA z)mF&!yt}rw?#|EP{ITmjqsH9EH?h-@Gk9 z5cPcRC0h1{q#y*AqP?!^qawL_re&krap__D za-%LFV|%{TXkT%?(NCqGy}t)1ScGgTPSmm#D{Q`z>Xuxll@zY_ah0WEAq$bpoJ?SA z@1X+nh;=lYs7Y>Ilc-) zLgc!Fkn0!9XG*PWH$~pubYrSwp1y1ernGMj>d`zU2cdiT$+{_8Xk5pXOmtJ%0pFtm z)T#^b-ASp6lPVXtYII7bQ~7hmExZxhDeGn&#kB?eIdwY{>KY;E%q1^G2z3xO8l#wCXnmcEZGF=^dkAS{gw-Ry-)>64 zWk)p}-|4y>k*YJTcNziQeV9WS{=*VciFl?TBbBCgh6z3ziKNdHUQ{~*^-PsRo@(K` zV(&}kz;$F9?zgS?R(OsbwX-l`8P98;rdv$rELQnYj=D0JcdCq=2dR+Xq6uu73Y zRjQPwiYH8!38MWR!|QwHXb1)UlzR2Tp3l5ez0a~qn6e&-XvBGPjCIT!q zHT1AlTaUxrpHhpkny7FH{moKGv)ENK$Bs88jNE~yncXfpci|gSXJ(uXLnfF_O-31XKXIgeE;@)PMni{dK z8;DZ5_-FSV*n626V75;yY{kpi0c>uyYfspigp_gX;`Z*r8S(n>R2{4J)MutOn)$m^ zaJn8gg76$MP>R+>b5V`6Uf2l6T$2+vmu(th#SLmBIFQw#jyJY#V4&gYf@X=FcG_5$ z1pQ8_sgXQ|BB{S@(}=G-nw}A{qE>LaH%b)kzC~dIy048sNs!j6*@<;pZ8Kt6eYQ;~ z7fmDrl&PXqj9hHMCSyOkemV0lfJjn}N(j=(cCsyfB3*1`q3YflSyM{0t1b#vB22Kg zgT94C40)Ya{Y{?MqK~kJN@$5TgGb?f%?dChpv}H%^(e~_Qc}P8YudhHq{wH<1lXmL z5q50XjnA2-z`9?E4X}R$Jr-T5buDyv@50^#CJ=~N4!00Eo5~r2zNSM;QVWX05XZ-178I>$iN7!fOmn5!G+-O z=;zOv=(SB@Cp_%2Ryx{L;9CZ zd{!cBcBx3lyCcbFhRo$OP3Q8l$Bg)F*23+8$AYKTxF3&2lkKGRw@DseYs!#NL76|T z@RH|Ba(9Hlo|_I3$JDSwG6QGiX_jx>5tX*l=D6@-It{tHa)B-+bRfxQjy3+2NO=|< z2Ly6}37!`qbFA_{rE;ffR9oj9yV|Aq=0%1aXdgM4bgPe)6Y?(3Knv*7e(c!oNy-Q* zMXlOY<^GPd20aJBzsI_}DA^9J?OnN;l*o0*{j%`t;tYmFb1;2&)3L{%K2jxQp?Rbg zF)H?f3=U99ZPJJIOlIb$d5z3!pE4c(!OnaI%k=pW>4`p)XIZ1rw#Ps76EVneC~JIR z(Tufwieycp3qj8p?CI8=*j%w5s~R~!JRCswX7&uVA1cpea9rBbc7fE|sr*LH3q7Md zQl~MJ=Qw9dI-J1@O*Y8Z6*vtB$Y_n}*+eJ{I>PNHR_6(xe}%kGj2U)_xyptqr>yX9 zg=(~Gp+<%=g_CVUg3N?dIGJ&`x^%2Ho|)v{MKB^X$h(Q-M5tm_gypt@pa(>+a7Uxf zGCBEa!rq8DIU^Z~WO{}SaiYTtr{zMayt&;ZQ~a3k5Y`1Usj+#mWgTSJe|FaFd*D(a zG@;@9+iFImr(d>aGZDPBS2DbnYdkaX^BK8ObakhY>k0BvROm|!m11&?#Ps16wQSom zPeGkx$WCqz5VAszL;~D$to*=H2d1rgx$Rw``f$>xe3Wl^IONF8Ii;Yltpn+Gkt1JS M33d(2?c=Ne087$n)Bpeg literal 0 HcmV?d00001 diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 1c65e833d47..4743b484d22 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -401,6 +401,7 @@ class GitLabDropdown selected = true # Set URL + console.log(data) if @options.url? url = @options.url(data) else diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 0def1ed2823..b62afb4bb4c 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -54,6 +54,7 @@ module API class BasicProjectDetails < Grape::Entity expose :id + expose :http_url_to_repo, :web_url expose :name, :name_with_namespace expose :path, :path_with_namespace end From f0c437ca7d5ece265b134d8323f4f01b656f1a90 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 8 Jul 2016 12:07:17 +0100 Subject: [PATCH 138/335] removes gemfile.lock dotfiles --- .Gemfile.swm | Bin 16384 -> 0 bytes .Gemfile.swn | Bin 16384 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .Gemfile.swm delete mode 100644 .Gemfile.swn diff --git a/.Gemfile.swm b/.Gemfile.swm deleted file mode 100644 index c5905cff7932aba6a13e5bafc60086613e1d4416..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeI3U5qS66~`M8L?>Z54KP8FvrKD&>Rj$b6uZO_8c16L}SG$jbfPJtVTB zOvNi#+Wy*FptZnjw7~hn(qeCcgy%Y!u?sJ_;WggZinSJKEznw^wLoiu)&i{sS_`xm zXf5#nV1cSQE4Tw4In#CKPWO4nj?b6>ZLbI1?|1DeKg<2S>OL=Z75IAG&+SKRfz|@8 z1zHQV7HBQdTA;N+Yk}4Rtp!>Ov=(SB@ISBsPlDiFw0k)v0Py_ZpZ{NcOA!14{0ck- z9t1VG8QcUe0e^aP5c~rC9DEmi4%`Ja_z>uT%fLC{h4X{pN8lbX1XqBIz)R-^!Oy_A zKmiVc^S~e96a+s8_kuCF3hV*P;O*drH=V3^`El?Q@ECXqJP5uBCg9_s2SPwT@qW-; zB2NOwMj~VLbuMF7=HWz@8=}P98fhxZ`ODe-?N_peXgOM(caj|^*|BBI(Sc}TJ{Xm% zF4&4IV~Gmp*lJOvGUk<3In$!t6lD;Ywh}oUZn?UbqJ?N_9@1<0Q9FTLZK#nfrIYDJ zd!v2y{mLtt`A*u*F`g%ETvdf$>2^)~IvOc8N<|c_tUFX?opt9ft5hN5ZdnhuLM`ID zl+{+q^SryZweKeR;X%JxUq@ZXg!nJ&;>QM~H8~k9F8dz993ugh{Y7T%MZF#@Mb_pz zmNHRsrO3w2Sh*MNp?;b2iQJHJs;aT8VtygoANiZ(QmAyMayvwO%rH>psvL#XU*Ehf zKM?hN?Il|Fg`^+^mZH6`>7ydKdZuNg+H$nis8)(3=4Bx&uNr!`gmMg`Q5~=TjO#&| z@p7XsAY*&J)M#IEz0pslp1r>ZCs>4RDNfX~6f11Lk?NLQrj-<~_HmV^VId2V%A8DK zYww`~@`!abny5)`T;tl~>xWrUs#s_(^O1F}jus*bhqd$GMJT?9?!@>fEa4URV)8a8 z0?lmYt93P2r95dI+KJWquo3G;%TyEmj`4|R8e_{x!g=&iVN7_up$i^+y%!>QgzFcT zt3u?uf{^PM%4bTgYd1yS+;n5AVxGQY38u7f4eHT6B?qB<_{q8{T4-FyluUF}*8$(7 z0o1As@7+nMijyiAw`z1src?QSq%!6*dTz#G4T9{3>zuXVH>DKigl~$e)lB1a>>9if zrWvo$|1rHU=9?PxES2OdG}4Q9u&!NQKkTa9;F-*MDN$d?M5^AtXrTiYj_?r*DE7D! zAnS*)2Px}j9L2Q-{5f?y66zWu=gcK9L9FeLst#=v$+#AXmw4$fl_y21yH=H`9I#4} zKvk-grHUs^l?kH#9K-8?>_)^gHwN~#z`n|I$uXP46xus&dYEQCd~e30vrUSI6jOH^ zqfL}CfnK6rnF!w9b^}H+D|jio8P_mS6h*f2@rf1ti`DKhAJB~5U=vh`7O+V1l*tTn zV^bJEq`qO=lQ*Gra!~SeD`MARmJjQce$f?ELl%!QU_#T#t*stm6fB&Jx=!Q6Iem|U z9R!b{4JgidOd*QeIb>d&Tv@@VZwhiBysd&?R`4DS1eDF}k~%C^#yCU0Fj}FsM8Mf{ zZ4OE`!IJA5T(s>Sv_GEaQT5``4FbhFA9FAj%f86tatjWYI00I%eH1BAl(E8Vq9y_? zH8u3GR9lb3+n-X4u$riF2>s1cN3+;fGRKZLC5+sGrkUL?ICtS2QfFqNv6H`PS;X*q zSbVA#zBQgRU;1*hcxbZqv4X=`*f4N365T4Db6DYhOj3FyKU#+OG(RZy8)MGgqV43$@fZYWVAZJ>3E8^Z}n3@`~ zts96^x%g-I9N2rA7+|(fD{RHf*a2*AwQEn*DtA!5Q)T?^GSD_0(skHJbUm zQ*gQ-HiGaRF;I%uL~~J%vtHN;#$1yVHkWN0VZ{w4Ij7oOaq+ zmIVDysi~1Xg(9iHY}1IZJDQ#mv7%ORx;IJ`?Y>1}0=ln_K5egkeRg7z6a{0*EBlsDvPmY$w~&C(^}67OL)@ku{|>yXvA) zCBg(-JLp?T#E{o%)!*c4E&2#ssDzeiGk6rv*Q@|D0^01GR*$j_Atm*TzozXQMv8pa zn!xz=j_tbfIkOa4_Y1KB_HUraqARtoh3@WM*n7YP0ujsM76NBeIYZFbbVx~RK~Y#D z=n1aT8w`Yrw|VUMaWG7wax89MCAT>|+Wd|-eJ&ZS^r$IzqQQ0iFMQI0s)(=VYA!{qy@% zINv`Feht0@J`HXF$H6{u0eBmr9Kd7XOW+gW7SIJR<81#lcnI7H1h@)Z3Em0b0se+_ z{tMuF@Emvw+y^G$X0Qx8;1cj&a4z^O&i<#spTU#hm*5fb1Mm&-b&!J$jKB(b54ady z2>yY7{vDhG&w$^6$HBwk+u+Nf1Z0mRpuJiPv=(SB&|09iKx={40<8sJ#RBGlr?+%S z|FVhCN@UG070Gya#M#V{xtylyTt4=g5ueRkxE=6V@U$BDzrd(yY$|?$dCi=BL|ai^^tNy-o+Vc0bSaU9lJeA z86l;pRhz2Z-*MKU=K%QkSa%mC+o83+D;JXzx$d}M7G7PP!H{SUrq6CV_Sn-$s)Q^w zkF+92#XgY10V=6Y`jDQ<%-l4uky-6iro%tjnXh1(J|7}I(MR$uYZTh{_-B411{n@z zjSnoEv35_9tSNLM==p*@-I^1dE7oIGBj<;Q1IXUYo}uxZT9+Ji+s?kk^SZ!wxZ5*)Zjl z72d5-jdm^6$S|gGvQ0>knQ#gxGwxQGj zTndCHG<<(s&1m%W%hqfrf|vG6hPQH!X9j*gBR7h!?i6x8K|YEKeQBXmOpcM5KD?rq zZCmCks8bBt$*loGR;ZCkfLo50A2{m3v^6icy$e(yPWqIO@(mA%9GN+%6!f)qAiXYf O8_b6w!5ou zSN9Hkqo81n3QAA|nh=l&6ZJt79>n+}`hW_G_$U~O=z~{c;;R}z{--{AX7{pz#0L}8 zo%}MhQ>Uv=ojP@@>U8g5;Um|rvwhKWfa}dc@MwO=jZg5$&b<2lX9ShxBb5(SCDO5? z@?Ea=gGa(dgvUudT#Qnlzr5h>+bZnpGVUIdRmun5k@-L+n<7<3Ch{uWkd^zndq`wM znTnUMwEeZUKx=_lX@T>DrN!O?3D0#dV;5dhcn6>BZfTA;N+Yk}4Rtp!>Ov=(SB z&|2XC!2(rrR&WP8a;EFdo$m9D9iRVp*Msi&yLObH<^EoEpO?A{d_C^x_M^2xYk}4R ztp!>Ov=(SB&|09iKx={40<8sF3$zyaA6S4VL2xeGy_^yNc>eFt|1Z8N2!0QK0Uibq zfg0QlZUUEpKfW;teg=LDz70ML?gAQo5Olz0;2iM6`9bgla4#5wE5JqIrSpQ|C*T{P z0EfVN;16#If**qWz!+Qw_JC#ZR`9~>(Jpurd>4EU2(Shs5Q2ArGe7`-{kkCd4)_wd z2Yed52mA(||2lX8+yhp@Mc}uu4T9&vli*(PW$<}02G@a$z=hx(@aJ=a;1qZfJPn=# z-vS2M55V;B4^H*+K9ucno|6+z0Le5{$t|!9lPJ_JE7QJHbC*69mtJ z2f-)7E#Q6NQt&S%V}1vI3?2b@g3o|G;1tIB3GgHEICvO51ik}XtR3YPTSr4{CE#kVA z)mF&!yt}rw?#|EP{ITmjqsH9EH?h-@Gk9 z5cPcRC0h1{q#y*AqP?!^qawL_re&krap__D za-%LFV|%{TXkT%?(NCqGy}t)1ScGgTPSmm#D{Q`z>Xuxll@zY_ah0WEAq$bpoJ?SA z@1X+nh;=lYs7Y>Ilc-) zLgc!Fkn0!9XG*PWH$~pubYrSwp1y1ernGMj>d`zU2cdiT$+{_8Xk5pXOmtJ%0pFtm z)T#^b-ASp6lPVXtYII7bQ~7hmExZxhDeGn&#kB?eIdwY{>KY;E%q1^G2z3xO8l#wCXnmcEZGF=^dkAS{gw-Ry-)>64 zWk)p}-|4y>k*YJTcNziQeV9WS{=*VciFl?TBbBCgh6z3ziKNdHUQ{~*^-PsRo@(K` zV(&}kz;$F9?zgS?R(OsbwX-l`8P98;rdv$rELQnYj=D0JcdCq=2dR+Xq6uu73Y zRjQPwiYH8!38MWR!|QwHXb1)UlzR2Tp3l5ez0a~qn6e&-XvBGPjCIT!q zHT1AlTaUxrpHhpkny7FH{moKGv)ENK$Bs88jNE~yncXfpci|gSXJ(uXLnfF_O-31XKXIgeE;@)PMni{dK z8;DZ5_-FSV*n626V75;yY{kpi0c>uyYfspigp_gX;`Z*r8S(n>R2{4J)MutOn)$m^ zaJn8gg76$MP>R+>b5V`6Uf2l6T$2+vmu(th#SLmBIFQw#jyJY#V4&gYf@X=FcG_5$ z1pQ8_sgXQ|BB{S@(}=G-nw}A{qE>LaH%b)kzC~dIy048sNs!j6*@<;pZ8Kt6eYQ;~ z7fmDrl&PXqj9hHMCSyOkemV0lfJjn}N(j=(cCsyfB3*1`q3YflSyM{0t1b#vB22Kg zgT94C40)Ya{Y{?MqK~kJN@$5TgGb?f%?dChpv}H%^(e~_Qc}P8YudhHq{wH<1lXmL z5q50XjnA2-z`9?E4X}R$Jr-T5buDyv@50^#CJ=~N4!00Eo5~r2zNSM;QVWX05XZ-178I>$iN7!fOmn5!G+-O z=;zOv=(SB@Cp_%2Ryx{L;9CZ zd{!cBcBx3lyCcbFhRo$OP3Q8l$Bg)F*23+8$AYKTxF3&2lkKGRw@DseYs!#NL76|T z@RH|Ba(9Hlo|_I3$JDSwG6QGiX_jx>5tX*l=D6@-It{tHa)B-+bRfxQjy3+2NO=|< z2Ly6}37!`qbFA_{rE;ffR9oj9yV|Aq=0%1aXdgM4bgPe)6Y?(3Knv*7e(c!oNy-Q* zMXlOY<^GPd20aJBzsI_}DA^9J?OnN;l*o0*{j%`t;tYmFb1;2&)3L{%K2jxQp?Rbg zF)H?f3=U99ZPJJIOlIb$d5z3!pE4c(!OnaI%k=pW>4`p)XIZ1rw#Ps76EVneC~JIR z(Tufwieycp3qj8p?CI8=*j%w5s~R~!JRCswX7&uVA1cpea9rBbc7fE|sr*LH3q7Md zQl~MJ=Qw9dI-J1@O*Y8Z6*vtB$Y_n}*+eJ{I>PNHR_6(xe}%kGj2U)_xyptqr>yX9 zg=(~Gp+<%=g_CVUg3N?dIGJ&`x^%2Ho|)v{MKB^X$h(Q-M5tm_gypt@pa(>+a7Uxf zGCBEa!rq8DIU^Z~WO{}SaiYTtr{zMayt&;ZQ~a3k5Y`1Usj+#mWgTSJe|FaFd*D(a zG@;@9+iFImr(d>aGZDPBS2DbnYdkaX^BK8ObakhY>k0BvROm|!m11&?#Ps16wQSom zPeGkx$WCqz5VAszL;~D$to*=H2d1rgx$Rw``f$>xe3Wl^IONF8Ii;Yltpn+Gkt1JS M33d(2?c=Ne087$n)Bpeg From c4dc0f52c3fbb0b195a23645ebdc78991abb332d Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Mon, 11 Jul 2016 16:05:06 +0100 Subject: [PATCH 139/335] adds test to check json fields on simple request and changes the url request format --- app/assets/javascripts/api.js.coffee | 2 +- app/assets/javascripts/gl_dropdown.js.coffee | 1 - lib/api/projects.rb | 2 +- spec/javascripts/project_title_spec.js.coffee | 2 +- spec/requests/api/projects_spec.rb | 10 ++++++++++ 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee index 8028e66f089..89b0ac697ed 100644 --- a/app/assets/javascripts/api.js.coffee +++ b/app/assets/javascripts/api.js.coffee @@ -3,7 +3,7 @@ groupPath: "/api/:version/groups/:id.json" namespacesPath: "/api/:version/namespaces.json" groupProjectsPath: "/api/:version/groups/:id/projects.json" - projectsPath: "/api/:version/projects.json?format=simple" + projectsPath: "/api/:version/projects.json?simple=true" labelsPath: "/api/:version/projects/:id/labels" licensePath: "/api/:version/licenses/:key" gitignorePath: "/api/:version/gitignores/:key" diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 4743b484d22..1c65e833d47 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -401,7 +401,6 @@ class GitLabDropdown selected = true # Set URL - console.log(data) if @options.url? url = @options.url(data) else diff --git a/lib/api/projects.rb b/lib/api/projects.rb index c46764c4897..7aea553bdca 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -25,7 +25,7 @@ module API @projects = current_user.authorized_projects @projects = filter_projects(@projects) @projects = paginate @projects - if params["format"] + if params["simple"] present @projects, with: Entities::BasicProjectWithAccess, user: current_user else present @projects, with: Entities::ProjectWithAccess, user: current_user diff --git a/spec/javascripts/project_title_spec.js.coffee b/spec/javascripts/project_title_spec.js.coffee index e49dfbf1ba4..0244119fa0e 100644 --- a/spec/javascripts/project_title_spec.js.coffee +++ b/spec/javascripts/project_title_spec.js.coffee @@ -22,7 +22,7 @@ describe 'Project Title', -> @projects_data = fixture.load('projects.json')[0] spyOn(jQuery, 'ajax').and.callFake (req) => - expect(req.url).toBe('/api/v3/projects.json?format=simple') + expect(req.url).toBe('/api/v3/projects.json?simple=true') d = $.Deferred() d.resolve @projects_data d.promise() diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 8a52725a893..2a0b56c5052 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -81,6 +81,16 @@ describe API::API, api: true do expect(json_response.first.keys).not_to include('open_issues_count') end + context 'GET /projects?simple=true' do + let(:keys) { ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace", "permissions"] } + it 'should return a simplified version of all the projects' do + get api('/projects?simple=true', user) + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first.keys).to match_array keys + end + end + context 'and using search' do it 'should return searched project' do get api('/projects', user), { search: project.name } From a4678edde4d1b2257b1173a4475ab1ba5bdbc228 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Mon, 11 Jul 2016 18:42:23 +0100 Subject: [PATCH 140/335] moves let variable to it statement by using a local variable --- spec/requests/api/projects_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 2a0b56c5052..23b0a2a8885 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -82,12 +82,12 @@ describe API::API, api: true do end context 'GET /projects?simple=true' do - let(:keys) { ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace", "permissions"] } it 'should return a simplified version of all the projects' do + expected_keys = ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace", "permissions"] get api('/projects?simple=true', user) expect(response).to have_http_status(200) expect(json_response).to be_an Array - expect(json_response.first.keys).to match_array keys + expect(json_response.first.keys).to match_array expected_keys end end From be3409ab7ad3a8bf7b0c9eecb588598869459741 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Tue, 12 Jul 2016 10:43:08 +0100 Subject: [PATCH 141/335] changes string to symbol in param --- lib/api/projects.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 7aea553bdca..844547665ef 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -25,7 +25,7 @@ module API @projects = current_user.authorized_projects @projects = filter_projects(@projects) @projects = paginate @projects - if params["simple"] + if params[:simple] present @projects, with: Entities::BasicProjectWithAccess, user: current_user else present @projects, with: Entities::ProjectWithAccess, user: current_user From ded67d3b68b438a71bb3771865981c3c7d0b3730 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Wed, 6 Jul 2016 10:15:41 +0100 Subject: [PATCH 142/335] implements filter_params --- lib/api/entities.rb | 2 ++ lib/api/helpers.rb | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index b62afb4bb4c..8673350b927 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -353,7 +353,9 @@ module API class ProjectWithAccess < Project expose :permissions do expose :project_access, using: Entities::ProjectAccess do |project, options| + project = Project.find_by(project[:id]) project.project_members.find_by(user_id: options[:user].id) + ] end expose :group_access, using: Entities::GroupAccess do |project, options| diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 77e407b54c5..3a1837effd8 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -287,6 +287,23 @@ module API # Projects helpers + def filter_params(projects) + project_entries = [] + + # Removes the redundant information of the object + projects.each do |project| + entry = { + id: project.id, + http_url_to_repo: project.http_url_to_repo, + name_with_namespace: project.name_with_namespace + } + + project_entries << entry + end + + project_entries + end + def filter_projects(projects) # If the archived parameter is passed, limit results accordingly if params[:archived].present? From 2179c4052e034e62867749043d53bae7eaf048d7 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Wed, 6 Jul 2016 17:53:40 +0100 Subject: [PATCH 143/335] adds basic functionality to the new endpoint of the api --- lib/api/entities.rb | 8 ++++++-- lib/api/helpers.rb | 17 ----------------- lib/api/projects.rb | 11 +++++++++++ 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 8673350b927..1ecf50cd595 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -91,6 +91,12 @@ module API end end + class SimpleProject < Grape::Entity + expose :id + expose :name, :name_with_namespace + expose :http_url_to_repo + end + class ProjectMember < UserBasic expose :access_level do |user, options| options[:project].project_members.find_by(user_id: user.id).access_level @@ -353,9 +359,7 @@ module API class ProjectWithAccess < Project expose :permissions do expose :project_access, using: Entities::ProjectAccess do |project, options| - project = Project.find_by(project[:id]) project.project_members.find_by(user_id: options[:user].id) - ] end expose :group_access, using: Entities::GroupAccess do |project, options| diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 3a1837effd8..77e407b54c5 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -287,23 +287,6 @@ module API # Projects helpers - def filter_params(projects) - project_entries = [] - - # Removes the redundant information of the object - projects.each do |project| - entry = { - id: project.id, - http_url_to_repo: project.http_url_to_repo, - name_with_namespace: project.name_with_namespace - } - - project_entries << entry - end - - project_entries - end - def filter_projects(projects) # If the archived parameter is passed, limit results accordingly if params[:archived].present? diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 844547665ef..9448af92a98 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -32,6 +32,17 @@ module API end end + # Get a simplified project list for authenticated user + # + # Example Request: + # GET /projects/simple + get '/simple' do + @projects = current_user.authorized_projects + @projects = filter_projects(@projects) + @projects = paginate @projects + present @projects, with: Entities::SimpleProjectWithAccess, user: current_user + end + # Get an owned projects list for authenticated user # # Example Request: From 10c5eea5029e931efb474b68112840614e52675b Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Thu, 7 Jul 2016 11:55:31 +0100 Subject: [PATCH 144/335] gets the new object through /simple endpoint and renders on the dropdown --- app/assets/javascripts/gl_dropdown.js.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 1c65e833d47..e226943a4c1 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -123,6 +123,7 @@ class GitLabDropdownRemote # Fetch the data by calling the data funcfion @dataEndpoint "", (data) => + console.log(data) if @options.success @options.success(data) From 2a161e7a10574b1678803843585686a93150f686 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Thu, 7 Jul 2016 11:55:58 +0100 Subject: [PATCH 145/335] removes debugging print --- app/assets/javascripts/gl_dropdown.js.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index e226943a4c1..1c65e833d47 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -123,7 +123,6 @@ class GitLabDropdownRemote # Fetch the data by calling the data funcfion @dataEndpoint "", (data) => - console.log(data) if @options.success @options.success(data) From 8d9e649c241be6a62a47201b57863a78c94e6f01 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 8 Jul 2016 09:47:09 +0100 Subject: [PATCH 146/335] changes the usage of simpleprojectdetails to already implemented basicprojectsdetails and changes the url to a more reader friendly format --- lib/api/entities.rb | 6 ------ lib/api/projects.rb | 11 ----------- 2 files changed, 17 deletions(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 1ecf50cd595..b62afb4bb4c 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -91,12 +91,6 @@ module API end end - class SimpleProject < Grape::Entity - expose :id - expose :name, :name_with_namespace - expose :http_url_to_repo - end - class ProjectMember < UserBasic expose :access_level do |user, options| options[:project].project_members.find_by(user_id: user.id).access_level diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 9448af92a98..844547665ef 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -32,17 +32,6 @@ module API end end - # Get a simplified project list for authenticated user - # - # Example Request: - # GET /projects/simple - get '/simple' do - @projects = current_user.authorized_projects - @projects = filter_projects(@projects) - @projects = paginate @projects - present @projects, with: Entities::SimpleProjectWithAccess, user: current_user - end - # Get an owned projects list for authenticated user # # Example Request: From 9018f46b87940375fc2666ba6c5b38876965cc79 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 8 Jul 2016 11:17:37 +0100 Subject: [PATCH 147/335] changes the project_title_spec accordingly --- spec/javascripts/project_title_spec.js.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/javascripts/project_title_spec.js.coffee b/spec/javascripts/project_title_spec.js.coffee index 0244119fa0e..d8fa126ffdd 100644 --- a/spec/javascripts/project_title_spec.js.coffee +++ b/spec/javascripts/project_title_spec.js.coffee @@ -22,6 +22,7 @@ describe 'Project Title', -> @projects_data = fixture.load('projects.json')[0] spyOn(jQuery, 'ajax').and.callFake (req) => + expect(req.url).toBe('/api/v3/projects.json?simple=true') d = $.Deferred() d.resolve @projects_data From 84346da058ff9886bc9b4288de0ccbcdc69c78a9 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 8 Jul 2016 12:06:39 +0100 Subject: [PATCH 148/335] fixes missing field on basicprojectdetails --- .Gemfile.swm | Bin 0 -> 16384 bytes .Gemfile.swn | Bin 0 -> 16384 bytes app/assets/javascripts/gl_dropdown.js.coffee | 1 + 3 files changed, 1 insertion(+) create mode 100644 .Gemfile.swm create mode 100644 .Gemfile.swn diff --git a/.Gemfile.swm b/.Gemfile.swm new file mode 100644 index 0000000000000000000000000000000000000000..c5905cff7932aba6a13e5bafc60086613e1d4416 GIT binary patch literal 16384 zcmeI3U5qS66~`M8L?>Z54KP8FvrKD&>Rj$b6uZO_8c16L}SG$jbfPJtVTB zOvNi#+Wy*FptZnjw7~hn(qeCcgy%Y!u?sJ_;WggZinSJKEznw^wLoiu)&i{sS_`xm zXf5#nV1cSQE4Tw4In#CKPWO4nj?b6>ZLbI1?|1DeKg<2S>OL=Z75IAG&+SKRfz|@8 z1zHQV7HBQdTA;N+Yk}4Rtp!>Ov=(SB@ISBsPlDiFw0k)v0Py_ZpZ{NcOA!14{0ck- z9t1VG8QcUe0e^aP5c~rC9DEmi4%`Ja_z>uT%fLC{h4X{pN8lbX1XqBIz)R-^!Oy_A zKmiVc^S~e96a+s8_kuCF3hV*P;O*drH=V3^`El?Q@ECXqJP5uBCg9_s2SPwT@qW-; zB2NOwMj~VLbuMF7=HWz@8=}P98fhxZ`ODe-?N_peXgOM(caj|^*|BBI(Sc}TJ{Xm% zF4&4IV~Gmp*lJOvGUk<3In$!t6lD;Ywh}oUZn?UbqJ?N_9@1<0Q9FTLZK#nfrIYDJ zd!v2y{mLtt`A*u*F`g%ETvdf$>2^)~IvOc8N<|c_tUFX?opt9ft5hN5ZdnhuLM`ID zl+{+q^SryZweKeR;X%JxUq@ZXg!nJ&;>QM~H8~k9F8dz993ugh{Y7T%MZF#@Mb_pz zmNHRsrO3w2Sh*MNp?;b2iQJHJs;aT8VtygoANiZ(QmAyMayvwO%rH>psvL#XU*Ehf zKM?hN?Il|Fg`^+^mZH6`>7ydKdZuNg+H$nis8)(3=4Bx&uNr!`gmMg`Q5~=TjO#&| z@p7XsAY*&J)M#IEz0pslp1r>ZCs>4RDNfX~6f11Lk?NLQrj-<~_HmV^VId2V%A8DK zYww`~@`!abny5)`T;tl~>xWrUs#s_(^O1F}jus*bhqd$GMJT?9?!@>fEa4URV)8a8 z0?lmYt93P2r95dI+KJWquo3G;%TyEmj`4|R8e_{x!g=&iVN7_up$i^+y%!>QgzFcT zt3u?uf{^PM%4bTgYd1yS+;n5AVxGQY38u7f4eHT6B?qB<_{q8{T4-FyluUF}*8$(7 z0o1As@7+nMijyiAw`z1src?QSq%!6*dTz#G4T9{3>zuXVH>DKigl~$e)lB1a>>9if zrWvo$|1rHU=9?PxES2OdG}4Q9u&!NQKkTa9;F-*MDN$d?M5^AtXrTiYj_?r*DE7D! zAnS*)2Px}j9L2Q-{5f?y66zWu=gcK9L9FeLst#=v$+#AXmw4$fl_y21yH=H`9I#4} zKvk-grHUs^l?kH#9K-8?>_)^gHwN~#z`n|I$uXP46xus&dYEQCd~e30vrUSI6jOH^ zqfL}CfnK6rnF!w9b^}H+D|jio8P_mS6h*f2@rf1ti`DKhAJB~5U=vh`7O+V1l*tTn zV^bJEq`qO=lQ*Gra!~SeD`MARmJjQce$f?ELl%!QU_#T#t*stm6fB&Jx=!Q6Iem|U z9R!b{4JgidOd*QeIb>d&Tv@@VZwhiBysd&?R`4DS1eDF}k~%C^#yCU0Fj}FsM8Mf{ zZ4OE`!IJA5T(s>Sv_GEaQT5``4FbhFA9FAj%f86tatjWYI00I%eH1BAl(E8Vq9y_? zH8u3GR9lb3+n-X4u$riF2>s1cN3+;fGRKZLC5+sGrkUL?ICtS2QfFqNv6H`PS;X*q zSbVA#zBQgRU;1*hcxbZqv4X=`*f4N365T4Db6DYhOj3FyKU#+OG(RZy8)MGgqV43$@fZYWVAZJ>3E8^Z}n3@`~ zts96^x%g-I9N2rA7+|(fD{RHf*a2*AwQEn*DtA!5Q)T?^GSD_0(skHJbUm zQ*gQ-HiGaRF;I%uL~~J%vtHN;#$1yVHkWN0VZ{w4Ij7oOaq+ zmIVDysi~1Xg(9iHY}1IZJDQ#mv7%ORx;IJ`?Y>1}0=ln_K5egkeRg7z6a{0*EBlsDvPmY$w~&C(^}67OL)@ku{|>yXvA) zCBg(-JLp?T#E{o%)!*c4E&2#ssDzeiGk6rv*Q@|D0^01GR*$j_Atm*TzozXQMv8pa zn!xz=j_tbfIkOa4_Y1KB_HUraqARtoh3@WM*n7YP0ujsM76NBeIYZFbbVx~RK~Y#D z=n1aT8w`Yrw|VUMaWG7wax89MCAT>|+Wd|-eJ&ZS^r$IzqQQ0iFMQI0s)(=VYA!{qy@% zINv`Feht0@J`HXF$H6{u0eBmr9Kd7XOW+gW7SIJR<81#lcnI7H1h@)Z3Em0b0se+_ z{tMuF@Emvw+y^G$X0Qx8;1cj&a4z^O&i<#spTU#hm*5fb1Mm&-b&!J$jKB(b54ady z2>yY7{vDhG&w$^6$HBwk+u+Nf1Z0mRpuJiPv=(SB&|09iKx={40<8sJ#RBGlr?+%S z|FVhCN@UG070Gya#M#V{xtylyTt4=g5ueRkxE=6V@U$BDzrd(yY$|?$dCi=BL|ai^^tNy-o+Vc0bSaU9lJeA z86l;pRhz2Z-*MKU=K%QkSa%mC+o83+D;JXzx$d}M7G7PP!H{SUrq6CV_Sn-$s)Q^w zkF+92#XgY10V=6Y`jDQ<%-l4uky-6iro%tjnXh1(J|7}I(MR$uYZTh{_-B411{n@z zjSnoEv35_9tSNLM==p*@-I^1dE7oIGBj<;Q1IXUYo}uxZT9+Ji+s?kk^SZ!wxZ5*)Zjl z72d5-jdm^6$S|gGvQ0>knQ#gxGwxQGj zTndCHG<<(s&1m%W%hqfrf|vG6hPQH!X9j*gBR7h!?i6x8K|YEKeQBXmOpcM5KD?rq zZCmCks8bBt$*loGR;ZCkfLo50A2{m3v^6icy$e(yPWqIO@(mA%9GN+%6!f)qAiXYf O8_b6w!5ou zSN9Hkqo81n3QAA|nh=l&6ZJt79>n+}`hW_G_$U~O=z~{c;;R}z{--{AX7{pz#0L}8 zo%}MhQ>Uv=ojP@@>U8g5;Um|rvwhKWfa}dc@MwO=jZg5$&b<2lX9ShxBb5(SCDO5? z@?Ea=gGa(dgvUudT#Qnlzr5h>+bZnpGVUIdRmun5k@-L+n<7<3Ch{uWkd^zndq`wM znTnUMwEeZUKx=_lX@T>DrN!O?3D0#dV;5dhcn6>BZfTA;N+Yk}4Rtp!>Ov=(SB z&|2XC!2(rrR&WP8a;EFdo$m9D9iRVp*Msi&yLObH<^EoEpO?A{d_C^x_M^2xYk}4R ztp!>Ov=(SB&|09iKx={40<8sF3$zyaA6S4VL2xeGy_^yNc>eFt|1Z8N2!0QK0Uibq zfg0QlZUUEpKfW;teg=LDz70ML?gAQo5Olz0;2iM6`9bgla4#5wE5JqIrSpQ|C*T{P z0EfVN;16#If**qWz!+Qw_JC#ZR`9~>(Jpurd>4EU2(Shs5Q2ArGe7`-{kkCd4)_wd z2Yed52mA(||2lX8+yhp@Mc}uu4T9&vli*(PW$<}02G@a$z=hx(@aJ=a;1qZfJPn=# z-vS2M55V;B4^H*+K9ucno|6+z0Le5{$t|!9lPJ_JE7QJHbC*69mtJ z2f-)7E#Q6NQt&S%V}1vI3?2b@g3o|G;1tIB3GgHEICvO51ik}XtR3YPTSr4{CE#kVA z)mF&!yt}rw?#|EP{ITmjqsH9EH?h-@Gk9 z5cPcRC0h1{q#y*AqP?!^qawL_re&krap__D za-%LFV|%{TXkT%?(NCqGy}t)1ScGgTPSmm#D{Q`z>Xuxll@zY_ah0WEAq$bpoJ?SA z@1X+nh;=lYs7Y>Ilc-) zLgc!Fkn0!9XG*PWH$~pubYrSwp1y1ernGMj>d`zU2cdiT$+{_8Xk5pXOmtJ%0pFtm z)T#^b-ASp6lPVXtYII7bQ~7hmExZxhDeGn&#kB?eIdwY{>KY;E%q1^G2z3xO8l#wCXnmcEZGF=^dkAS{gw-Ry-)>64 zWk)p}-|4y>k*YJTcNziQeV9WS{=*VciFl?TBbBCgh6z3ziKNdHUQ{~*^-PsRo@(K` zV(&}kz;$F9?zgS?R(OsbwX-l`8P98;rdv$rELQnYj=D0JcdCq=2dR+Xq6uu73Y zRjQPwiYH8!38MWR!|QwHXb1)UlzR2Tp3l5ez0a~qn6e&-XvBGPjCIT!q zHT1AlTaUxrpHhpkny7FH{moKGv)ENK$Bs88jNE~yncXfpci|gSXJ(uXLnfF_O-31XKXIgeE;@)PMni{dK z8;DZ5_-FSV*n626V75;yY{kpi0c>uyYfspigp_gX;`Z*r8S(n>R2{4J)MutOn)$m^ zaJn8gg76$MP>R+>b5V`6Uf2l6T$2+vmu(th#SLmBIFQw#jyJY#V4&gYf@X=FcG_5$ z1pQ8_sgXQ|BB{S@(}=G-nw}A{qE>LaH%b)kzC~dIy048sNs!j6*@<;pZ8Kt6eYQ;~ z7fmDrl&PXqj9hHMCSyOkemV0lfJjn}N(j=(cCsyfB3*1`q3YflSyM{0t1b#vB22Kg zgT94C40)Ya{Y{?MqK~kJN@$5TgGb?f%?dChpv}H%^(e~_Qc}P8YudhHq{wH<1lXmL z5q50XjnA2-z`9?E4X}R$Jr-T5buDyv@50^#CJ=~N4!00Eo5~r2zNSM;QVWX05XZ-178I>$iN7!fOmn5!G+-O z=;zOv=(SB@Cp_%2Ryx{L;9CZ zd{!cBcBx3lyCcbFhRo$OP3Q8l$Bg)F*23+8$AYKTxF3&2lkKGRw@DseYs!#NL76|T z@RH|Ba(9Hlo|_I3$JDSwG6QGiX_jx>5tX*l=D6@-It{tHa)B-+bRfxQjy3+2NO=|< z2Ly6}37!`qbFA_{rE;ffR9oj9yV|Aq=0%1aXdgM4bgPe)6Y?(3Knv*7e(c!oNy-Q* zMXlOY<^GPd20aJBzsI_}DA^9J?OnN;l*o0*{j%`t;tYmFb1;2&)3L{%K2jxQp?Rbg zF)H?f3=U99ZPJJIOlIb$d5z3!pE4c(!OnaI%k=pW>4`p)XIZ1rw#Ps76EVneC~JIR z(Tufwieycp3qj8p?CI8=*j%w5s~R~!JRCswX7&uVA1cpea9rBbc7fE|sr*LH3q7Md zQl~MJ=Qw9dI-J1@O*Y8Z6*vtB$Y_n}*+eJ{I>PNHR_6(xe}%kGj2U)_xyptqr>yX9 zg=(~Gp+<%=g_CVUg3N?dIGJ&`x^%2Ho|)v{MKB^X$h(Q-M5tm_gypt@pa(>+a7Uxf zGCBEa!rq8DIU^Z~WO{}SaiYTtr{zMayt&;ZQ~a3k5Y`1Usj+#mWgTSJe|FaFd*D(a zG@;@9+iFImr(d>aGZDPBS2DbnYdkaX^BK8ObakhY>k0BvROm|!m11&?#Ps16wQSom zPeGkx$WCqz5VAszL;~D$to*=H2d1rgx$Rw``f$>xe3Wl^IONF8Ii;Yltpn+Gkt1JS M33d(2?c=Ne087$n)Bpeg literal 0 HcmV?d00001 diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 1c65e833d47..4743b484d22 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -401,6 +401,7 @@ class GitLabDropdown selected = true # Set URL + console.log(data) if @options.url? url = @options.url(data) else From 9102ad1fb5db175238e9ef897c9fa1db0ba4614e Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Fri, 8 Jul 2016 12:07:17 +0100 Subject: [PATCH 149/335] removes gemfile.lock dotfiles --- .Gemfile.swm | Bin 16384 -> 0 bytes .Gemfile.swn | Bin 16384 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .Gemfile.swm delete mode 100644 .Gemfile.swn diff --git a/.Gemfile.swm b/.Gemfile.swm deleted file mode 100644 index c5905cff7932aba6a13e5bafc60086613e1d4416..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeI3U5qS66~`M8L?>Z54KP8FvrKD&>Rj$b6uZO_8c16L}SG$jbfPJtVTB zOvNi#+Wy*FptZnjw7~hn(qeCcgy%Y!u?sJ_;WggZinSJKEznw^wLoiu)&i{sS_`xm zXf5#nV1cSQE4Tw4In#CKPWO4nj?b6>ZLbI1?|1DeKg<2S>OL=Z75IAG&+SKRfz|@8 z1zHQV7HBQdTA;N+Yk}4Rtp!>Ov=(SB@ISBsPlDiFw0k)v0Py_ZpZ{NcOA!14{0ck- z9t1VG8QcUe0e^aP5c~rC9DEmi4%`Ja_z>uT%fLC{h4X{pN8lbX1XqBIz)R-^!Oy_A zKmiVc^S~e96a+s8_kuCF3hV*P;O*drH=V3^`El?Q@ECXqJP5uBCg9_s2SPwT@qW-; zB2NOwMj~VLbuMF7=HWz@8=}P98fhxZ`ODe-?N_peXgOM(caj|^*|BBI(Sc}TJ{Xm% zF4&4IV~Gmp*lJOvGUk<3In$!t6lD;Ywh}oUZn?UbqJ?N_9@1<0Q9FTLZK#nfrIYDJ zd!v2y{mLtt`A*u*F`g%ETvdf$>2^)~IvOc8N<|c_tUFX?opt9ft5hN5ZdnhuLM`ID zl+{+q^SryZweKeR;X%JxUq@ZXg!nJ&;>QM~H8~k9F8dz993ugh{Y7T%MZF#@Mb_pz zmNHRsrO3w2Sh*MNp?;b2iQJHJs;aT8VtygoANiZ(QmAyMayvwO%rH>psvL#XU*Ehf zKM?hN?Il|Fg`^+^mZH6`>7ydKdZuNg+H$nis8)(3=4Bx&uNr!`gmMg`Q5~=TjO#&| z@p7XsAY*&J)M#IEz0pslp1r>ZCs>4RDNfX~6f11Lk?NLQrj-<~_HmV^VId2V%A8DK zYww`~@`!abny5)`T;tl~>xWrUs#s_(^O1F}jus*bhqd$GMJT?9?!@>fEa4URV)8a8 z0?lmYt93P2r95dI+KJWquo3G;%TyEmj`4|R8e_{x!g=&iVN7_up$i^+y%!>QgzFcT zt3u?uf{^PM%4bTgYd1yS+;n5AVxGQY38u7f4eHT6B?qB<_{q8{T4-FyluUF}*8$(7 z0o1As@7+nMijyiAw`z1src?QSq%!6*dTz#G4T9{3>zuXVH>DKigl~$e)lB1a>>9if zrWvo$|1rHU=9?PxES2OdG}4Q9u&!NQKkTa9;F-*MDN$d?M5^AtXrTiYj_?r*DE7D! zAnS*)2Px}j9L2Q-{5f?y66zWu=gcK9L9FeLst#=v$+#AXmw4$fl_y21yH=H`9I#4} zKvk-grHUs^l?kH#9K-8?>_)^gHwN~#z`n|I$uXP46xus&dYEQCd~e30vrUSI6jOH^ zqfL}CfnK6rnF!w9b^}H+D|jio8P_mS6h*f2@rf1ti`DKhAJB~5U=vh`7O+V1l*tTn zV^bJEq`qO=lQ*Gra!~SeD`MARmJjQce$f?ELl%!QU_#T#t*stm6fB&Jx=!Q6Iem|U z9R!b{4JgidOd*QeIb>d&Tv@@VZwhiBysd&?R`4DS1eDF}k~%C^#yCU0Fj}FsM8Mf{ zZ4OE`!IJA5T(s>Sv_GEaQT5``4FbhFA9FAj%f86tatjWYI00I%eH1BAl(E8Vq9y_? zH8u3GR9lb3+n-X4u$riF2>s1cN3+;fGRKZLC5+sGrkUL?ICtS2QfFqNv6H`PS;X*q zSbVA#zBQgRU;1*hcxbZqv4X=`*f4N365T4Db6DYhOj3FyKU#+OG(RZy8)MGgqV43$@fZYWVAZJ>3E8^Z}n3@`~ zts96^x%g-I9N2rA7+|(fD{RHf*a2*AwQEn*DtA!5Q)T?^GSD_0(skHJbUm zQ*gQ-HiGaRF;I%uL~~J%vtHN;#$1yVHkWN0VZ{w4Ij7oOaq+ zmIVDysi~1Xg(9iHY}1IZJDQ#mv7%ORx;IJ`?Y>1}0=ln_K5egkeRg7z6a{0*EBlsDvPmY$w~&C(^}67OL)@ku{|>yXvA) zCBg(-JLp?T#E{o%)!*c4E&2#ssDzeiGk6rv*Q@|D0^01GR*$j_Atm*TzozXQMv8pa zn!xz=j_tbfIkOa4_Y1KB_HUraqARtoh3@WM*n7YP0ujsM76NBeIYZFbbVx~RK~Y#D z=n1aT8w`Yrw|VUMaWG7wax89MCAT>|+Wd|-eJ&ZS^r$IzqQQ0iFMQI0s)(=VYA!{qy@% zINv`Feht0@J`HXF$H6{u0eBmr9Kd7XOW+gW7SIJR<81#lcnI7H1h@)Z3Em0b0se+_ z{tMuF@Emvw+y^G$X0Qx8;1cj&a4z^O&i<#spTU#hm*5fb1Mm&-b&!J$jKB(b54ady z2>yY7{vDhG&w$^6$HBwk+u+Nf1Z0mRpuJiPv=(SB&|09iKx={40<8sJ#RBGlr?+%S z|FVhCN@UG070Gya#M#V{xtylyTt4=g5ueRkxE=6V@U$BDzrd(yY$|?$dCi=BL|ai^^tNy-o+Vc0bSaU9lJeA z86l;pRhz2Z-*MKU=K%QkSa%mC+o83+D;JXzx$d}M7G7PP!H{SUrq6CV_Sn-$s)Q^w zkF+92#XgY10V=6Y`jDQ<%-l4uky-6iro%tjnXh1(J|7}I(MR$uYZTh{_-B411{n@z zjSnoEv35_9tSNLM==p*@-I^1dE7oIGBj<;Q1IXUYo}uxZT9+Ji+s?kk^SZ!wxZ5*)Zjl z72d5-jdm^6$S|gGvQ0>knQ#gxGwxQGj zTndCHG<<(s&1m%W%hqfrf|vG6hPQH!X9j*gBR7h!?i6x8K|YEKeQBXmOpcM5KD?rq zZCmCks8bBt$*loGR;ZCkfLo50A2{m3v^6icy$e(yPWqIO@(mA%9GN+%6!f)qAiXYf O8_b6w!5ou zSN9Hkqo81n3QAA|nh=l&6ZJt79>n+}`hW_G_$U~O=z~{c;;R}z{--{AX7{pz#0L}8 zo%}MhQ>Uv=ojP@@>U8g5;Um|rvwhKWfa}dc@MwO=jZg5$&b<2lX9ShxBb5(SCDO5? z@?Ea=gGa(dgvUudT#Qnlzr5h>+bZnpGVUIdRmun5k@-L+n<7<3Ch{uWkd^zndq`wM znTnUMwEeZUKx=_lX@T>DrN!O?3D0#dV;5dhcn6>BZfTA;N+Yk}4Rtp!>Ov=(SB z&|2XC!2(rrR&WP8a;EFdo$m9D9iRVp*Msi&yLObH<^EoEpO?A{d_C^x_M^2xYk}4R ztp!>Ov=(SB&|09iKx={40<8sF3$zyaA6S4VL2xeGy_^yNc>eFt|1Z8N2!0QK0Uibq zfg0QlZUUEpKfW;teg=LDz70ML?gAQo5Olz0;2iM6`9bgla4#5wE5JqIrSpQ|C*T{P z0EfVN;16#If**qWz!+Qw_JC#ZR`9~>(Jpurd>4EU2(Shs5Q2ArGe7`-{kkCd4)_wd z2Yed52mA(||2lX8+yhp@Mc}uu4T9&vli*(PW$<}02G@a$z=hx(@aJ=a;1qZfJPn=# z-vS2M55V;B4^H*+K9ucno|6+z0Le5{$t|!9lPJ_JE7QJHbC*69mtJ z2f-)7E#Q6NQt&S%V}1vI3?2b@g3o|G;1tIB3GgHEICvO51ik}XtR3YPTSr4{CE#kVA z)mF&!yt}rw?#|EP{ITmjqsH9EH?h-@Gk9 z5cPcRC0h1{q#y*AqP?!^qawL_re&krap__D za-%LFV|%{TXkT%?(NCqGy}t)1ScGgTPSmm#D{Q`z>Xuxll@zY_ah0WEAq$bpoJ?SA z@1X+nh;=lYs7Y>Ilc-) zLgc!Fkn0!9XG*PWH$~pubYrSwp1y1ernGMj>d`zU2cdiT$+{_8Xk5pXOmtJ%0pFtm z)T#^b-ASp6lPVXtYII7bQ~7hmExZxhDeGn&#kB?eIdwY{>KY;E%q1^G2z3xO8l#wCXnmcEZGF=^dkAS{gw-Ry-)>64 zWk)p}-|4y>k*YJTcNziQeV9WS{=*VciFl?TBbBCgh6z3ziKNdHUQ{~*^-PsRo@(K` zV(&}kz;$F9?zgS?R(OsbwX-l`8P98;rdv$rELQnYj=D0JcdCq=2dR+Xq6uu73Y zRjQPwiYH8!38MWR!|QwHXb1)UlzR2Tp3l5ez0a~qn6e&-XvBGPjCIT!q zHT1AlTaUxrpHhpkny7FH{moKGv)ENK$Bs88jNE~yncXfpci|gSXJ(uXLnfF_O-31XKXIgeE;@)PMni{dK z8;DZ5_-FSV*n626V75;yY{kpi0c>uyYfspigp_gX;`Z*r8S(n>R2{4J)MutOn)$m^ zaJn8gg76$MP>R+>b5V`6Uf2l6T$2+vmu(th#SLmBIFQw#jyJY#V4&gYf@X=FcG_5$ z1pQ8_sgXQ|BB{S@(}=G-nw}A{qE>LaH%b)kzC~dIy048sNs!j6*@<;pZ8Kt6eYQ;~ z7fmDrl&PXqj9hHMCSyOkemV0lfJjn}N(j=(cCsyfB3*1`q3YflSyM{0t1b#vB22Kg zgT94C40)Ya{Y{?MqK~kJN@$5TgGb?f%?dChpv}H%^(e~_Qc}P8YudhHq{wH<1lXmL z5q50XjnA2-z`9?E4X}R$Jr-T5buDyv@50^#CJ=~N4!00Eo5~r2zNSM;QVWX05XZ-178I>$iN7!fOmn5!G+-O z=;zOv=(SB@Cp_%2Ryx{L;9CZ zd{!cBcBx3lyCcbFhRo$OP3Q8l$Bg)F*23+8$AYKTxF3&2lkKGRw@DseYs!#NL76|T z@RH|Ba(9Hlo|_I3$JDSwG6QGiX_jx>5tX*l=D6@-It{tHa)B-+bRfxQjy3+2NO=|< z2Ly6}37!`qbFA_{rE;ffR9oj9yV|Aq=0%1aXdgM4bgPe)6Y?(3Knv*7e(c!oNy-Q* zMXlOY<^GPd20aJBzsI_}DA^9J?OnN;l*o0*{j%`t;tYmFb1;2&)3L{%K2jxQp?Rbg zF)H?f3=U99ZPJJIOlIb$d5z3!pE4c(!OnaI%k=pW>4`p)XIZ1rw#Ps76EVneC~JIR z(Tufwieycp3qj8p?CI8=*j%w5s~R~!JRCswX7&uVA1cpea9rBbc7fE|sr*LH3q7Md zQl~MJ=Qw9dI-J1@O*Y8Z6*vtB$Y_n}*+eJ{I>PNHR_6(xe}%kGj2U)_xyptqr>yX9 zg=(~Gp+<%=g_CVUg3N?dIGJ&`x^%2Ho|)v{MKB^X$h(Q-M5tm_gypt@pa(>+a7Uxf zGCBEa!rq8DIU^Z~WO{}SaiYTtr{zMayt&;ZQ~a3k5Y`1Usj+#mWgTSJe|FaFd*D(a zG@;@9+iFImr(d>aGZDPBS2DbnYdkaX^BK8ObakhY>k0BvROm|!m11&?#Ps16wQSom zPeGkx$WCqz5VAszL;~D$to*=H2d1rgx$Rw``f$>xe3Wl^IONF8Ii;Yltpn+Gkt1JS M33d(2?c=Ne087$n)Bpeg From da137ec320734632b75ab22dd35073feee694f13 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Mon, 11 Jul 2016 16:05:06 +0100 Subject: [PATCH 150/335] adds test to check json fields on simple request and changes the url request format --- app/assets/javascripts/gl_dropdown.js.coffee | 1 - spec/javascripts/project_title_spec.js.coffee | 1 - 2 files changed, 2 deletions(-) diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 4743b484d22..1c65e833d47 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -401,7 +401,6 @@ class GitLabDropdown selected = true # Set URL - console.log(data) if @options.url? url = @options.url(data) else diff --git a/spec/javascripts/project_title_spec.js.coffee b/spec/javascripts/project_title_spec.js.coffee index d8fa126ffdd..0244119fa0e 100644 --- a/spec/javascripts/project_title_spec.js.coffee +++ b/spec/javascripts/project_title_spec.js.coffee @@ -22,7 +22,6 @@ describe 'Project Title', -> @projects_data = fixture.load('projects.json')[0] spyOn(jQuery, 'ajax').and.callFake (req) => - expect(req.url).toBe('/api/v3/projects.json?simple=true') d = $.Deferred() d.resolve @projects_data From 9ec232014fe8c92a87607705a484068f0324a3fa Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Tue, 12 Jul 2016 10:43:43 -0500 Subject: [PATCH 151/335] Change sidebar drop shadow to rgba --- app/assets/stylesheets/framework/sidebar.scss | 2 +- app/assets/stylesheets/framework/variables.scss | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 99833ef842a..cec52678495 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -17,7 +17,7 @@ height: 100%; overflow: hidden; transition: width $sidebar-transition-duration; - @include box-shadow(2px 0 16px 0 $box-shadow-gray); + @include box-shadow(2px 0 16px 0 $black-transparent); } } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 230ed28438a..4337fab5d87 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -86,7 +86,6 @@ $todo-alert-blue: #428bca; $btn-side-margin: 10px; $btn-sm-side-margin: 7px; $btn-xs-side-margin: 5px; -$box-shadow-gray: #bbb; /* * Color schema From e7d9fcc1c9162271512edbd430d103c0697ccdbc Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Tue, 12 Jul 2016 17:59:21 +0200 Subject: [PATCH 152/335] API: Expose due_date for issues --- CHANGELOG | 1 + doc/api/issues.md | 29 ++++++++++++++++++++--------- lib/api/entities.rb | 1 + lib/api/issues.rb | 10 ++++++---- spec/requests/api/issues_spec.rb | 25 +++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 13 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 84bfc27b151..2dab994ecb8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -35,6 +35,7 @@ v 8.10.0 (unreleased) - Add notification settings dropdown for groups - Wildcards for protected branches. !4665 - Allow importing from Github using Personal Access Tokens. (Eric K Idema) + - API: Expose `due_date` for issues (Robert Schilling) - API: Todos !3188 (Robert Schilling) - API: Expose shared groups for projects and shared projects for groups !5050 (Robert Schilling) - Add "Enabled Git access protocols" to Application Settings diff --git a/doc/api/issues.md b/doc/api/issues.md index 3ced787b23e..419fb8f85d8 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -78,7 +78,8 @@ Example response: "iid" : 6, "labels" : [], "subscribed" : false, - "user_notes_count": 1 + "user_notes_count": 1, + "due_date": "2016-07-22" } ] ``` @@ -154,7 +155,8 @@ Example response: "updated_at" : "2016-01-04T15:31:46.176Z", "created_at" : "2016-01-04T15:31:46.176Z", "subscribed" : false, - "user_notes_count": 1 + "user_notes_count": 1, + "due_date": null } ] ``` @@ -232,7 +234,8 @@ Example response: "updated_at" : "2016-01-04T15:31:46.176Z", "created_at" : "2016-01-04T15:31:46.176Z", "subscribed" : false, - "user_notes_count": 1 + "user_notes_count": 1, + "due_date": "2016-07-22" } ] ``` @@ -295,7 +298,8 @@ Example response: "updated_at" : "2016-01-04T15:31:46.176Z", "created_at" : "2016-01-04T15:31:46.176Z", "subscribed": false, - "user_notes_count": 1 + "user_notes_count": 1, + "due_date": null } ``` @@ -320,6 +324,7 @@ POST /projects/:id/issues | `milestone_id` | integer | no | The ID of a milestone to assign issue | | `labels` | string | no | Comma-separated label names for an issue | | `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` | +| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | ```bash curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues?title=Issues%20with%20auth&labels=bug @@ -351,7 +356,8 @@ Example response: "updated_at" : "2016-01-07T12:44:33.959Z", "milestone" : null, "subscribed" : true, - "user_notes_count": 0 + "user_notes_count": 0, + "due_date": null } ``` @@ -379,6 +385,7 @@ PUT /projects/:id/issues/:issue_id | `labels` | string | no | Comma-separated label names for an issue | | `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it | | `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` | +| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | ```bash curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85?state_event=close @@ -410,7 +417,8 @@ Example response: "assignee" : null, "milestone" : null, "subscribed" : true, - "user_notes_count": 0 + "user_notes_count": 0, + "due_date": "2016-07-22" } ``` @@ -487,7 +495,8 @@ Example response: "state": "active", "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon", "web_url": "https://gitlab.example.com/u/solon.cremin" - } + }, + "due_date": null } ``` @@ -541,7 +550,8 @@ Example response: "state": "active", "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon", "web_url": "https://gitlab.example.com/u/solon.cremin" - } + }, + "due_date": null } ``` @@ -596,7 +606,8 @@ Example response: "avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon", "web_url": "https://gitlab.example.com/u/orville" }, - "subscribed": false + "subscribed": false, + "due_date": null } ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 301dbb688a7..40e2a487fe9 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -186,6 +186,7 @@ module API end expose :user_notes_count expose :upvotes, :downvotes + expose :due_date end class ExternalIssue < Grape::Entity diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 8a03a41e9c5..c588103e517 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -152,12 +152,13 @@ module API # milestone_id (optional) - The ID of a milestone to assign issue # labels (optional) - The labels of an issue # created_at (optional) - Date time string, ISO 8601 formatted + # due_date (optional) - Date time string in the format YEAR-MONTH-DAY # Example Request: # POST /projects/:id/issues - post ":id/issues" do + post ':id/issues' do required_attributes! [:title] - keys = [:title, :description, :assignee_id, :milestone_id] + keys = [:title, :description, :assignee_id, :milestone_id, :due_date] keys << :created_at if current_user.admin? || user_project.owner == current_user attrs = attributes_for_keys(keys) @@ -201,12 +202,13 @@ module API # labels (optional) - The labels of an issue # state_event (optional) - The state event of an issue (close|reopen) # updated_at (optional) - Date time string, ISO 8601 formatted + # due_date (optional) - Date time string in the format YEAR-MONTH-DAY # Example Request: # PUT /projects/:id/issues/:issue_id - put ":id/issues/:issue_id" do + put ':id/issues/:issue_id' do issue = user_project.issues.find(params[:issue_id]) authorize! :update_issue, issue - keys = [:title, :description, :assignee_id, :milestone_id, :state_event] + keys = [:title, :description, :assignee_id, :milestone_id, :state_event, :due_date] keys << :updated_at if current_user.admin? || user_project.owner == current_user attrs = attributes_for_keys(keys) diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 6adccb4ebae..12f2cfa6942 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -503,6 +503,20 @@ describe API::API, api: true do ]) end + context 'with due date' do + it 'creates a new project issue' do + due_date = 2.weeks.from_now.strftime('%Y-%m-%d') + + post api("/projects/#{project.id}/issues", user), + title: 'new issue', due_date: due_date + + expect(response).to have_http_status(201) + expect(json_response['title']).to eq('new issue') + expect(json_response['description']).to be_nil + expect(json_response['due_date']).to eq(due_date) + end + end + context 'when an admin or owner makes the request' do it 'accepts the creation date to be set' do creation_time = 2.weeks.ago @@ -683,6 +697,17 @@ describe API::API, api: true do end end + describe 'PUT /projects/:id/issues/:issue_id to update due date' do + it 'creates a new project issue' do + due_date = 2.weeks.from_now.strftime('%Y-%m-%d') + + put api("/projects/#{project.id}/issues/#{issue.id}", user), due_date: due_date + + expect(response).to have_http_status(200) + expect(json_response['due_date']).to eq(due_date) + end + end + describe "DELETE /projects/:id/issues/:issue_id" do it "rejects a non member from deleting an issue" do delete api("/projects/#{project.id}/issues/#{issue.id}", non_member) From e981d6cd0d6b8ae7d2911a57a65751deaa9ec555 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 12 Jul 2016 11:25:39 -0500 Subject: [PATCH 153/335] Extended regexes ignore whitespace, so use \s --- lib/gitlab/diff/inline_diff.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/diff/inline_diff.rb b/lib/gitlab/diff/inline_diff.rb index 72d9abeefcc..4a3eb92b9fc 100644 --- a/lib/gitlab/diff/inline_diff.rb +++ b/lib/gitlab/diff/inline_diff.rb @@ -4,7 +4,7 @@ module Gitlab # Regex to find a run of deleted lines followed by the same number of added lines REGEX = %r{ # Runs start at the beginning of the string (the first line) or after a space (for an unchanged line) - (?:\A| ) + (?:\A|\s) # This matches a number of `-`s followed by the same number of `+`s through recursion (? @@ -14,7 +14,7 @@ module Gitlab ) # Runs end at the end of the string (the last line) or before a space (for an unchanged line) - (?= |\z) + (?=\s|\z) }x.freeze attr_accessor :old_line, :new_line, :offset From 563b303bde6701fc91351701db651e8da68f9b80 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Tue, 12 Jul 2016 17:32:40 +0100 Subject: [PATCH 154/335] removes basicprojectwithaccess and replaces it with basicprojectdetails --- lib/api/.projects.rb.swn | Bin 0 -> 28672 bytes lib/api/entities.rb | 8 -------- lib/api/projects.rb | 2 +- 3 files changed, 1 insertion(+), 9 deletions(-) create mode 100644 lib/api/.projects.rb.swn diff --git a/lib/api/.projects.rb.swn b/lib/api/.projects.rb.swn new file mode 100644 index 0000000000000000000000000000000000000000..890811564d29fab383059a6165488d4f178b8832 GIT binary patch literal 28672 zcmeI54~!hwS-_XL23j|Dnkb0M(7Zd7+#NaZnZ%H?spUWM#aOYO!}cX<-Rm;9J9js| z-Pz5|tnG{I6co7IuzPMx)7^4Jif_50+H(A2!Fw|W&V)f@X0I2uoW+@C z^+h4a+*YUCcKv9}su$_xnU=RW<8-~5ZqRv$+lazyuvlC{nObU~)IhNYdePFBH(g%2 z@rEDRDg`!=kBO_UoG+FwQ%en$8YneTYM|6Wsew`hr3Ok3lp6S^)Iii-UwIc-cA37q zcj)hL%YDB}|9z+aUdtG_381*RU{4eIl~`uoA$ah+U#l^Q5D zP->vmK&gRJ1EmH^4U`%vHBf4x)Ih0$QUe#D0jF81TuHvqOM9FBe`Ei@u(4A4B0LEn zhTjAq7T|ig3_kg~O66zZR`{>WE0vSbh6VUh*bBG9Rj>iR_S#D2@8B=sLGWNVOu#c6 zDwVSkz!JO-j=~tc0V?o?*HkK>fe%0%ZiN?KU8y_|{|vti55og+H@pSj2w(lqO661V zv+z@JKPumS!ON65o)FT54r1XscraM1id9Ea=SMcPZY z*)!TtVl}-mpUwR6+TBhN)q6opOm@1F*YTa!R3(;>$B%iTx9GLJXszCo(HEAK*dn%y z#Wm4%mz-WJvNCmhi!HB_74?=x6!csXI&D`tp$Oe5^8Drg3buE1cQ7e16;skE99`tM z_qts-I!CF;y;W~`Ig357)jUTjZ8unUIj_5WZg{R5y)Z;-c%4l*Yy_Ta@T^wD75anF zp)|B@B4#N{Dq2j+lkrgQ6dggOEOlrD_qfTNWSDaTGDPUVX41^JxFv9%$jxNa$6UXu ze+f!-LxO$;Jr_(R%&9_kG#lp!&+@trYF*|l-Mr1&a&sr;$`=!>uajUhpU0x zNHZ=BVf7tN$%iOB2;r`>J2;!xZ^$z=)#7@f`5)R7fe z?As$cOTsxXMeXGb^@T}2J0fKCP^G>qW+L^mwHBx3|5dtZIDXw}wmsiyr6x$)G1=$^ z0a~d`p=nXeh)ieHXeNoYacm{`H_==ioOLHHx2w@`Lt0U0pkBMmN_@7aInLD%T70v( zL=7;C)=gjCsavL?yN;v_eQiP{1=&41Nh}mw@>&cx)3)JcBAvEcl0>Qce5y{Xl@#an zq7{0A*I@iK>rNPVmoa@@HqgWj@)N^GN?P9F7SaW77P5nrK^V0O)y-ueRUM_MgO9H2 zu~6(hm1+0q>M_qfF7G(?Fmf1K&7?^(dejGp>Qc)j>KfGJ69M$eT{f=P zC{^i{b`_b{y$JdpKCBDXdI_}OIqnZqxjHmd;YuRW<|yhGjxSU$qwY|&SVqJh*&a>< z6`q~FNAKPvs^4veZqgR%#GQ2i{#kps6M79jJ?wE=9kmMQ?W9mvd0lz850BPDmXX;uoo@ohS;zL{&m$JAx4E_|aN^HNJo@C)H|u zRczm`7T8l_hlr!5YqdL)#ruAi4y{^kZhrUveYc3(5Q#(k?$~u?);bj-Hgl2QF}aRn z;oTz!P=R-IYQns#MHWS+GMNdN;~ZN4GaNo0LUV=!62{FTkKI0 zOL|jhqtk0OMcZX?xhx*sAXA#Tc-iejx4zivw2;&~N$+;7!|0jPELpAUVYNeCcbym; zq}W8tsx7HYWvVva7K_@+T72?pUDzd}?R4vLdOhmY^UXG?3NSfV+*X&hvAL15)a~>F z6jU>J!fBxwkTUQ+tcjB>Dr;iq=-b~mvvB>4I3;tc(_D19XSy7>r}r^&ii3@o6NctS zABs1Ny@AtpYqec-`#8EeJt7m@oo0`vrTi)F|EIB|9cg1@|C{~yr?Bsv@Of&}W_zKux}wz$%OCP6Ml1?yx!0gtVyrBxAJ`G~HlwJTE3TpA6ZiIW=xH zSWt9B?X2Ls9aLy4FiLT9hiAaqsm-4e&d6&HD1beZ{_Lhb=)?_2Dl_he<4Ps<#kKK; zv^}IURA<+&C;r4WvRzEb{i_K)BKk*7OgJPY?P1lS+gNwsaXK)r4l%i7O5A>^f0Hsk zG$nQ&+#@E{_3z(z+pH9y8lT2IXOQNNev-zo-F(uFFgEgnwS`mHT20uOgG)L(*j2Od z;E~xw2Y2nC9xS5$J*g9pGn4wXwp^+Oju?9V>{M_~fK%0B#Ka39KrDYolA-0k3Co{$ISzGQal6mz#9wl^+~l+M~WktXRE zZ`blxPR!oiO*SBO7gUpU)eK~NF13FP9AG{ZVf~oX@|yS};hIVa~~I z6qtUi+tP(?fbP^2Mp|3H7k%LEV_NH1`65k8)zCTSHg_b4Ogf_!cddS*MXeTZlOM*z z>NVUdo9vVFDyCz<@Kn`3;WluaCZ#C5Nh+Y!Yi}cu9Ko z=3wD>pNo6ce6hE6RO#Zdkdbre0zXF0XNQ7}nkO3^GHR~kaFJ1SX9Gw^&86dU>WhKn zH&#Z^l|-1NSxo!zNX|ArQBy6?KzjWoEeWa4f5oxFV|tB6Kb^ z{;GJSSY=!Ferp9#si-&I+bw;d>xnkYdN-ITj*hcpsTmX= zTVC6Xh@f*CD{gaPT5Q{TV>&Zr@5#kk`VHT2k)?)hE|g0S*~ipJuZYq+kvUNKt?pVT zkag5N#gp%-xd%_jqn415a2++@H~T`TV98S0=q9n&bs}p;bUw=)6FZ6@$E=0M^cu)4 z!qvhh6VZ}gs8r(9xS*wp-2a!Kk4l@A{r@HP7jgF3`R@e}w!s8EkDdQc=)w}Xup4S{ z9mr<@{v194b+{Qe!t>bve+Cah2z%jWZ2ynJ``{jUJKP4>z<*%({}J2|(hu-m@DJGh zk3a-Bz<*-vKM6k#ZvkohuY*6p&VLWg!5+8;Ho|AH^FIy00ms0Dt?(4~{>R}lcoZIl z_rg2jAp9V_9$vr)@C5uZJOm$t7A%4TdtnD$5C4O2K>7a30J^6ka7O1jc6a!>-5cE+pGjUw>mUudeolRt5Ii}aAFmwsBBB) zxJ~boxx1a;iRuK3s2l%SQYy>LOtCruaYtd9vGYPYex=xO=Y^5dHT8AoS0d*6FlS|a zu|}=7U&8q1m9?PNJkb0%1>{<#=S#;sQBz~7K;n`co2==hra6j(uv0}Q#pSg*Z+n82 zuiaF9DK$E8Dt)EZdQp|C3p=MuwcMpt=&rc)3{$7wW5s}v>cJQ06SF&iI$5NCG5h$y z!I3U3a1*I>*Y?fLcX3I&hjYHUWWc8N zW*Z_Mht*S)Y5cOmXKfmd*Opi)Fqpub?z9tzv0fl`^0?)qZvQv@g;sWq@?v zcPQiaNh_2d=01#XlkyoE_XJPH$Y+1`lG)rL?fawsJ01yz|Ein)g{@n1JF4j#B3-)V zM9zQpLI+;rN$7}uO1b%(?%$e)3C}i%&axY(wKJ{;$f`w5p%(fQ?KMpQ?x4tQEy^w0 z!HX9R#>ysa%9phLZ{E-Mzu5co8Gw(&WAG^a0z3ex;CA>SxDsB%_Wu<8JgmV9*a`Ak zflaUx*2AmdEBFJx1W&_5a6hcVJjl2K`EGzefhXVr_(|x&7I+Tdz@LKj8F;V{*28o7 z2OfrN;0kya|G-%|1M*z}r{N^r19R{runqnNf5EfxD9CpM)L{p_7Ao)}euEd_bJBkR zXW)Lg3$B6<@HKo0pM{UXX*dA;;VSq;{07FaApHr4K)?og20y`BkTC|wp$*cXa0eWO z8oU}lhmYV4NFPE27U6o>3>)Fo_y$hH5x5zy2HBSK{QyHgagUO5S>rQtXxL0mMXcm@ z#IjFDXCy0e8GSb}+fXO?iU-M)_YN=GPQ>yMleyqn^n#$Vm%3{J?^T|xLtRjvu zy~||T0E;|1ukyLZZKPfqL1^EAN7^lYjijo1Rl0CgjYXQs-UhTW$p7_W!arJ`ziQ^v zrCzI5Hxnvb!9f_wU7jCK=hmEUY1}umkb!gi-k{U#?ngpjklHCy)yl|?BvGX-OIgDC zhU3Nr+I1itutjKkTGm^N3X{P$g)Bi7GiXm-xkwjpNB4za_6Tb6PyW-8s%}j)&gVLa#21 ziciuqzz6uWjWT%gK>Rb-WU2_;mL2kH0#Ul#40lF zof#79c}q1Rxj~!d9}!ETnh~^$`wGdgvShQE*F-2~SUHBtnkAJ`AD-(QvY~rez8fWJ z{It(GW{gZlZHLnEgQJ)&M{X8e5@9`Ds-vw z^Ox~!JEU;7f%nYrpFJ|0du@jl)42yXFq)Im%bE5}o5Pyom>=b6X*+UdC*NtqJZ4ug zO!tS>Md}<3n5Cf8=7!f&!END+$2yDi;A1P^{w;)bz%O-resgSc{BZop=v;iSvSLbe zQ(m@&B(BbyQO9)|yo-Uo^5&YlB)6#szcrO|V%dkubDbg%E>?}0u6kA9n3Ot-rwH9y zd9zP0Slnw)>w1-9OgB)1I=fVuNv{%1UQyao|FDEE=xmvis=n7sd!L@kib~GN6$mgd z%b+83CQ0y-EqdNDNb-g)3z(^8i^=xze0b-eTv{_jJAAgDkvhK@iR1M7IH!=!kyLak z2G9XU9jis|Pr4V$0cf2JhGvJc8WfEqdwsPho~Z^eu~E zn}_txD+k6zO;2L_+zK7J*8G)g*rK^BQSP8OQ3$E^L9^ERy=zEMPWt4FG?<-7injuD z6NFi9*+X;Ss>{^LMP2_v`=w literal 0 HcmV?d00001 diff --git a/lib/api/entities.rb b/lib/api/entities.rb index b62afb4bb4c..8e03c08f47b 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -342,14 +342,6 @@ module API end end - class BasicProjectWithAccess < BasicProjectDetails - expose :permissions do - expose :project_access, using: Entities::ProjectAccess do |project, options| - project.project_members.find_by(user_id: options[:user].id) - end - end - end - class ProjectWithAccess < Project expose :permissions do expose :project_access, using: Entities::ProjectAccess do |project, options| diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 844547665ef..6d2a6f3946c 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -26,7 +26,7 @@ module API @projects = filter_projects(@projects) @projects = paginate @projects if params[:simple] - present @projects, with: Entities::BasicProjectWithAccess, user: current_user + present @projects, with: Entities::BasicProjectDetails, user: current_user else present @projects, with: Entities::ProjectWithAccess, user: current_user end From 3e44aac08dc744915b932a0a7bed0d3f3ab3ab6b Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Tue, 12 Jul 2016 17:36:22 +0100 Subject: [PATCH 155/335] fixes test according to four-phase test pattern --- lib/api/.projects.rb.swn | Bin 28672 -> 28672 bytes spec/requests/api/projects_spec.rb | 1 + 2 files changed, 1 insertion(+) diff --git a/lib/api/.projects.rb.swn b/lib/api/.projects.rb.swn index 890811564d29fab383059a6165488d4f178b8832..6a9e5f146eafe1548d561955a5915b48388486e7 100644 GIT binary patch delta 32 mcmZp8z}WDBQ8dXQ%+puFT+f672m}}y@}*nDUvCtBoeuz+P6?0z delta 32 mcmZp8z}WDBQ8dXQ%+puFT+f672m}}y@}yhCpKla>oeuz+F$s$R diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 23b0a2a8885..d7c0f60048b 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -84,6 +84,7 @@ describe API::API, api: true do context 'GET /projects?simple=true' do it 'should return a simplified version of all the projects' do expected_keys = ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace", "permissions"] + get api('/projects?simple=true', user) expect(response).to have_http_status(200) expect(json_response).to be_an Array From c39356998b1850f3dc26fe0b987cb419c1d1afb4 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Fri, 8 Jul 2016 00:42:16 +0300 Subject: [PATCH 156/335] Optimistic locking for Issue and Merge Requests --- CHANGELOG | 1 + app/controllers/projects/issues_controller.rb | 6 ++++- .../projects/merge_requests_controller.rb | 5 +++- app/models/concerns/issuable.rb | 6 +++++ app/views/shared/issuable/_form.html.haml | 9 +++++++ .../20160707104333_add_lock_to_issuables.rb | 17 +++++++++++++ db/schema.rb | 24 ++++++++++--------- features/project/merge_requests.feature | 2 +- spec/features/issues_spec.rb | 11 +++++++++ spec/features/merge_requests/edit_mr_spec.rb | 11 +++++++++ 10 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 db/migrate/20160707104333_add_lock_to_issuables.rb diff --git a/CHANGELOG b/CHANGELOG index a1d44d02bc5..4dd96f0287a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -81,6 +81,7 @@ v 8.10.0 (unreleased) - Remove duplicate `description` field in `MergeRequest` entities (Ben Boeckel) - Style of import project buttons were fixed in the new project page. !5183 (rdemirbay) - Fix GitHub client requests when rate limit is disabled + - Optimistic locking for Issues and Merge Requests (Title and description overriding prevention) v 8.9.6 (unreleased) - Fix importing of events under notes for GitLab projects diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index b6e80762e3c..f7ada5cfee4 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -119,6 +119,10 @@ class Projects::IssuesController < Projects::ApplicationController render json: @issue.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } }) end end + + rescue ActiveRecord::StaleObjectError + @conflict = true + render :edit end def referenced_merge_requests @@ -216,7 +220,7 @@ class Projects::IssuesController < Projects::ApplicationController def issue_params params.require(:issue).permit( :title, :assignee_id, :position, :description, :confidential, - :milestone_id, :due_date, :state_event, :task_num, label_ids: [] + :milestone_id, :due_date, :state_event, :task_num, :lock_version, label_ids: [] ) end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index df659bb8c3b..2deb7959700 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -196,6 +196,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController else render "edit" end + rescue ActiveRecord::StaleObjectError + @conflict = true + render :edit end def remove_wip @@ -424,7 +427,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController :title, :assignee_id, :source_project_id, :source_branch, :target_project_id, :target_branch, :milestone_id, :state_event, :description, :task_num, :force_remove_source_branch, - label_ids: [] + :lock_version, label_ids: [] ) end diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index acb6f5a2998..fb49bd7dd64 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -87,6 +87,12 @@ module Issuable User.find(assignee_id_was).update_cache_counts if assignee_id_was assignee.update_cache_counts if assignee end + + # We want to use optimistic lock for cases when only title or description are involved + # http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html + def locking_enabled? + title_changed? || description_changed? + end end module ClassMethods diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index c30bdb0ae91..98bbb12eaec 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -1,5 +1,12 @@ = form_errors(issuable) +- if @conflict + .alert.alert-danger + Someone edited the #{issuable.class.model_name.human.downcase} the same time you did. + Please check out + = link_to "the #{issuable.class.model_name.human.downcase}", polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), target: "_blank" + and make sure your changes will not unintentionally remove theirs + .form-group = f.label :title, class: 'control-label' .col-sm-10 @@ -149,3 +156,5 @@ = link_to 'Delete', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), data: { confirm: "#{issuable.class.name.titleize} will be removed! Are you sure?" }, method: :delete, class: 'btn btn-danger btn-grouped' = link_to 'Cancel', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), class: 'btn btn-grouped btn-cancel' + += f.hidden_field :lock_version diff --git a/db/migrate/20160707104333_add_lock_to_issuables.rb b/db/migrate/20160707104333_add_lock_to_issuables.rb new file mode 100644 index 00000000000..cb516672800 --- /dev/null +++ b/db/migrate/20160707104333_add_lock_to_issuables.rb @@ -0,0 +1,17 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddLockToIssuables < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + disable_ddl_transaction! + + def up + add_column_with_default :issues, :lock_version, :integer, default: 0 + add_column_with_default :merge_requests, :lock_version, :integer, default: 0 + end + + def down + remove_column :issues, :lock_version + remove_column :merge_requests, :lock_version + end +end diff --git a/db/schema.rb b/db/schema.rb index a5eea3a697c..9d31947d80f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160705163108) do +ActiveRecord::Schema.define(version: 20160707104333) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -70,11 +70,11 @@ ActiveRecord::Schema.define(version: 20160705163108) do t.string "recaptcha_site_key" t.string "recaptcha_private_key" t.integer "metrics_port", default: 8089 - t.boolean "akismet_enabled", default: false - t.string "akismet_api_key" t.integer "metrics_sample_interval", default: 15 t.boolean "sentry_enabled", default: false t.string "sentry_dsn" + t.boolean "akismet_enabled", default: false + t.string "akismet_api_key" t.boolean "email_author_in_body", default: false t.integer "default_group_visibility" t.boolean "repository_checks_enabled", default: false @@ -84,10 +84,10 @@ ActiveRecord::Schema.define(version: 20160705163108) do t.string "health_check_access_token" t.boolean "send_user_confirmation_email", default: false t.integer "container_registry_token_expire_delay", default: 5 - t.boolean "user_default_external", default: false, null: false t.text "after_sign_up_text" t.string "repository_storage", default: "default" t.string "enabled_git_access_protocol" + t.boolean "user_default_external", default: false, null: false end create_table "audit_events", force: :cascade do |t| @@ -165,8 +165,8 @@ ActiveRecord::Schema.define(version: 20160705163108) do t.text "artifacts_metadata" t.integer "erased_by_id" t.datetime "erased_at" - t.string "environment" t.datetime "artifacts_expire_at" + t.string "environment" t.integer "artifacts_size" end @@ -481,10 +481,11 @@ ActiveRecord::Schema.define(version: 20160705163108) do t.string "state" t.integer "iid" t.integer "updated_by_id" + t.integer "moved_to_id" t.boolean "confidential", default: false t.datetime "deleted_at" t.date "due_date" - t.integer "moved_to_id" + t.integer "lock_version", default: 0, null: false end add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree @@ -624,6 +625,7 @@ ActiveRecord::Schema.define(version: 20160705163108) do t.integer "merge_user_id" t.string "merge_commit_sha" t.datetime "deleted_at" + t.integer "lock_version", default: 0, null: false end add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree @@ -773,10 +775,10 @@ ActiveRecord::Schema.define(version: 20160705163108) do t.integer "user_id", null: false t.string "token", null: false t.string "name", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false t.boolean "revoked", default: false t.datetime "expires_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "personal_access_tokens", ["token"], name: "index_personal_access_tokens_on_token", unique: true, using: :btree @@ -896,9 +898,9 @@ ActiveRecord::Schema.define(version: 20160705163108) do t.string "type" t.string "title" t.integer "project_id" - t.datetime "created_at" - t.datetime "updated_at" - t.boolean "active", default: false, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "active", null: false t.text "properties" t.boolean "template", default: false t.boolean "push_events", default: true diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 21768c15c17..8176ec5ab45 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -89,7 +89,7 @@ Feature: Project Merge Requests Then The list should be sorted by "Oldest updated" @javascript - Scenario: Visiting Merge Requests from a differente Project after sorting + Scenario: Visiting Merge Requests from a different Project after sorting Given I visit project "Shop" merge requests page And I sort the list by "Oldest updated" And I visit dashboard merge requests page diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index d51c9abea19..cfe6349a1a1 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -121,6 +121,17 @@ describe 'Issues', feature: true do expect(page).to have_content date.to_s(:medium) end end + + it 'warns about version conflict' do + issue.update(title: "New title") + + fill_in 'issue_title', with: 'bug 345' + fill_in 'issue_description', with: 'bug description' + + click_button 'Save changes' + + expect(page).to have_content 'Someone edited the issue the same time you did' + end end end diff --git a/spec/features/merge_requests/edit_mr_spec.rb b/spec/features/merge_requests/edit_mr_spec.rb index 9e007ab7635..8ad884492d1 100644 --- a/spec/features/merge_requests/edit_mr_spec.rb +++ b/spec/features/merge_requests/edit_mr_spec.rb @@ -17,5 +17,16 @@ feature 'Edit Merge Request', feature: true do it 'form should have class js-quick-submit' do expect(page).to have_selector('.js-quick-submit') end + + it 'warns about version conflict' do + merge_request.update(title: "New title") + + fill_in 'merge_request_title', with: 'bug 345' + fill_in 'merge_request_description', with: 'bug description' + + click_button 'Save changes' + + expect(page).to have_content 'Someone edited the merge request the same time you did' + end end end From 244134f9c33dea0003dc2403dceace4b94a87d2e Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Mon, 11 Jul 2016 08:10:04 +0200 Subject: [PATCH 157/335] Cache todos pending/done dashboard query counts --- CHANGELOG | 1 + app/controllers/dashboard/todos_controller.rb | 13 +++- app/controllers/projects/todos_controller.rb | 2 +- app/finders/todos_finder.rb | 2 +- app/helpers/todos_helper.rb | 4 +- .../projects/todo_controller_spec.rb | 78 ++++++++++++------- 6 files changed, 62 insertions(+), 38 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ee3ee4c37d6..3758baa0a0a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -49,6 +49,7 @@ v 8.10.0 (unreleased) - Collapse large diffs by default (!4990) - Check for conflicts with existing Project's wiki path when creating a new project. - Show last push widget in upstream after push to fork + - Cache todos pending/done dashboard query counts. - Don't instantiate a git tree on Projects show default view - Bump Rinku to 2.0.0 - Remove unused front-end variable -> default_issues_tracker diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb index 3a2db3e6eeb..19a76a5b5d8 100644 --- a/app/controllers/dashboard/todos_controller.rb +++ b/app/controllers/dashboard/todos_controller.rb @@ -1,6 +1,4 @@ class Dashboard::TodosController < Dashboard::ApplicationController - include TodosHelper - before_action :find_todos, only: [:index, :destroy_all] def index @@ -13,7 +11,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController respond_to do |format| format.html { redirect_to dashboard_todos_path, notice: 'Todo was successfully marked as done.' } format.js { head :ok } - format.json { render json: { count: todos_pending_count, done_count: todos_done_count } } + format.json { render json: todos_counts } end end @@ -23,7 +21,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController respond_to do |format| format.html { redirect_to dashboard_todos_path, notice: 'All todos were marked as done.' } format.js { head :ok } - format.json { render json: { count: todos_pending_count, done_count: todos_done_count } } + format.json { render json: todos_counts } end end @@ -36,4 +34,11 @@ class Dashboard::TodosController < Dashboard::ApplicationController def find_todos @todos ||= TodosFinder.new(current_user, params).execute end + + def todos_counts + { + count: TodosFinder.new(current_user, state: :pending).execute.count, + done_count: TodosFinder.new(current_user, state: :done).execute.count + } + end end diff --git a/app/controllers/projects/todos_controller.rb b/app/controllers/projects/todos_controller.rb index 23868d986e9..5685d0f4e7c 100644 --- a/app/controllers/projects/todos_controller.rb +++ b/app/controllers/projects/todos_controller.rb @@ -5,7 +5,7 @@ class Projects::TodosController < Projects::ApplicationController todo = TodoService.new.mark_todo(issuable, current_user) render json: { - count: current_user.todos_pending_count, + count: TodosFinder.new(current_user, state: :pending).execute.count, delete_path: dashboard_todo_path(todo) } end diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb index 7806d9e4cc5..1a8f490355b 100644 --- a/app/finders/todos_finder.rb +++ b/app/finders/todos_finder.rb @@ -8,7 +8,7 @@ # action_id: integer # author_id: integer # project_id; integer -# state: 'pending' or 'done' +# state: 'pending' (default) or 'done' # type: 'Issue' or 'MergeRequest' # diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index a832a6c8df7..0925760e69c 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -1,10 +1,10 @@ module TodosHelper def todos_pending_count - TodosFinder.new(current_user, state: :pending).execute.count + @todos_pending_count ||= TodosFinder.new(current_user, state: :pending).execute.count end def todos_done_count - TodosFinder.new(current_user, state: :done).execute.count + @todos_done_count ||= TodosFinder.new(current_user, state: :done).execute.count end def todo_action_name(todo) diff --git a/spec/controllers/projects/todo_controller_spec.rb b/spec/controllers/projects/todo_controller_spec.rb index 5a8bba28594..936320a3709 100644 --- a/spec/controllers/projects/todo_controller_spec.rb +++ b/spec/controllers/projects/todo_controller_spec.rb @@ -1,6 +1,8 @@ require('spec_helper') describe Projects::TodosController do + include ApiHelpers + let(:user) { create(:user) } let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } @@ -8,43 +10,51 @@ describe Projects::TodosController do context 'Issues' do describe 'POST create' do + def go + post :create, + namespace_id: project.namespace.path, + project_id: project.path, + issuable_id: issue.id, + issuable_type: 'issue', + format: 'html' + end + context 'when authorized' do before do sign_in(user) project.team << [user, :developer] end - it 'should create todo for issue' do + it 'creates todo for issue' do expect do - post(:create, namespace_id: project.namespace.path, - project_id: project.path, - issuable_id: issue.id, - issuable_type: 'issue') + go end.to change { user.todos.count }.by(1) expect(response).to have_http_status(200) end + + it 'returns todo path and pending count' do + go + + expect(response).to have_http_status(200) + expect(json_response['count']).to eq 1 + expect(json_response['delete_path']).to match(/\/dashboard\/todos\/\d{1}/) + end end context 'when not authorized' do - it 'should not create todo for issue that user has no access to' do + it 'does not create todo for issue that user has no access to' do sign_in(user) expect do - post(:create, namespace_id: project.namespace.path, - project_id: project.path, - issuable_id: issue.id, - issuable_type: 'issue') + go end.to change { user.todos.count }.by(0) expect(response).to have_http_status(404) end - it 'should not create todo for issue when user not logged in' do + it 'does not create todo for issue when user not logged in' do expect do - post(:create, namespace_id: project.namespace.path, - project_id: project.path, - issuable_id: issue.id, - issuable_type: 'issue') + go end.to change { user.todos.count }.by(0) expect(response).to have_http_status(302) @@ -55,43 +65,51 @@ describe Projects::TodosController do context 'Merge Requests' do describe 'POST create' do + def go + post :create, + namespace_id: project.namespace.path, + project_id: project.path, + issuable_id: merge_request.id, + issuable_type: 'merge_request', + format: 'html' + end + context 'when authorized' do before do sign_in(user) project.team << [user, :developer] end - it 'should create todo for merge request' do + it 'creates todo for merge request' do expect do - post(:create, namespace_id: project.namespace.path, - project_id: project.path, - issuable_id: merge_request.id, - issuable_type: 'merge_request') + go end.to change { user.todos.count }.by(1) expect(response).to have_http_status(200) end + + it 'returns todo path and pending count' do + go + + expect(response).to have_http_status(200) + expect(json_response['count']).to eq 1 + expect(json_response['delete_path']).to match(/\/dashboard\/todos\/\d{1}/) + end end context 'when not authorized' do - it 'should not create todo for merge request user has no access to' do + it 'does not create todo for merge request user has no access to' do sign_in(user) expect do - post(:create, namespace_id: project.namespace.path, - project_id: project.path, - issuable_id: merge_request.id, - issuable_type: 'merge_request') + go end.to change { user.todos.count }.by(0) expect(response).to have_http_status(404) end - it 'should not create todo for merge request user has no access to' do + it 'does not create todo for merge request user has no access to' do expect do - post(:create, namespace_id: project.namespace.path, - project_id: project.path, - issuable_id: merge_request.id, - issuable_type: 'merge_request') + go end.to change { user.todos.count }.by(0) expect(response).to have_http_status(302) From 770d2831f8c69c8f485092fadc37a017acda8fcc Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Tue, 12 Jul 2016 18:45:16 +0100 Subject: [PATCH 158/335] fixes test for simplified version of project --- app/controllers/concerns/filter_branches.rb | 8 ++++++++ spec/requests/api/projects_spec.rb | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 app/controllers/concerns/filter_branches.rb diff --git a/app/controllers/concerns/filter_branches.rb b/app/controllers/concerns/filter_branches.rb new file mode 100644 index 00000000000..5376a514e19 --- /dev/null +++ b/app/controllers/concerns/filter_branches.rb @@ -0,0 +1,8 @@ +module FilterBranches + extend ActiveSupport::Concern + + def filter_branches(branches) + if params[:search].present? && @sort + branches = @repository.find_similar_branches(params[:search], @sort) + end +end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index d7c0f60048b..4ddab08ef14 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -83,7 +83,7 @@ describe API::API, api: true do context 'GET /projects?simple=true' do it 'should return a simplified version of all the projects' do - expected_keys = ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace", "permissions"] + expected_keys = ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace"] get api('/projects?simple=true', user) expect(response).to have_http_status(200) From 47b5b441395921e9f8e9982bb3f560e5db5a67bc Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 12 Jul 2016 17:22:10 +0200 Subject: [PATCH 159/335] Defend against 'Host' header injection Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/17877 . This change adds 'defense in depth' against 'Host' HTTP header injection. It affects normal users in the following way. Suppose your GitLab server has IP address 1.2.3.4 and hostname gitlab.example.com. Currently, if you enter 1.2.3.4 in your browser, you get redirected to 1.2.3.4/users/sign_in. After this change, you get redirected from 1.2.3.4 to gitlab.example.com/users/sign_in. This is because the address you typed in the address bar of your browser ('1.2.3.4'), which gets stored in the 'Host' header, is now being overwritten to 'gitlab.example.com' in NGINX. In this change we also make NGINX clear the 'X-Forwarded-Host' header because Ruby on Rails also uses that header the same wayas the 'Host' header. We think that for most GitLab servers this is the right behavior, and if not then administrators can change this behavior themselves at the NGINX level. --- CHANGELOG | 1 + lib/support/nginx/gitlab | 7 ++++++- lib/support/nginx/gitlab-ssl | 7 ++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ee3ee4c37d6..852a123f0cd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -78,6 +78,7 @@ v 8.10.0 (unreleased) - Add reminder to not paste private SSH keys !4399 (Ingo Blechschmidt) - Remove duplicate `description` field in `MergeRequest` entities (Ben Boeckel) - Style of import project buttons were fixed in the new project page. !5183 (rdemirbay) + - Overwrite Host and X-Forwarded-Host headers in NGINX !5213 v 8.9.6 (unreleased) - Fix importing of events under notes for GitLab projects diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab index d521de28e8a..4a4892a2e07 100644 --- a/lib/support/nginx/gitlab +++ b/lib/support/nginx/gitlab @@ -49,7 +49,12 @@ server { proxy_http_version 1.1; - proxy_set_header Host $http_host; + ## By overwriting Host and clearing X-Forwarded-Host we ensure that + ## internal HTTP redirects generated by GitLab always send users to + ## YOUR_SERVER_FQDN. + proxy_set_header Host YOUR_SERVER_FQDN; + proxy_set_header X-Forwarded-Host ""; + proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl index bf014b56cf6..0b93d7f292f 100644 --- a/lib/support/nginx/gitlab-ssl +++ b/lib/support/nginx/gitlab-ssl @@ -93,7 +93,12 @@ server { proxy_http_version 1.1; - proxy_set_header Host $http_host; + ## By overwriting Host and clearing X-Forwarded-Host we ensure that + ## internal HTTP redirects generated by GitLab always send users to + ## YOUR_SERVER_FQDN. + proxy_set_header Host YOUR_SERVER_FQDN; + proxy_set_header X-Forwarded-Host ""; + proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Ssl on; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; From d957d5f1aa45d3a8474678e5439ccdc09a545482 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Mon, 11 Jul 2016 11:02:11 +0100 Subject: [PATCH 160/335] Add approval required todos --- app/finders/todos_finder.rb | 2 +- app/helpers/todos_helper.rb | 1 + app/models/todo.rb | 12 +++++++----- doc/api/todos.md | 2 +- spec/factories/todos.rb | 4 ++++ 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb index 7806d9e4cc5..681b403b817 100644 --- a/app/finders/todos_finder.rb +++ b/app/finders/todos_finder.rb @@ -37,7 +37,7 @@ class TodosFinder private def action_id? - action_id.present? && [Todo::ASSIGNED, Todo::MENTIONED, Todo::BUILD_FAILED, Todo::MARKED].include?(action_id.to_i) + action_id.present? && Todo::ACTION_NAMES.has_key?(action_id.to_i) end def action_id diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index a832a6c8df7..e43c209f90c 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -13,6 +13,7 @@ module TodosHelper when Todo::MENTIONED then 'mentioned you on' when Todo::BUILD_FAILED then 'The build failed for your' when Todo::MARKED then 'added a todo for' + when Todo::APPROVAL_REQUIRED then 'set you as an approver for' end end diff --git a/app/models/todo.rb b/app/models/todo.rb index ac3fdbc7f3b..8d7a5965aa1 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -1,14 +1,16 @@ class Todo < ActiveRecord::Base - ASSIGNED = 1 - MENTIONED = 2 - BUILD_FAILED = 3 - MARKED = 4 + ASSIGNED = 1 + MENTIONED = 2 + BUILD_FAILED = 3 + MARKED = 4 + APPROVAL_REQUIRED = 5 # This is an EE-only feature ACTION_NAMES = { ASSIGNED => :assigned, MENTIONED => :mentioned, BUILD_FAILED => :build_failed, - MARKED => :marked + MARKED => :marked, + APPROVAL_REQUIRED => :approval_required } belongs_to :author, class_name: "User" diff --git a/doc/api/todos.md b/doc/api/todos.md index 29e73664410..23f6e35f2a4 100644 --- a/doc/api/todos.md +++ b/doc/api/todos.md @@ -15,7 +15,7 @@ Parameters: | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `action` | string | no | The action to be filtered. Can be `assigned`, `mentioned`, `build_failed`, or `marked`. | +| `action` | string | no | The action to be filtered. Can be `assigned`, `mentioned`, `build_failed`, `marked`, or `approval_required`. | | `author_id` | integer | no | The ID of an author | | `project_id` | integer | no | The ID of a project | | `state` | string | no | The state of the todo. Can be either `pending` or `done` | diff --git a/spec/factories/todos.rb b/spec/factories/todos.rb index 7fc20cd5555..866e663f026 100644 --- a/spec/factories/todos.rb +++ b/spec/factories/todos.rb @@ -23,6 +23,10 @@ FactoryGirl.define do action { Todo::BUILD_FAILED } end + trait :approval_required do + action { Todo::APPROVAL_REQUIRED } + end + trait :done do state :done end From 144d22f7f87c270cb5192366c6e76dfad2a2c389 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Tue, 12 Jul 2016 18:57:08 +0100 Subject: [PATCH 161/335] Delete award emoji when deleting a user --- CHANGELOG | 3 ++- app/models/user.rb | 2 +- ...171823_remove_award_emojis_with_no_user.rb | 21 +++++++++++++++++++ db/schema.rb | 2 +- 4 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20160712171823_remove_award_emojis_with_no_user.rb diff --git a/CHANGELOG b/CHANGELOG index a50edf1a797..1a4d792ef84 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ v 8.10.0 (unreleased) - Refactor repository paths handling to allow multiple git mount points - Optimize system note visibility checking by memoizing the visible reference count !5070 - Add Application Setting to configure default Repository Path for new projects + - Delete award emoji when deleting a user - Remove pinTo from Flash and make inline flash messages look nicer !4854 (winniehell) - Wrap code blocks on Activies and Todos page. !4783 (winniehell) - Align flash messages with left side of page content !4959 (winniehell) @@ -73,7 +74,7 @@ v 8.10.0 (unreleased) - Allow '?', or '&' for label names - Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests - Add date when user joined the team on the member page - - Fix 404 redirect after validation fails importing a GitLab project + - Fix 404 redirect after validation fails importing a GitLab project - Fix 404 redirect after validation fails importing a GitLab project - Added setting to set new users by default as external !4545 (Dravere) - Add min value for project limit field on user's form !3622 (jastkand) diff --git a/app/models/user.rb b/app/models/user.rb index 79c670cb35a..7a72c202150 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -87,7 +87,7 @@ class User < ActiveRecord::Base has_many :builds, dependent: :nullify, class_name: 'Ci::Build' has_many :todos, dependent: :destroy has_many :notification_settings, dependent: :destroy - has_many :award_emoji, as: :awardable, dependent: :destroy + has_many :award_emoji, dependent: :destroy # # Validations diff --git a/db/migrate/20160712171823_remove_award_emojis_with_no_user.rb b/db/migrate/20160712171823_remove_award_emojis_with_no_user.rb new file mode 100644 index 00000000000..668c22bb51c --- /dev/null +++ b/db/migrate/20160712171823_remove_award_emojis_with_no_user.rb @@ -0,0 +1,21 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class RemoveAwardEmojisWithNoUser < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # When using the methods "add_concurrent_index" or "add_column_with_default" + # you must disable the use of transactions as these methods can not run in an + # existing transaction. When using "add_concurrent_index" make sure that this + # method is the _only_ method called in the migration, any other changes + # should go in a separate migration. This ensures that upon failure _only_ the + # index creation fails and can be retried or reverted easily. + # + # To disable transactions uncomment the following line and remove these + # comments: + # disable_ddl_transaction! + + def up + AwardEmoji.joins('LEFT JOIN users ON users.id = user_id').where('users.id IS NULL').destroy_all + end +end diff --git a/db/schema.rb b/db/schema.rb index 9d31947d80f..f24e47b85b2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160707104333) do +ActiveRecord::Schema.define(version: 20160712171823) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" From 9fa8cf6759c798eee8aeec9016a0abbea87ed275 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Tue, 12 Jul 2016 19:19:48 +0100 Subject: [PATCH 162/335] removes redundant filter_branches file --- app/controllers/concerns/filter_branches.rb | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 app/controllers/concerns/filter_branches.rb diff --git a/app/controllers/concerns/filter_branches.rb b/app/controllers/concerns/filter_branches.rb deleted file mode 100644 index 5376a514e19..00000000000 --- a/app/controllers/concerns/filter_branches.rb +++ /dev/null @@ -1,8 +0,0 @@ -module FilterBranches - extend ActiveSupport::Concern - - def filter_branches(branches) - if params[:search].present? && @sort - branches = @repository.find_similar_branches(params[:search], @sort) - end -end From 47199c35a5555483309cdbde39c3da51e5a75d69 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Thu, 7 Jul 2016 08:44:00 -0500 Subject: [PATCH 163/335] Add clock and calendar icons for duration and finished at; add finished at section in pipelines --- app/views/projects/ci/builds/_build.html.haml | 2 ++ app/views/projects/ci/pipelines/_pipeline.html.haml | 5 +++++ .../generic_commit_statuses/_generic_commit_status.html.haml | 2 ++ 3 files changed, 9 insertions(+) diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml index 5bd6e3f0ebc..00004163047 100644 --- a/app/views/projects/ci/builds/_build.html.haml +++ b/app/views/projects/ci/builds/_build.html.haml @@ -57,10 +57,12 @@ %td.duration - if build.duration + = icon("clock-o") #{duration_in_words(build.finished_at, build.started_at)} %td.timestamp - if build.finished_at + = icon("calendar") %span #{time_ago_with_tooltip(build.finished_at)} - if defined?(coverage) && coverage diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index af8dd5cd02c..f2c19797206 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -45,7 +45,12 @@ %td - if pipeline.started_at && pipeline.finished_at %p.duration + = icon("clock-o") = duration_in_numbers(pipeline.finished_at, pipeline.started_at) + - if pipeline.finished_at + %p.duration + = icon("calendar") + #{time_ago_with_tooltip(pipeline.finished_at)} %td .controls.hidden-xs.pull-right diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml index 5bc5c71283e..542827b2f15 100644 --- a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml +++ b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml @@ -50,10 +50,12 @@ %td.duration - if generic_commit_status.duration + = icon("clock-o") #{duration_in_words(generic_commit_status.finished_at, generic_commit_status.started_at)} %td.timestamp - if generic_commit_status.finished_at + = icon("calendar") %span #{time_ago_with_tooltip(generic_commit_status.finished_at)} - if defined?(coverage) && coverage From 446eecb85275352dcd4c3e2c6054461da2a51ca7 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Thu, 7 Jul 2016 13:40:40 -0500 Subject: [PATCH 164/335] Move pipeline ID to commit column; add status; branch style updates --- app/assets/stylesheets/pages/builds.scss | 32 ++++++++++++++++++- .../projects/ci/pipelines/_pipeline.html.haml | 9 +++--- app/views/projects/pipelines/index.html.haml | 4 +-- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index e8f1935d239..76024933650 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -83,7 +83,37 @@ } } -table.builds { + +.table.builds { + + tr { + th { + padding: 18px 10px; + border: none; + } + } + + tbody { + border-top-width: 1px; + } + + .branch-commit { + + .branch-name { + max-width: 180px; + overflow: hidden; + display: inline-block; + white-space: nowrap; + vertical-align: top; + text-overflow: ellipsis; + margin-left: 10px; + } + + .commit-id { + color: $gl-link-color; + } + } + .build-link { a { color: $gl-dark-link-color; diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index f2c19797206..daeaf7f99eb 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -1,14 +1,15 @@ - status = pipeline.status %tr.commit %td.commit-link - = link_to namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: "ci-status ci-#{status}" do - = ci_icon_for_status(status) - %strong ##{pipeline.id} + = link_to namespace_project_pipeline_path(@project.namespace, @project, pipeline.id) do + = ci_status_with_icon(status) + %td %div.branch-commit + %span ##{pipeline.id} - if pipeline.ref - = link_to pipeline.ref, namespace_project_commits_path(@project.namespace, @project, pipeline.ref), class: "monospace" + = link_to pipeline.ref, namespace_project_commits_path(@project.namespace, @project, pipeline.ref), class: "monospace branch-name" · = link_to pipeline.short_sha, namespace_project_commit_path(@project.namespace, @project, pipeline.sha), class: "commit-id monospace"   diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml index 7c225e2b282..e1c82a8179d 100644 --- a/app/views/projects/pipelines/index.html.haml +++ b/app/views/projects/pipelines/index.html.haml @@ -45,13 +45,13 @@ .table-holder %table.table.builds %tbody - %th ID + %th Status %th Commit - stages.each do |stage| %th.stage %span.has-tooltip{ title: "#{stage.titleize}" } = stage.titleize - %th Duration + %%th %th = render @pipelines, commit_sha: true, stage: true, allow_retry: true, stages: stages From 1f67cc4a559e72bedf06f169343c504fcfdd3d49 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Fri, 8 Jul 2016 10:01:56 -0500 Subject: [PATCH 165/335] Set width on stage columns; min width on table with scroll on mobile; add avatar to commit column --- app/assets/stylesheets/framework/avatar.scss | 1 + .../stylesheets/framework/variables.scss | 1 + app/assets/stylesheets/pages/builds.scss | 38 -------- app/assets/stylesheets/pages/pipelines.scss | 87 ++++++++++++++++++- .../projects/ci/pipelines/_pipeline.html.haml | 10 +-- app/views/projects/pipelines/index.html.haml | 2 +- 6 files changed, 93 insertions(+), 46 deletions(-) diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss index bb8d71fbae8..8b6ddf8ba18 100644 --- a/app/assets/stylesheets/framework/avatar.scss +++ b/app/assets/stylesheets/framework/avatar.scss @@ -20,6 +20,7 @@ } &.s16 { width: 16px; height: 16px; margin-right: 6px; } + &.s20 { width: 20px; height: 20px; margin-right: 7px; } &.s24 { width: 24px; height: 24px; margin-right: 8px; } &.s26 { width: 26px; height: 26px; margin-right: 8px; } &.s32 { width: 32px; height: 32px; margin-right: 10px; } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 4337fab5d87..09d3caa0e6a 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -17,6 +17,7 @@ $focus-border-color: #3aabf0; $table-border-color: #f0f0f0; $background-color: #fafafa; $dark-background-color: #f7f7f7; +$table-text-gray: #8f8f8f; /* * Text diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index 76024933650..99a2cd306cf 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -83,44 +83,6 @@ } } - -.table.builds { - - tr { - th { - padding: 18px 10px; - border: none; - } - } - - tbody { - border-top-width: 1px; - } - - .branch-commit { - - .branch-name { - max-width: 180px; - overflow: hidden; - display: inline-block; - white-space: nowrap; - vertical-align: top; - text-overflow: ellipsis; - margin-left: 10px; - } - - .commit-id { - color: $gl-link-color; - } - } - - .build-link { - a { - color: $gl-dark-link-color; - } - } -} - .build-trace { background: $ci-output-bg; color: $ci-text-color; diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 6128868b670..fb5840a4f67 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -1,12 +1,13 @@ .pipelines { .stage { - max-width: 100px; + max-width: 70px; + width: 70px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } - .duration, .finished_at { + .duration, .finished-at { margin: 4px 0; } @@ -22,3 +23,85 @@ margin: 4px; } } + +.content-list.pipelines { + width: 100%; + overflow: auto; +} + +.table.builds { + min-width: 1100px; + + tr { + th { + padding: 18px 10px; + border: none; + } + } + + tbody { + border-top-width: 1px; + } + + .branch-commit { + + .branch-name { + margin-left: 8px; + font-weight: bold; + max-width: 180px; + overflow: hidden; + display: inline-block; + white-space: nowrap; + vertical-align: top; + text-overflow: ellipsis; + } + + .fa { + margin: 0 6px; + } + + .commit-id { + color: $gl-link-color; + margin-right: 8px; + } + + .commit-title { + margin-top: 4px; + max-width: 320px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + .avatar { + margin-left: 0; + } + } + + .duration, + .finished-at { + color: $table-text-gray; + + .fa { + margin-right: 5px; + } + } + + .pipeline-actions { + + .btn { + color: $table-text-gray; + } + + .btn-remove { + color: $white-light; + } + } + + .build-link { + + a { + color: $gl-dark-link-color; + } + } +} diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index daeaf7f99eb..b8712b5dc45 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -10,9 +10,8 @@ %span ##{pipeline.id} - if pipeline.ref = link_to pipeline.ref, namespace_project_commits_path(@project.namespace, @project, pipeline.ref), class: "monospace branch-name" - · + = icon("code-fork") = link_to pipeline.short_sha, namespace_project_commit_path(@project.namespace, @project, pipeline.sha), class: "commit-id monospace" -   - if pipeline.tag? %span.label.label-primary tag - elsif pipeline.latest? @@ -26,6 +25,7 @@ %p.commit-title - if commit = pipeline.commit + = commit_author_avatar(commit, size: 20) = link_to_gfm truncate(commit.title, length: 60), namespace_project_commit_path(@project.namespace, @project, commit.id), class: "commit-row-message" - else Cant find HEAD commit for this branch @@ -46,14 +46,14 @@ %td - if pipeline.started_at && pipeline.finished_at %p.duration - = icon("clock-o") + = icon("clock-o") = duration_in_numbers(pipeline.finished_at, pipeline.started_at) - if pipeline.finished_at - %p.duration + %p.finished-at = icon("calendar") #{time_ago_with_tooltip(pipeline.finished_at)} - %td + %td.pipeline-actions .controls.hidden-xs.pull-right - artifacts = pipeline.builds.latest.select { |b| b.artifacts? } - if artifacts.present? diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml index e1c82a8179d..4672ff165d3 100644 --- a/app/views/projects/pipelines/index.html.haml +++ b/app/views/projects/pipelines/index.html.haml @@ -51,7 +51,7 @@ %th.stage %span.has-tooltip{ title: "#{stage.titleize}" } = stage.titleize - %%th + %th %th = render @pipelines, commit_sha: true, stage: true, allow_retry: true, stages: stages From 191687a10ce275f98e287876ddf7e69969790e71 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Fri, 8 Jul 2016 14:09:30 -0500 Subject: [PATCH 166/335] Add empty deploy dropdown button --- app/assets/stylesheets/pages/pipelines.scss | 27 ++++++++++++++++++ .../projects/ci/pipelines/_pipeline.html.haml | 28 +++++++++++++------ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index fb5840a4f67..c73755ee920 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -90,12 +90,35 @@ .pipeline-actions { .btn { + margin: 0; + } + + .dropdown-toggle, + .dropdown-menu { color: $table-text-gray; + + .fa { + color: $table-text-gray; + margin-right: 6px; + font-size: 14px; + } } .btn-remove { color: $white-light; } + + .btn-group { + &.open { + .btn-default { + background-color: $white-normal; + border-color: $border-white-normal; + + &:hover { + } + } + } + } } .build-link { @@ -104,4 +127,8 @@ color: $gl-dark-link-color; } } + + .btn-group.open .dropdown-toggle { + box-shadow: none; + } } diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index b8712b5dc45..4167db3fdcb 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -57,16 +57,26 @@ .controls.hidden-xs.pull-right - artifacts = pipeline.builds.latest.select { |b| b.artifacts? } - if artifacts.present? - .dropdown.inline.build-artifacts - %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} - = icon('download') - %b.caret - %ul.dropdown-menu.dropdown-menu-align-right - - artifacts.each do |build| + .btn-group.inline + .btn-group + %a.dropdown-toggle.btn.btn-default{type: 'button', 'data-toggle' => 'dropdown'} + = icon("play") + %b.caret + %ul.dropdown-menu.dropdown-menu-align-right %li - = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, build), rel: 'nofollow' do - = icon("download") - %span Download '#{build.name}' artifacts + = link_to '#' do + = icon("play") + %span Deploy to production + .btn-group + %a.dropdown-toggle.btn.btn-default.build-artifacts{type: 'button', 'data-toggle' => 'dropdown'} + = icon("download") + %b.caret + %ul.dropdown-menu.dropdown-menu-align-right + - artifacts.each do |build| + %li + = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, build), rel: 'nofollow' do + = icon("download") + %span Download '#{build.name}' artifacts - if can?(current_user, :update_pipeline, @project) - if pipeline.retryable? From a87a0ffd4429d794644c36ed84e1389ff2922895 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Fri, 8 Jul 2016 14:20:58 -0500 Subject: [PATCH 167/335] Add link to pipline ID --- app/views/projects/ci/pipelines/_pipeline.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index 4167db3fdcb..f8c03a430bd 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -7,7 +7,8 @@ %td %div.branch-commit - %span ##{pipeline.id} + = link_to namespace_project_pipeline_path(@project.namespace, @project, pipeline.id) do + %span ##{pipeline.id} - if pipeline.ref = link_to pipeline.ref, namespace_project_commits_path(@project.namespace, @project, pipeline.ref), class: "monospace branch-name" = icon("code-fork") From 16fda5f19c2c0fb63105d7cf122360a0afaa29ca Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 11 Jul 2016 08:38:27 -0500 Subject: [PATCH 168/335] Update builds page --- app/assets/stylesheets/pages/pipelines.scss | 25 +++--- app/views/projects/builds/index.html.haml | 8 +- app/views/projects/ci/builds/_build.html.haml | 84 +++++++++---------- 3 files changed, 58 insertions(+), 59 deletions(-) diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index c73755ee920..bd3dc462302 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -7,10 +7,6 @@ white-space: nowrap; } - .duration, .finished-at { - margin: 4px 0; - } - .commit-title { margin: 0; } @@ -24,9 +20,13 @@ } } -.content-list.pipelines { - width: 100%; - overflow: auto; +.content-list { + + &.pipelines, + &.builds-content-list { + width: 100%; + overflow: auto; + } } .table.builds { @@ -76,11 +76,16 @@ .avatar { margin-left: 0; } + + .label-container { + margin-top: 5px; + } } .duration, .finished-at { color: $table-text-gray; + margin: 4px 0; .fa { margin-right: 5px; @@ -91,10 +96,11 @@ .btn { margin: 0; + color: $table-text-gray; } .dropdown-toggle, - .dropdown-menu { + .dropdown-menu { color: $table-text-gray; .fa { @@ -113,9 +119,6 @@ .btn-default { background-color: $white-normal; border-color: $border-white-normal; - - &:hover { - } } } } diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml index 381b3754cd5..85c31dfd918 100644 --- a/app/views/projects/builds/index.html.haml +++ b/app/views/projects/builds/index.html.haml @@ -36,7 +36,7 @@ = link_to ci_lint_path, class: 'btn btn-default' do %span CI Lint - %ul.content-list + %ul.content-list.builds-content-list - if @builds.blank? %li .nothing-here-block No builds to show @@ -46,14 +46,10 @@ %thead %tr %th Status - %th Build ID %th Commit - %th Ref %th Stage %th Name - %th Tags - %th Duration - %th Finished at + %th - if @project.build_coverage_enabled? %th Coverage %th diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml index 00004163047..099da5d1c72 100644 --- a/app/views/projects/ci/builds/_build.html.haml +++ b/app/views/projects/ci/builds/_build.html.haml @@ -1,32 +1,45 @@ -%tr.build +%tr.build.commit %td.status - if can?(current_user, :read_build, build) = ci_status_with_icon(build.status, namespace_project_build_url(build.project.namespace, build.project, build)) - else = ci_status_with_icon(build.status) - %td.build-link - - if can?(current_user, :read_build, build) - = link_to namespace_project_build_url(build.project.namespace, build.project, build) do - %strong ##{build.id} - - else - %strong ##{build.id} - - - if build.stuck? - = icon('warning', class: 'text-warning has-tooltip', title: 'Build is stuck. Check runners.') - - if defined?(retried) && retried - = icon('warning', class: 'text-warning has-tooltip', title: 'Build was retried.') - - - if defined?(commit_sha) && commit_sha - %td - = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace" - - - if defined?(ref) && ref - %td - - if build.ref - = link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref) + %td + %div.branch-commit + - if can?(current_user, :read_build, build) + = link_to namespace_project_build_url(build.project.namespace, build.project, build) do + %span ##{build.id} - else - .light none + %span ##{build.id} + + - if build.stuck? + = icon('warning', class: 'text-warning has-tooltip', title: 'Build is stuck. Check runners.') + - if defined?(retried) && retried + = icon('warning', class: 'text-warning has-tooltip', title: 'Build was retried.') + + - if defined?(ref) && ref + - if build.ref + = link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref), class: "monospace branch-name" + - else + .light none + = icon("code-fork") + + - if defined?(commit_sha) && commit_sha + = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "commit-id monospace" + + .label-container + - if build.tags.any? + - build.tags.each do |tag| + %span.label.label-primary + = tag + - if build.try(:trigger_request) + %span.label.label-info triggered + - if build.try(:allow_failure) + %span.label.label-danger allowed to fail + - if defined?(retried) && retried + %span.label.label-warning retried + - if defined?(runner) && runner %td @@ -43,27 +56,14 @@ = build.name %td - .label-container - - if build.tags.any? - - build.tags.each do |tag| - %span.label.label-primary - = tag - - if build.try(:trigger_request) - %span.label.label-info triggered - - if build.try(:allow_failure) - %span.label.label-danger allowed to fail - - if defined?(retried) && retried - %span.label.label-warning retried - - %td.duration - if build.duration - = icon("clock-o") - #{duration_in_words(build.finished_at, build.started_at)} - - %td.timestamp + %p.duration + = icon("clock-o") + #{duration_in_words(build.finished_at, build.started_at)} - if build.finished_at - = icon("calendar") - %span #{time_ago_with_tooltip(build.finished_at)} + %p.finished-at + = icon("calendar") + %span #{time_ago_with_tooltip(build.finished_at)} - if defined?(coverage) && coverage %td.coverage @@ -81,4 +81,4 @@ = icon('remove', class: 'cred') - elsif defined?(allow_retry) && allow_retry && build.retryable? = link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do - = icon('refresh') + = icon('repeat') From 694ab941ea99ca4c4a32ceea090317851390d56f Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 11 Jul 2016 13:57:12 -0500 Subject: [PATCH 169/335] Rearrange and update admin builds --- app/views/admin/builds/_build.html.haml | 65 ++++++++++--------- app/views/admin/builds/index.html.haml | 10 +-- app/views/projects/ci/builds/_build.html.haml | 18 ++--- .../projects/ci/pipelines/_pipeline.html.haml | 2 +- 4 files changed, 47 insertions(+), 48 deletions(-) diff --git a/app/views/admin/builds/_build.html.haml b/app/views/admin/builds/_build.html.haml index 967151bc33b..ecf0205249a 100644 --- a/app/views/admin/builds/_build.html.haml +++ b/app/views/admin/builds/_build.html.haml @@ -1,31 +1,41 @@ - project = build.project -%tr.build +%tr.build.commit %td.status = ci_status_with_icon(build.status) - %td.build-link - - if can?(current_user, :read_build, build.project) - = link_to namespace_project_build_url(build.project.namespace, build.project, build) do - %strong Build ##{build.id} - - else - %strong Build ##{build.id} + %td + .branch-commit + - if can?(current_user, :read_build, build.project) + = link_to namespace_project_build_url(build.project.namespace, build.project, build) do + %span ##{build.id} + - else + %span ##{build.id} - - if build.stuck? - %i.fa.fa-warning.text-warning + - if build.stuck? + %i.fa.fa-warning.text-warning + + - if build.ref + = link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref), class: "monospace branch-name" + - else + .light none + = icon("code-fork") + + = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace commit-id" + + - if build.tags.any? + .label-container + - build.tags.each do |tag| + %span.label.label-primary + = tag + - if build.try(:trigger_request) + %span.label.label-info triggered + - if build.try(:allow_failure) + %span.label.label-danger allowed to fail %td - if project = link_to project.name_with_namespace, admin_namespace_project_path(project.namespace, project) - %td - = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace" - - %td - - if build.ref - = link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref) - - else - .light none - %td - if build.try(:runner) = runner_link(build.runner) @@ -36,22 +46,15 @@ #{build.stage} / #{build.name} %td - - if build.tags.any? - - build.tags.each do |tag| - %span.label.label-primary - = tag - - if build.try(:trigger_request) - %span.label.label-info triggered - - if build.try(:allow_failure) - %span.label.label-danger allowed to fail - - %td.duration - if build.duration - #{duration_in_words(build.finished_at, build.started_at)} + %p.duration + = icon("clock-o") + #{duration_in_words(build.finished_at, build.started_at)} - %td.timestamp - if build.finished_at - %span #{time_ago_with_tooltip(build.finished_at)} + %p.finished-at + = icon("calendar") + %span #{time_ago_with_tooltip(build.finished_at)} - if defined?(coverage) && coverage %td.coverage diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml index 1e60205f91a..9ea3cca0ecb 100644 --- a/app/views/admin/builds/index.html.haml +++ b/app/views/admin/builds/index.html.haml @@ -27,7 +27,7 @@ .row-content-block.second-block #{(@scope || 'all').capitalize} builds - %ul.content-list + %ul.content-list.builds-content-list - if @builds.blank? %li .nothing-here-block No builds to show @@ -37,15 +37,11 @@ %thead %tr %th Status - %th Build ID - %th Project %th Commit - %th Ref + %th Project %th Runner %th Name - %th Tags - %th Duration - %th Finished at + %th %th - @builds.each do |build| diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml index 099da5d1c72..2099c9f8c5d 100644 --- a/app/views/projects/ci/builds/_build.html.haml +++ b/app/views/projects/ci/builds/_build.html.haml @@ -6,7 +6,7 @@ = ci_status_with_icon(build.status) %td - %div.branch-commit + .branch-commit - if can?(current_user, :read_build, build) = link_to namespace_project_build_url(build.project.namespace, build.project, build) do %span ##{build.id} @@ -28,17 +28,17 @@ - if defined?(commit_sha) && commit_sha = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "commit-id monospace" - .label-container - - if build.tags.any? + - if build.tags.any? + .label-container - build.tags.each do |tag| %span.label.label-primary = tag - - if build.try(:trigger_request) - %span.label.label-info triggered - - if build.try(:allow_failure) - %span.label.label-danger allowed to fail - - if defined?(retried) && retried - %span.label.label-warning retried + - if build.try(:trigger_request) + %span.label.label-info triggered + - if build.try(:allow_failure) + %span.label.label-danger allowed to fail + - if defined?(retried) && retried + %span.label.label-warning retried - if defined?(runner) && runner diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index f8c03a430bd..766ea31ef70 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -6,7 +6,7 @@ %td - %div.branch-commit + .branch-commit = link_to namespace_project_pipeline_path(@project.namespace, @project, pipeline.id) do %span ##{pipeline.id} - if pipeline.ref From c57471ddb456c9640f6d77128e1fc56c7a5b35b2 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 11 Jul 2016 14:27:35 -0500 Subject: [PATCH 170/335] Add new stopwatch and commit icons; rename custom icon helper; fix commit pipeline layout --- app/assets/stylesheets/pages/pipelines.scss | 22 +++++++++++++++---- app/helpers/appearances_helper.rb | 2 +- app/views/admin/builds/_build.html.haml | 4 ++-- app/views/projects/ci/builds/_build.html.haml | 4 ++-- .../projects/ci/pipelines/_pipeline.html.haml | 4 ++-- app/views/projects/commit/_pipeline.html.haml | 4 +--- app/views/projects/issues/index.html.haml | 2 +- app/views/shared/icons/_icon_commit.svg | 3 +++ app/views/shared/icons/_icon_timer.svg | 1 + 9 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 app/views/shared/icons/_icon_commit.svg create mode 100644 app/views/shared/icons/_icon_timer.svg diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index bd3dc462302..064bb83e44c 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -1,7 +1,7 @@ .pipelines { .stage { - max-width: 70px; - width: 70px; + max-width: 80px; + width: 80px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -34,7 +34,7 @@ tr { th { - padding: 18px 10px; + padding: 16px; border: none; } } @@ -56,8 +56,11 @@ text-overflow: ellipsis; } - .fa { + svg { margin: 0 6px; + height: 14px; + width: auto; + vertical-align: middle; } .commit-id { @@ -88,6 +91,17 @@ margin: 4px 0; .fa { + font-size: 12px; + } + + svg { + height: 12px; + width: auto; + vertical-align: middle; + } + + .fa, + svg { margin-right: 5px; } } diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb index 950f323e383..e12a1052988 100644 --- a/app/helpers/appearances_helper.rb +++ b/app/helpers/appearances_helper.rb @@ -31,7 +31,7 @@ module AppearancesHelper end end - def navbar_icon(icon_name, size: 16) + def custom_icon(icon_name, size: 16) render "shared/icons/#{icon_name}.svg", size: size end end diff --git a/app/views/admin/builds/_build.html.haml b/app/views/admin/builds/_build.html.haml index ecf0205249a..c60f81f8936 100644 --- a/app/views/admin/builds/_build.html.haml +++ b/app/views/admin/builds/_build.html.haml @@ -18,7 +18,7 @@ = link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref), class: "monospace branch-name" - else .light none - = icon("code-fork") + = custom_icon("icon_commit") = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace commit-id" @@ -48,7 +48,7 @@ %td - if build.duration %p.duration - = icon("clock-o") + = custom_icon("icon_timer") #{duration_in_words(build.finished_at, build.started_at)} - if build.finished_at diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml index 2099c9f8c5d..0c29658e4d9 100644 --- a/app/views/projects/ci/builds/_build.html.haml +++ b/app/views/projects/ci/builds/_build.html.haml @@ -23,7 +23,7 @@ = link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref), class: "monospace branch-name" - else .light none - = icon("code-fork") + = custom_icon("icon_commit") - if defined?(commit_sha) && commit_sha = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "commit-id monospace" @@ -58,7 +58,7 @@ %td - if build.duration %p.duration - = icon("clock-o") + = custom_icon("icon_timer") #{duration_in_words(build.finished_at, build.started_at)} - if build.finished_at %p.finished-at diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index 766ea31ef70..4ef72ff5d2a 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -11,7 +11,7 @@ %span ##{pipeline.id} - if pipeline.ref = link_to pipeline.ref, namespace_project_commits_path(@project.namespace, @project, pipeline.ref), class: "monospace branch-name" - = icon("code-fork") + = custom_icon("icon_commit") = link_to pipeline.short_sha, namespace_project_commit_path(@project.namespace, @project, pipeline.sha), class: "commit-id monospace" - if pipeline.tag? %span.label.label-primary tag @@ -47,7 +47,7 @@ %td - if pipeline.started_at && pipeline.finished_at %p.duration - = icon("clock-o") + = custom_icon("icon_timer") = duration_in_numbers(pipeline.finished_at, pipeline.started_at) - if pipeline.finished_at %p.finished-at diff --git a/app/views/projects/commit/_pipeline.html.haml b/app/views/projects/commit/_pipeline.html.haml index 0411137b7c6..41fd5459429 100644 --- a/app/views/projects/commit/_pipeline.html.haml +++ b/app/views/projects/commit/_pipeline.html.haml @@ -42,9 +42,7 @@ %th Status %th Build ID %th Name - %th Tags - %th Duration - %th Finished at + %th - if pipeline.project.build_coverage_enabled? %th Coverage %th diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml index 312bd86ed04..7612fe3719a 100644 --- a/app/views/projects/issues/index.html.haml +++ b/app/views/projects/issues/index.html.haml @@ -32,7 +32,7 @@ Code, test, and deploy together .blank-state .blank-state-icon - = navbar_icon("issues", size: 50) + = custom_icon("issues", size: 50) %h3.blank-state-title You don't have any issues right now. %p.blank-state-text diff --git a/app/views/shared/icons/_icon_commit.svg b/app/views/shared/icons/_icon_commit.svg new file mode 100644 index 00000000000..0e96035b7b7 --- /dev/null +++ b/app/views/shared/icons/_icon_commit.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/views/shared/icons/_icon_timer.svg b/app/views/shared/icons/_icon_timer.svg new file mode 100644 index 00000000000..0b1e5804427 --- /dev/null +++ b/app/views/shared/icons/_icon_timer.svg @@ -0,0 +1 @@ + \ No newline at end of file From 8ed105bf42ed28be1d9c19e2cd6401fb3c89a046 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 11 Jul 2016 15:36:09 -0500 Subject: [PATCH 171/335] Fix label alignment bug; re-add build-link --- app/assets/stylesheets/pages/pipelines.scss | 5 ++++- app/views/admin/builds/_build.html.haml | 16 ++++++++-------- app/views/projects/ci/builds/_build.html.haml | 16 ++++++++-------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 064bb83e44c..cbf8297f387 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -81,7 +81,10 @@ } .label-container { - margin-top: 5px; + + .label { + margin-top: 5px; + } } } diff --git a/app/views/admin/builds/_build.html.haml b/app/views/admin/builds/_build.html.haml index c60f81f8936..2b5a4628242 100644 --- a/app/views/admin/builds/_build.html.haml +++ b/app/views/admin/builds/_build.html.haml @@ -7,9 +7,9 @@ .branch-commit - if can?(current_user, :read_build, build.project) = link_to namespace_project_build_url(build.project.namespace, build.project, build) do - %span ##{build.id} + %span.build-link ##{build.id} - else - %span ##{build.id} + %span.build-link ##{build.id} - if build.stuck? %i.fa.fa-warning.text-warning @@ -22,15 +22,15 @@ = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace commit-id" - - if build.tags.any? - .label-container + .label-container + - if build.tags.any? - build.tags.each do |tag| %span.label.label-primary = tag - - if build.try(:trigger_request) - %span.label.label-info triggered - - if build.try(:allow_failure) - %span.label.label-danger allowed to fail + - if build.try(:trigger_request) + %span.label.label-info triggered + - if build.try(:allow_failure) + %span.label.label-danger allowed to fail %td - if project diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml index 0c29658e4d9..f60929d0990 100644 --- a/app/views/projects/ci/builds/_build.html.haml +++ b/app/views/projects/ci/builds/_build.html.haml @@ -28,17 +28,17 @@ - if defined?(commit_sha) && commit_sha = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "commit-id monospace" - - if build.tags.any? - .label-container + .label-container + - if build.tags.any? - build.tags.each do |tag| %span.label.label-primary = tag - - if build.try(:trigger_request) - %span.label.label-info triggered - - if build.try(:allow_failure) - %span.label.label-danger allowed to fail - - if defined?(retried) && retried - %span.label.label-warning retried + - if build.try(:trigger_request) + %span.label.label-info triggered + - if build.try(:allow_failure) + %span.label.label-danger allowed to fail + - if defined?(retried) && retried + %span.label.label-warning retried - if defined?(runner) && runner From 843ac2a351d2b957dc60ad3476faacc91d7972d8 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 11 Jul 2016 16:50:35 -0500 Subject: [PATCH 172/335] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index a50edf1a797..fafbf3c7edc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -83,6 +83,7 @@ v 8.10.0 (unreleased) - Style of import project buttons were fixed in the new project page. !5183 (rdemirbay) - Fix GitHub client requests when rate limit is disabled - Optimistic locking for Issues and Merge Requests (Title and description overriding prevention) + - Redesign Builds and Pipelines pages v 8.9.6 (unreleased) - Fix importing of events under notes for GitLab projects From 6b5cb2455e8ee9dee2b62ebba4f12e3b258f1a7c Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 11 Jul 2016 18:23:21 -0500 Subject: [PATCH 173/335] Update duration representation on builds pages --- app/views/admin/builds/_build.html.haml | 2 +- app/views/projects/ci/builds/_build.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/builds/_build.html.haml b/app/views/admin/builds/_build.html.haml index 2b5a4628242..ce818c30c30 100644 --- a/app/views/admin/builds/_build.html.haml +++ b/app/views/admin/builds/_build.html.haml @@ -49,7 +49,7 @@ - if build.duration %p.duration = custom_icon("icon_timer") - #{duration_in_words(build.finished_at, build.started_at)} + = duration_in_numbers(build.finished_at, build.started_at) - if build.finished_at %p.finished-at diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml index f60929d0990..e1b42b2cfa5 100644 --- a/app/views/projects/ci/builds/_build.html.haml +++ b/app/views/projects/ci/builds/_build.html.haml @@ -59,7 +59,7 @@ - if build.duration %p.duration = custom_icon("icon_timer") - #{duration_in_words(build.finished_at, build.started_at)} + = duration_in_numbers(build.finished_at, build.started_at) - if build.finished_at %p.finished-at = icon("calendar") From bd7d6124524e0a2222f7837b27857b363b34729f Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 12 Jul 2016 14:55:18 -0500 Subject: [PATCH 174/335] Update CHANGELOG for 8.9.6 [ci skip] --- CHANGELOG | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a50edf1a797..6fbbec0a520 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -84,8 +84,11 @@ v 8.10.0 (unreleased) - Fix GitHub client requests when rate limit is disabled - Optimistic locking for Issues and Merge Requests (Title and description overriding prevention) -v 8.9.6 (unreleased) - - Fix importing of events under notes for GitLab projects +v 8.9.6 + - Fix importing of events under notes for GitLab projects. !5154 + - Fix log statements in import/export. !5129 + - Fix commit avatar alignment in compare view. !5128 + - Fix broken migration in MySQL. !5005 v 8.9.5 - Add more debug info to import/export and memory killer. !5108 From 0ec69815868f77526bd5a2c060d22fbe272af9ea Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 11 Jul 2016 19:48:35 -0500 Subject: [PATCH 175/335] Use number_with_delimiter for Todos pending/done tab counts --- app/views/dashboard/todos/index.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml index fc42e5dcc66..4e340b6ec16 100644 --- a/app/views/dashboard/todos/index.html.haml +++ b/app/views/dashboard/todos/index.html.haml @@ -9,14 +9,14 @@ %span To do %span.badge - = todos_pending_count + = number_with_delimiter(todos_pending_count) - todo_done_active = ('active' if params[:state] == 'done') %li{class: "todos-done #{todo_done_active}"} = link_to todos_filter_path(state: 'done') do %span Done %span.badge - = todos_done_count + = number_with_delimiter(todos_done_count) .nav-controls - if @todos.any?(&:pending?) From 78d75652bc69854136c97a45652c1c705b4ad854 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 12 Jul 2016 15:06:04 -0500 Subject: [PATCH 176/335] Add a UI guide note about number_with_delimiter [ci skip] --- doc/development/ui_guide.md | 48 +++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/doc/development/ui_guide.md b/doc/development/ui_guide.md index 8d02c52c477..65252288019 100644 --- a/doc/development/ui_guide.md +++ b/doc/development/ui_guide.md @@ -1,45 +1,45 @@ -# UI Guide for building GitLab +# UI Guide for building GitLab ## GitLab UI development kit We created a page inside GitLab where you can check commonly used html and css elements. -When you run GitLab instance locally - just visit http://localhost:3000/help/ui page to see UI examples +When you run GitLab instance locally - just visit http://localhost:3000/help/ui page to see UI examples you can use during GitLab development. ## Design repository -All design files are stored in the [gitlab-design](https://gitlab.com/gitlab-org/gitlab-design) -repository and maintained by GitLab UX designers. +All design files are stored in the [gitlab-design](https://gitlab.com/gitlab-org/gitlab-design) +repository and maintained by GitLab UX designers. ## Navigation -GitLab's layout contains 2 sections: the left sidebar and the content. The left sidebar contains a static navigation menu. -This menu will be visible regardless of what page you visit. The left sidebar also contains the GitLab logo -and the current user's profile picture. The content section contains a header and the content itself. -The header describes the current GitLab page and what navigation is -available to user in this area. Depending on the area (project, group, profile setting) the header name and navigation may change. For example when user visits one of the +GitLab's layout contains 2 sections: the left sidebar and the content. The left sidebar contains a static navigation menu. +This menu will be visible regardless of what page you visit. The left sidebar also contains the GitLab logo +and the current user's profile picture. The content section contains a header and the content itself. +The header describes the current GitLab page and what navigation is +available to user in this area. Depending on the area (project, group, profile setting) the header name and navigation may change. For example when user visits one of the project pages the header will contain a project name and navigation for that project. When the user visits a group page it will contain a group name and navigation related to this group. ### Adding new tab to header navigation -We try to keep the amount of tabs in the header navigation between 5 and 10 so that it fits on a typical laptop screen. We also try not to confuse the user with too many options. Ideally each -tab should represent separate functionality. Everything related to the issue -tracker should be under the 'Issues' tab while everything related to the wiki should +We try to keep the amount of tabs in the header navigation between 5 and 10 so that it fits on a typical laptop screen. We also try not to confuse the user with too many options. Ideally each +tab should represent separate functionality. Everything related to the issue +tracker should be under the 'Issues' tab while everything related to the wiki should be under 'Wiki' tab and so on and so forth. -When adding a new tab to the header don't use more than 2 words for text in the link. +When adding a new tab to the header don't use more than 2 words for text in the link. We want to keep links short and easy to remember and fit all of them in the small screen. -## Mobile screen size +## Mobile screen size -We want GitLab to work well on small mobile screens as well. Size limitations make it is impossible to fit everything on a mobile screen. In this case it is OK to hide -part of the UI for smaller resolutions in favor of a better user experience. +We want GitLab to work well on small mobile screens as well. Size limitations make it is impossible to fit everything on a mobile screen. In this case it is OK to hide +part of the UI for smaller resolutions in favor of a better user experience. However core functionality like browsing files, creating issues, writing comments, should be available on all resolutions. ## Icons -* `trash` icon for button or link that does destructive action like removing +* `trash` icon for button or link that does destructive action like removing information from database or file system * `x` icon for closing/hiding UI element. For example close modal window * `pencil` icon for edit button or link @@ -52,8 +52,14 @@ information from database or file system * Button should contain icon or text. Exceptions should be approved by UX designer. * Use red button for destructive actions (not revertable). For example removing issue. -* Use green or blue button for primary action. Primary button should be only one. -Do not use both green and blue button in one form. -* For all other cases use default white button. -* Text button should have only first word capitalized. So should be "Create issue" instead of "Create Issue" +* Use green or blue button for primary action. Primary button should be only one. +Do not use both green and blue button in one form. +* For all other cases use default white button. +* Text button should have only first word capitalized. So should be "Create issue" instead of "Create Issue" +## Counts + +* Always use the [`number_with_delimiter`][number_with_delimiter] helper to + display counts in the UI. + +[number_with_delimiter]: http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html#method-i-number_with_delimiter From 3404e10fd003efdc44d9689eec120babd0513009 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Tue, 12 Jul 2016 15:58:26 -0500 Subject: [PATCH 177/335] Change running status color to blue; update icon to spinner --- app/assets/stylesheets/pages/merge_requests.scss | 7 +++++-- app/assets/stylesheets/pages/status.scss | 12 +++++++++--- app/helpers/ci_status_helper.rb | 4 +++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index d9756b66af0..15c6c9f231a 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -73,11 +73,14 @@ color: #888; } - &.ci-pending, - &.ci-running { + &.ci-pending { color: $gl-warning; } + &.ci-running { + color: $blue-normal; + } + &.ci-failed, &.ci-error { color: $gl-danger; diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss index 2370d35924e..c6b053150be 100644 --- a/app/assets/stylesheets/pages/status.scss +++ b/app/assets/stylesheets/pages/status.scss @@ -32,11 +32,15 @@ border-color: $gl-gray; } - &.ci-pending, - &.ci-running { + &.ci-pending { color: $gl-warning; border-color: $gl-warning; } + + &.ci-running { + color: $blue-normal; + border-color: $blue-normal; + } } .ci-status-icon-success { @@ -45,10 +49,12 @@ .ci-status-icon-failed { color: $gl-danger; } - .ci-status-icon-running, .ci-status-icon-pending { color: $gl-warning; } + .ci-status-icon-running { + color: $blue-normal; + } .ci-status-icon-canceled, .ci-status-icon-disabled, .ci-status-icon-not-found, diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index 8e4ae1e6aec..e6c99c9959e 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -29,8 +29,10 @@ module CiStatusHelper 'check' when 'failed' 'close' - when 'running', 'pending' + when 'pending' 'clock-o' + when 'running' + 'spinner' else 'circle' end From 6434be6384c34c0edd377bea11247100a65192ba Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Tue, 12 Jul 2016 16:12:23 -0500 Subject: [PATCH 178/335] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 3a176cd5a1e..bdc2c6aae28 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -84,6 +84,7 @@ v 8.10.0 (unreleased) - Fix GitHub client requests when rate limit is disabled - Optimistic locking for Issues and Merge Requests (Title and description overriding prevention) - Redesign Builds and Pipelines pages + - Change status color and icon for running builds v 8.9.6 - Fix importing of events under notes for GitLab projects. !5154 From 489e1937043d6f58af28d11831ba6da94e90a705 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 13 Jul 2016 00:02:10 -0500 Subject: [PATCH 179/335] Rename constant to be more descriptive --- lib/gitlab/diff/inline_diff.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/diff/inline_diff.rb b/lib/gitlab/diff/inline_diff.rb index 4a3eb92b9fc..28ad637fda4 100644 --- a/lib/gitlab/diff/inline_diff.rb +++ b/lib/gitlab/diff/inline_diff.rb @@ -2,7 +2,7 @@ module Gitlab module Diff class InlineDiff # Regex to find a run of deleted lines followed by the same number of added lines - REGEX = %r{ + LINE_PAIRS_PATTERN = %r{ # Runs start at the beginning of the string (the first line) or after a space (for an unchanged line) (?:\A|\s) @@ -72,7 +72,7 @@ module Gitlab line_prefixes = lines.each_with_object("") { |line, s| s << line[0] }.gsub(/[^ +-]/, ' ') changed_line_pairs = [] - line_prefixes.scan(REGEX) do + line_prefixes.scan(LINE_PAIRS_PATTERN) do # For `"---+++"`, `begin_index == 0`, `end_index == 6` begin_index, end_index = Regexp.last_match.offset(:del_ins) From 545a85dc6487d80c3bc64df85f43765937ca3c86 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Sun, 10 Jul 2016 23:48:44 -0500 Subject: [PATCH 180/335] Actually render old and new sections of parallel diff next to each other --- CHANGELOG | 1 + features/steps/shared/diff_note.rb | 4 +- lib/gitlab/diff/parallel_diff.rb | 129 +++++++++++-------------- spec/fixtures/parallel_diff_result.yml | 34 ++----- 4 files changed, 65 insertions(+), 103 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3e4a10bb5a3..ac8f5de855c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -33,6 +33,7 @@ v 8.10.0 (unreleased) - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - Only show New Snippet button to users that can create snippets. - PipelinesFinder uses git cache data + - Actually render old and new sections of parallel diff next to each other - Throttle the update of `project.pushes_since_gc` to 1 minute. - Check for conflicts with existing Project's wiki path when creating a new project. - Show last push widget in upstream after push to fork diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb index 56ef44ec969..2f20d8bd6da 100644 --- a/features/steps/shared/diff_note.rb +++ b/features/steps/shared/diff_note.rb @@ -32,8 +32,8 @@ module SharedDiffNote end step 'I leave a diff comment in a parallel view on the left side like "Old comment"' do - click_parallel_diff_line(sample_commit.line_code, 'old') - page.within("#{diff_file_selector} form[data-line-code='#{sample_commit.line_code}']") do + click_parallel_diff_line(sample_commit.del_line_code, 'old') + page.within("#{diff_file_selector} form[data-line-code='#{sample_commit.del_line_code}']") do fill_in "note[note]", with: "Old comment" find(".js-comment-button").trigger("click") end diff --git a/lib/gitlab/diff/parallel_diff.rb b/lib/gitlab/diff/parallel_diff.rb index 1c1fc148123..b069afdd28c 100644 --- a/lib/gitlab/diff/parallel_diff.rb +++ b/lib/gitlab/diff/parallel_diff.rb @@ -8,95 +8,78 @@ module Gitlab end def parallelize - lines = [] - skip_next = false + i = 0 + free_right_index = nil + + lines = [] highlighted_diff_lines = diff_file.highlighted_diff_lines highlighted_diff_lines.each do |line| - full_line = line.text - type = line.type line_code = diff_file.line_code(line) - line_new = line.new_pos - line_old = line.old_pos position = diff_file.position(line) - next_line = diff_file.next_line(line.index) - - if next_line - next_line = highlighted_diff_lines[next_line.index] - full_next_line = next_line.text - next_line_code = diff_file.line_code(next_line) - next_type = next_line.type - next_position = diff_file.position(next_line) - end - - case type + case line.type when 'match', nil # line in the right panel is the same as in the left one lines << { left: { - type: type, - number: line_old, - text: full_line, + type: line.type, + number: line.old_pos, + text: line.text, line_code: line_code, position: position }, right: { - type: type, - number: line_new, - text: full_line, + type: line.type, + number: line.new_pos, + text: line.text, line_code: line_code, position: position } } + + free_right_index = nil + i += 1 when 'old' - case next_type - when 'new' - # Left side has text removed, right side has text added - lines << { - left: { - type: type, - number: line_old, - text: full_line, - line_code: line_code, - position: position - }, - right: { - type: next_type, - number: line_new, - text: full_next_line, - line_code: next_line_code, - position: next_position, - } + lines << { + left: { + type: line.type, + number: line.old_pos, + text: line.text, + line_code: line_code, + position: position + }, + right: { + type: nil, + number: nil, + text: "", + line_code: line_code, + position: position } - skip_next = true - when 'old', 'nonewline', nil - # Left side has text removed, right side doesn't have any change - # No next line code, no new line number, no new line text - lines << { - left: { - type: type, - number: line_old, - text: full_line, - line_code: line_code, - position: position - }, - right: { - type: next_type, - number: nil, - text: "", - line_code: nil, - position: nil - } - } - end + } + + # Once we come upon a new line it can be put on the right of this old line + free_right_index ||= i + i += 1 when 'new' - if skip_next - # Change has been already included in previous line so no need to do it again - skip_next = false - next + data = { + type: line.type, + number: line.new_pos, + text: line.text, + line_code: line_code, + position: position + } + + if free_right_index + # If an old line came before this without a line on the right, this + # line can be put to the right of it. + lines[free_right_index][:right] = data + + # If there are any other old lines on the left that don't yet have + # a new counterpart on the right, update the free_right_index + next_free_right_index = free_right_index + 1 + free_right_index = next_free_right_index < i ? next_free_right_index : nil else - # Change is only on the right side, left side has no change lines << { left: { type: nil, @@ -105,17 +88,15 @@ module Gitlab line_code: line_code, position: position }, - right: { - type: type, - number: line_new, - text: full_line, - line_code: line_code, - position: position - } + right: data } + + free_right_index = nil + i += 1 end end end + lines end end diff --git a/spec/fixtures/parallel_diff_result.yml b/spec/fixtures/parallel_diff_result.yml index 7d01183e3ef..333eda1191a 100644 --- a/spec/fixtures/parallel_diff_result.yml +++ b/spec/fixtures/parallel_diff_result.yml @@ -252,27 +252,6 @@ :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9 :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9 :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d - :right: - :type: old - :number: - :text: '' - :line_code: - :position: -- :left: - :type: old - :number: 14 - :text: | - - options = { chdir: path } - :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_13 - :position: !ruby/object:Gitlab::Diff::Position - attributes: - :old_path: files/ruby/popen.rb - :new_path: files/ruby/popen.rb - :old_line: 14 - :new_line: - :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9 - :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9 - :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d :right: :type: new :number: 13 @@ -289,16 +268,17 @@ :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9 :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d - :left: - :type: - :number: - :text: '' - :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14 + :type: old + :number: 14 + :text: | + - options = { chdir: path } + :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_13 :position: !ruby/object:Gitlab::Diff::Position attributes: :old_path: files/ruby/popen.rb :new_path: files/ruby/popen.rb - :old_line: - :new_line: 14 + :old_line: 14 + :new_line: :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9 :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9 :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d From 9b234825e45884d24d78de81f5934ed765a27302 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 13 Jul 2016 09:26:40 +0200 Subject: [PATCH 181/335] fix specs --- app/models/project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index 57ea948390b..f85c6a65858 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -465,7 +465,7 @@ class Project < ActiveRecord::Base import_url = Gitlab::UrlSanitizer.new(value) super(import_url.sanitized_url) - create_or_update_import_data(credentials: import_url.credentials) if valid? + create_or_update_import_data(credentials: import_url.credentials) unless errors.messages[:import_url] end def import_url From f0577d838544152f558411ef1101d56c5852d92e Mon Sep 17 00:00:00 2001 From: Mathias Vestergaard Date: Fri, 20 May 2016 01:58:34 +0200 Subject: [PATCH 182/335] Added "developers can merge" setting to protected branches - Cherry-picked from `mvestergaard:branch-protection-dev-merge` - https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4220 --- CHANGELOG | 1 + .../javascripts/protected_branches.js.coffee | 9 +++++--- .../projects/protected_branches_controller.rb | 2 +- app/models/merge_request.rb | 3 ++- app/models/project.rb | 4 ++++ app/services/git_push_service.rb | 3 ++- .../_branches_list.html.haml | 2 ++ .../_protected_branch.html.haml | 2 ++ .../protected_branches/index.html.haml | 8 +++++++ ...elopers_can_merge_to_protected_branches.rb | 9 ++++++++ db/schema.rb | 7 ++++--- lib/gitlab/access.rb | 8 ++++--- lib/gitlab/git_access.rb | 10 +++++++++ spec/lib/gitlab/git_access_spec.rb | 21 +++++++++++++++++++ spec/services/git_push_service_spec.rb | 13 ++++++++++-- 15 files changed, 88 insertions(+), 14 deletions(-) create mode 100644 db/migrate/20160519203051_add_developers_can_merge_to_protected_branches.rb diff --git a/CHANGELOG b/CHANGELOG index f1dcc40a273..e144ba8513f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -497,6 +497,7 @@ v 8.7.7 - Prevent unauthorized access to other projects build traces - Forbid scripting for wiki files - Only show notes through JSON on confidential issues that the user has access to + - Added protected branch setting that allows Developers to accept merge requests while push is still disallowed. !4220 (Mathias Vestergaard) v 8.7.6 - Fix links on wiki pages for relative url setups. !4131 (Artem Sidorenko) diff --git a/app/assets/javascripts/protected_branches.js.coffee b/app/assets/javascripts/protected_branches.js.coffee index 79c2306e4d2..ce2fc883620 100644 --- a/app/assets/javascripts/protected_branches.js.coffee +++ b/app/assets/javascripts/protected_branches.js.coffee @@ -1,9 +1,11 @@ $ -> $(".protected-branches-list :checkbox").change (e) -> name = $(this).attr("name") - if name == "developers_can_push" + row = $(this).parents("tr") + if name == "developers_can_push" || name == "developers_can_merge" id = $(this).val() - checked = $(this).is(":checked") + can_push = row.find("input[name=developers_can_push]").is(":checked") + can_merge = row.find("input[name=developers_can_merge]").is(":checked") url = $(this).data("url") $.ajax type: "PUT" @@ -12,7 +14,8 @@ $ -> data: id: id protected_branch: - developers_can_push: checked + developers_can_push: can_push + developers_can_merge: can_merge success: -> row = $(e.target) diff --git a/app/controllers/projects/protected_branches_controller.rb b/app/controllers/projects/protected_branches_controller.rb index 80dad758afa..10dca47fded 100644 --- a/app/controllers/projects/protected_branches_controller.rb +++ b/app/controllers/projects/protected_branches_controller.rb @@ -50,6 +50,6 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController end def protected_branch_params - params.require(:protected_branch).permit(:name, :developers_can_push) + params.require(:protected_branch).permit(:name, :developers_can_push, :developers_can_merge) end end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 157901378d3..23d68706527 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -552,7 +552,8 @@ class MergeRequest < ActiveRecord::Base end def can_be_merged_by?(user) - ::Gitlab::GitAccess.new(user, project, 'web').can_push_to_branch?(target_branch) + access = ::Gitlab::GitAccess.new(user, project, 'web') + access.can_push_to_branch?(target_branch) || access.can_merge_to_branch?(target_branch) end def mergeable_ci_state? diff --git a/app/models/project.rb b/app/models/project.rb index a66b750cd48..2bd97fc48f1 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -832,6 +832,10 @@ class Project < ActiveRecord::Base protected_branches.matching(branch_name).any?(&:developers_can_push) end + def developers_can_merge_to_protected_branch?(branch_name) + protected_branches.matching(branch_name).any?(&:developers_can_merge) + end + def forked? !(forked_project_link.nil? || forked_project_link.forked_from_project.nil?) end diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index a886f35981f..e02b50ff9a2 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -89,7 +89,8 @@ class GitPushService < BaseService # Set protection on the default branch if configured if current_application_settings.default_branch_protection != PROTECTION_NONE developers_can_push = current_application_settings.default_branch_protection == PROTECTION_DEV_CAN_PUSH ? true : false - @project.protected_branches.create({ name: @project.default_branch, developers_can_push: developers_can_push }) + developers_can_merge = current_application_settings.default_branch_protection == PROTECTION_DEV_CAN_MERGE ? true : false + @project.protected_branches.create({ name: @project.default_branch, developers_can_push: developers_can_push, developers_can_merge: developers_can_merge }) end end diff --git a/app/views/projects/protected_branches/_branches_list.html.haml b/app/views/projects/protected_branches/_branches_list.html.haml index 97cb1a9052b..181d1a27c73 100644 --- a/app/views/projects/protected_branches/_branches_list.html.haml +++ b/app/views/projects/protected_branches/_branches_list.html.haml @@ -8,6 +8,7 @@ .table-responsive %table.table.protected-branches-list %colgroup + %col{ width: "27%" } %col{ width: "30%" } %col{ width: "25%" } %col{ width: "25%" } @@ -18,6 +19,7 @@ %th Protected Branch %th Commit %th Developers Can Push + %th Developers can Merge - if can_admin_project %th %tbody diff --git a/app/views/projects/protected_branches/_protected_branch.html.haml b/app/views/projects/protected_branches/_protected_branch.html.haml index 474aec3a97c..7fda7f96047 100644 --- a/app/views/projects/protected_branches/_protected_branch.html.haml +++ b/app/views/projects/protected_branches/_protected_branch.html.haml @@ -16,6 +16,8 @@ (branch was removed from repository) %td = check_box_tag("developers_can_push", protected_branch.id, protected_branch.developers_can_push, data: { url: url }) + %td + = check_box_tag("developers_can_merge", protected_branch.id, protected_branch.developers_can_merge, data: { url: url }) - if can_admin_project %td = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, protected_branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-warning btn-sm pull-right" diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml index 3fab95751e0..101b3f3b452 100644 --- a/app/views/projects/protected_branches/index.html.haml +++ b/app/views/projects/protected_branches/index.html.haml @@ -36,6 +36,14 @@ = f.label :developers_can_push, "Developers can push", class: "label-light append-bottom-0" %p.light.append-bottom-0 Allow developers to push to this branch + + .form-group + = f.check_box :developers_can_merge, class: "pull-left" + .prepend-left-20 + = f.label :developers_can_merge, "Developers can merge", class: "label-light append-bottom-0" + %p.light.append-bottom-0 + Allow developers to accept merge requests to this branch = f.submit "Protect", class: "btn-create btn protect-branch-btn", disabled: true + %hr = render "branches_list" diff --git a/db/migrate/20160519203051_add_developers_can_merge_to_protected_branches.rb b/db/migrate/20160519203051_add_developers_can_merge_to_protected_branches.rb new file mode 100644 index 00000000000..15ad8e8bcbb --- /dev/null +++ b/db/migrate/20160519203051_add_developers_can_merge_to_protected_branches.rb @@ -0,0 +1,9 @@ +class AddDevelopersCanMergeToProtectedBranches < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + def change + add_column_with_default :protected_branches, :developers_can_merge, :boolean, default: false, allow_null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index f24e47b85b2..4562e6bb0c3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -860,11 +860,12 @@ ActiveRecord::Schema.define(version: 20160712171823) do add_index "projects", ["visibility_level"], name: "index_projects_on_visibility_level", using: :btree create_table "protected_branches", force: :cascade do |t| - t.integer "project_id", null: false - t.string "name", null: false + t.integer "project_id", null: false + t.string "name", null: false t.datetime "created_at" t.datetime "updated_at" - t.boolean "developers_can_push", default: false, null: false + t.boolean "developers_can_push", default: false, null: false + t.boolean "developers_can_merge", default: false, null: false end add_index "protected_branches", ["project_id"], name: "index_protected_branches_on_project_id", using: :btree diff --git a/lib/gitlab/access.rb b/lib/gitlab/access.rb index 831f1e635ba..de41ea415a6 100644 --- a/lib/gitlab/access.rb +++ b/lib/gitlab/access.rb @@ -14,9 +14,10 @@ module Gitlab OWNER = 50 # Branch protection settings - PROTECTION_NONE = 0 - PROTECTION_DEV_CAN_PUSH = 1 - PROTECTION_FULL = 2 + PROTECTION_NONE = 0 + PROTECTION_DEV_CAN_PUSH = 1 + PROTECTION_FULL = 2 + PROTECTION_DEV_CAN_MERGE = 3 class << self def values @@ -54,6 +55,7 @@ module Gitlab def protection_options { "Not protected: Both developers and masters can push new commits, force push, or delete the branch." => PROTECTION_NONE, + "Protected against pushes: Developers cannot push new commits, but are allowed to accept merge requests to the branch." => PROTECTION_DEV_CAN_MERGE, "Partially protected: Developers can push new commits, but cannot force push or delete the branch. Masters can do all of those." => PROTECTION_DEV_CAN_PUSH, "Fully protected: Developers cannot push new commits, force push, or delete the branch. Only masters can do any of those." => PROTECTION_FULL, } diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index 7679c7e4bb8..e20e3338262 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -39,6 +39,16 @@ module Gitlab end end + def can_merge_to_branch?(ref) + return false unless user + + if project.protected_branch?(ref) && !project.developers_can_merge_to_protected_branch?(ref) + user.can?(:push_code_to_protected_branches, project) + else + user.can?(:push_code, project) + end + end + def can_read_project? if user user.can?(:read_project, project) diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index c79ba11f782..b90d9c724f1 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -65,6 +65,27 @@ describe Gitlab::GitAccess, lib: true do expect(access.can_push_to_branch?(@branch.name)).to be_falsey end end + + describe 'merge to protected branch if allowed for developers' do + before do + @branch = create :protected_branch, project: project, developers_can_merge: true + end + + it "returns true if user is a master" do + project.team << [user, :master] + expect(access.can_merge_to_branch?(@branch.name)).to be_truthy + end + + it "returns true if user is a developer" do + project.team << [user, :developer] + expect(access.can_merge_to_branch?(@branch.name)).to be_truthy + end + + it "returns false if user is a reporter" do + project.team << [user, :reporter] + expect(access.can_merge_to_branch?(@branch.name)).to be_falsey + end + end end describe '#check with single protocols allowed' do diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index afabeed4a80..0f30a84a2cf 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -224,7 +224,7 @@ describe GitPushService, services: true do it "when pushing a branch for the first time" do expect(project).to receive(:execute_hooks) expect(project.default_branch).to eq("master") - expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false }) + expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false, developers_can_merge: false }) execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) end @@ -242,7 +242,16 @@ describe GitPushService, services: true do expect(project).to receive(:execute_hooks) expect(project.default_branch).to eq("master") - expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: true }) + expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: true, developers_can_merge: false }) + execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) + end + + it "when pushing a branch for the first time with default branch protection set to 'developers can merge'" do + stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE) + + expect(project).to receive(:execute_hooks) + expect(project.default_branch).to eq("master") + expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false, developers_can_merge: true }) execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) end From 495db09653bafb0371e5d5a5f12d5bc33cdb584b Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Thu, 23 Jun 2016 14:58:14 +0530 Subject: [PATCH 183/335] Enforce "developers can merge" during `pre-receive`. 1. When a merge request is being merged, save the merge commit SHA in the `in_progress_merge_commit_sha` database column. 2. The `pre-receive` hook looks for any locked (in progress) merge request with `in_progress_merge_commit_sha` matching the `newrev` it is passed. 3. If it finds a matching MR, the merge is legitimate. 4. Update `git_access_spec` to test the behaviour we added here. Also refactored this spec a bit to make it easier to add more contexts / conditions. --- app/models/repository.rb | 14 +- app/services/merge_requests/merge_service.rb | 4 +- ...ress_merge_commit_sha_to_merge_requests.rb | 8 + db/schema.rb | 1 + lib/gitlab/checks/matching_merge_request.rb | 18 ++ lib/gitlab/git_access.rb | 7 + spec/lib/gitlab/diff/position_tracer_spec.rb | 3 +- spec/lib/gitlab/git_access_spec.rb | 185 +++++++++++------- spec/models/repository_spec.rb | 9 +- .../merge_requests/refresh_service_spec.rb | 3 +- 10 files changed, 167 insertions(+), 85 deletions(-) create mode 100644 db/migrate/20160629025435_add_column_in_progress_merge_commit_sha_to_merge_requests.rb create mode 100644 lib/gitlab/checks/matching_merge_request.rb diff --git a/app/models/repository.rb b/app/models/repository.rb index 5b670cb4b8f..09487b62f98 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -769,9 +769,9 @@ class Repository end end - def merge(user, source_sha, target_branch, options = {}) - our_commit = rugged.branches[target_branch].target - their_commit = rugged.lookup(source_sha) + def merge(user, merge_request, options = {}) + our_commit = rugged.branches[merge_request.target_branch].target + their_commit = rugged.lookup(merge_request.diff_head_sha) raise "Invalid merge target" if our_commit.nil? raise "Invalid merge source" if their_commit.nil? @@ -779,14 +779,16 @@ class Repository merge_index = rugged.merge_commits(our_commit, their_commit) return false if merge_index.conflicts? - commit_with_hooks(user, target_branch) do |ref| + commit_with_hooks(user, merge_request.target_branch) do |tmp_ref| actual_options = options.merge( parents: [our_commit, their_commit], tree: merge_index.write_tree(rugged), - update_ref: ref + update_ref: tmp_ref ) - Rugged::Commit.create(rugged, actual_options) + commit_id = Rugged::Commit.create(rugged, actual_options) + merge_request.update(in_progress_merge_commit_sha: commit_id) + commit_id end end diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index f1b1d90c457..0dac0614141 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -34,7 +34,7 @@ module MergeRequests committer: committer } - commit_id = repository.merge(current_user, merge_request.diff_head_sha, merge_request.target_branch, options) + commit_id = repository.merge(current_user, merge_request, options) merge_request.update(merge_commit_sha: commit_id) rescue GitHooksService::PreReceiveError => e merge_request.update(merge_error: e.message) @@ -43,6 +43,8 @@ module MergeRequests merge_request.update(merge_error: "Something went wrong during merge") Rails.logger.error(e.message) false + ensure + merge_request.update(in_progress_merge_commit_sha: nil) end def after_merge diff --git a/db/migrate/20160629025435_add_column_in_progress_merge_commit_sha_to_merge_requests.rb b/db/migrate/20160629025435_add_column_in_progress_merge_commit_sha_to_merge_requests.rb new file mode 100644 index 00000000000..7c5f76572ef --- /dev/null +++ b/db/migrate/20160629025435_add_column_in_progress_merge_commit_sha_to_merge_requests.rb @@ -0,0 +1,8 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddColumnInProgressMergeCommitShaToMergeRequests < ActiveRecord::Migration + def change + add_column :merge_requests, :in_progress_merge_commit_sha, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 4562e6bb0c3..64019cf79bb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -626,6 +626,7 @@ ActiveRecord::Schema.define(version: 20160712171823) do t.string "merge_commit_sha" t.datetime "deleted_at" t.integer "lock_version", default: 0, null: false + t.string "in_progress_merge_commit_sha" end add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree diff --git a/lib/gitlab/checks/matching_merge_request.rb b/lib/gitlab/checks/matching_merge_request.rb new file mode 100644 index 00000000000..849848515da --- /dev/null +++ b/lib/gitlab/checks/matching_merge_request.rb @@ -0,0 +1,18 @@ +module Gitlab + module Checks + class MatchingMergeRequest + def initialize(newrev, branch_name, project) + @newrev = newrev + @branch_name = branch_name + @project = project + end + + def match? + @project.merge_requests + .with_state(:locked) + .where(in_progress_merge_commit_sha: @newrev, target_branch: @branch_name) + .exists? + end + end + end +end diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index e20e3338262..feaf845209e 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -177,10 +177,15 @@ module Gitlab Gitlab::ForcePushCheck.force_push?(project, oldrev, newrev) end + def protocol_allowed? Gitlab::ProtocolAccess.allowed?(protocol) end + def matching_merge_request?(newrev, branch_name) + Checks::MatchingMergeRequest.new(newrev, branch_name, project).match? + end + private def protected_branch_action(oldrev, newrev, branch_name) @@ -190,6 +195,8 @@ module Gitlab elsif Gitlab::Git.blank_ref?(newrev) # and we dont allow remove of protected branch :remove_protected_branches + elsif matching_merge_request?(newrev, branch_name) && project.developers_can_merge_to_protected_branch?(branch_name) + :push_code elsif project.developers_can_push_to_protected_branch?(branch_name) :push_code else diff --git a/spec/lib/gitlab/diff/position_tracer_spec.rb b/spec/lib/gitlab/diff/position_tracer_spec.rb index 08312e60f4a..c268f84c759 100644 --- a/spec/lib/gitlab/diff/position_tracer_spec.rb +++ b/spec/lib/gitlab/diff/position_tracer_spec.rb @@ -1639,7 +1639,8 @@ describe Gitlab::Diff::PositionTracer, lib: true do committer: committer } - repository.merge(current_user, second_create_file_commit.sha, branch_name, options) + merge_request = create(:merge_request, source_branch: second_create_file_commit.sha, target_branch: branch_name, source_project: project) + repository.merge(current_user, merge_request, options) project.commit(branch_name) end diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index b90d9c724f1..50cf2f1e93f 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -181,96 +181,47 @@ describe Gitlab::GitAccess, lib: true do end describe 'push_access_check' do - def protect_feature_branch - create(:protected_branch, name: 'feature', project: project) - end + before { merge_into_protected_branch } + let(:unprotected_branch) { FFaker::Internet.user_name } - def changes - { - push_new_branch: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow", + let(:changes) do + { push_new_branch: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow", push_master: '6f6d7e7ed 570e7b2ab refs/heads/master', push_protected_branch: '6f6d7e7ed 570e7b2ab refs/heads/feature', push_remove_protected_branch: "570e7b2ab #{Gitlab::Git::BLANK_SHA} "\ 'refs/heads/feature', push_tag: '6f6d7e7ed 570e7b2ab refs/tags/v1.0.0', push_new_tag: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/tags/v7.8.9", - push_all: ['6f6d7e7ed 570e7b2ab refs/heads/master', '6f6d7e7ed 570e7b2ab refs/heads/feature'] - } + push_all: ['6f6d7e7ed 570e7b2ab refs/heads/master', '6f6d7e7ed 570e7b2ab refs/heads/feature'], + merge_into_protected_branch: "0b4bc9a #{merge_into_protected_branch} refs/heads/feature" } end - def self.permissions_matrix - { - master: { - push_new_branch: true, - push_master: true, - push_protected_branch: true, - push_remove_protected_branch: false, - push_tag: true, - push_new_tag: true, - push_all: true, - }, - - developer: { - push_new_branch: true, - push_master: true, - push_protected_branch: false, - push_remove_protected_branch: false, - push_tag: false, - push_new_tag: true, - push_all: false, - }, - - reporter: { - push_new_branch: false, - push_master: false, - push_protected_branch: false, - push_remove_protected_branch: false, - push_tag: false, - push_new_tag: false, - push_all: false, - }, - - guest: { - push_new_branch: false, - push_master: false, - push_protected_branch: false, - push_remove_protected_branch: false, - push_tag: false, - push_new_tag: false, - push_all: false, - } - } + def stub_git_hooks + # Running the `pre-receive` hook is expensive, and not necessary for this test. + allow_any_instance_of(GitHooksService).to receive(:execute).and_yield end - def self.updated_permissions_matrix - updated_permissions_matrix = permissions_matrix.dup - updated_permissions_matrix[:developer][:push_protected_branch] = true - updated_permissions_matrix[:developer][:push_all] = true - updated_permissions_matrix - end + def merge_into_protected_branch + @protected_branch_merge_commit ||= begin + stub_git_hooks + project.repository.add_branch(user, unprotected_branch, 'feature') + target_branch = project.repository.lookup('feature') + source_branch = project.repository.commit_file(user, FFaker::InternetSE.login_user_name, FFaker::HipsterIpsum.paragraph, FFaker::HipsterIpsum.sentence, unprotected_branch, false) + rugged = project.repository.rugged + author = { email: "email@example.com", time: Time.now, name: "Example Git User" } - permissions_matrix.keys.each do |role| - describe "#{role} access" do - before { protect_feature_branch } - before { project.team << [user, role] } - permissions_matrix[role].each do |action, allowed| - context action do - subject { access.push_access_check(changes[action]) } - - it { expect(subject.allowed?).to allowed ? be_truthy : be_falsey } - end - end + merge_index = rugged.merge_commits(target_branch, source_branch) + Rugged::Commit.create(rugged, author: author, committer: author, message: "commit message", parents: [target_branch, source_branch], tree: merge_index.write_tree(rugged)) end end - context "with enabled developers push to protected branches " do - updated_permissions_matrix.keys.each do |role| + def self.run_permission_checks(permissions_matrix) + permissions_matrix.keys.each do |role| describe "#{role} access" do - before { create(:protected_branch, name: 'feature', developers_can_push: true, project: project) } before { project.team << [user, role] } - updated_permissions_matrix[role].each do |action, allowed| + permissions_matrix[role].each do |action, allowed| context action do subject { access.push_access_check(changes[action]) } @@ -280,5 +231,97 @@ describe Gitlab::GitAccess, lib: true do end end end + + permissions_matrix = { + master: { + push_new_branch: true, + push_master: true, + push_protected_branch: true, + push_remove_protected_branch: false, + push_tag: true, + push_new_tag: true, + push_all: true, + merge_into_protected_branch: true + }, + + developer: { + push_new_branch: true, + push_master: true, + push_protected_branch: false, + push_remove_protected_branch: false, + push_tag: false, + push_new_tag: true, + push_all: false, + merge_into_protected_branch: false + }, + + reporter: { + push_new_branch: false, + push_master: false, + push_protected_branch: false, + push_remove_protected_branch: false, + push_tag: false, + push_new_tag: false, + push_all: false, + merge_into_protected_branch: false + }, + + guest: { + push_new_branch: false, + push_master: false, + push_protected_branch: false, + push_remove_protected_branch: false, + push_tag: false, + push_new_tag: false, + push_all: false, + merge_into_protected_branch: false + } + } + + [['feature', 'exact'], ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type| + context do + before { create(:protected_branch, name: protected_branch_name, project: project) } + + run_permission_checks(permissions_matrix) + end + + context "when 'developers can push' is turned on for the #{protected_branch_type} protected branch" do + before { create(:protected_branch, name: protected_branch_name, developers_can_push: true, project: project) } + + run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true })) + end + + context "when 'developers can merge' is turned on for the #{protected_branch_type} protected branch" do + before { create(:protected_branch, name: protected_branch_name, developers_can_merge: true, project: project) } + + context "when a merge request exists for the given source/target branch" do + context "when the merge request is in progress" do + before do + create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', state: 'locked', in_progress_merge_commit_sha: merge_into_protected_branch) + end + + run_permission_checks(permissions_matrix.deep_merge(developer: { merge_into_protected_branch: true })) + end + + context "when the merge request is not in progress" do + before do + create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', in_progress_merge_commit_sha: nil) + end + + run_permission_checks(permissions_matrix.deep_merge(developer: { merge_into_protected_branch: false })) + end + end + + context "when a merge request does not exist for the given source/target branch" do + run_permission_checks(permissions_matrix.deep_merge(developer: { merge_into_protected_branch: false })) + end + end + + context "when 'developers can merge' and 'developers can push' are turned on for the #{protected_branch_type} protected branch" do + before { create(:protected_branch, name: protected_branch_name, developers_can_merge: true, developers_can_push: true, project: project) } + + run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true })) + end + end end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index b39b958450c..e14cec589fe 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -4,16 +4,17 @@ describe Repository, models: true do include RepoHelpers TestBlob = Struct.new(:name) - let(:repository) { create(:project).repository } + let(:project) { create(:project) } + let(:repository) { project.repository } let(:user) { create(:user) } let(:commit_options) do author = repository.user_to_committer(user) { message: 'Test message', committer: author, author: author } end let(:merge_commit) do - source_sha = repository.find_branch('feature').target - merge_commit_sha = repository.merge(user, source_sha, 'master', commit_options) - repository.commit(merge_commit_sha) + merge_request = create(:merge_request, source_branch: 'feature', target_branch: 'master', source_project: project) + merge_commit_id = repository.merge(user, merge_request, commit_options) + repository.commit(merge_commit_id) end describe '#branch_names_contains' do diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 06f56d85aa8..ce643b3f860 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -88,8 +88,7 @@ describe MergeRequests::RefreshService, services: true do # Merge master -> feature branch author = { email: 'test@gitlab.com', time: Time.now, name: "Me" } commit_options = { message: 'Test message', committer: author, author: author } - master_commit = @project.repository.commit('master') - @project.repository.merge(@user, master_commit.id, 'feature', commit_options) + @project.repository.merge(@user, @merge_request, commit_options) commit = @project.repository.commit('feature') service.new(@project, @user).execute(@oldrev, commit.id, 'refs/heads/feature') reload_mrs From 60245bbe228014a9f689adafd64b571883ef6eb3 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Fri, 24 Jun 2016 10:37:04 +0530 Subject: [PATCH 184/335] Refactor `Gitlab::GitAccess` 1. Don't use case statements for dispatch anymore. This leads to a lot of duplication, and makes the logic harder to follow. 2. Remove duplicated logic. - For example, the `can_push_to_branch?` exists, but we also have a different way of checking the same condition within `change_access_check`. - This kind of duplication is removed, and the `can_push_to_branch?` method is used in both places. 3. Move checks returning true/false to `UserAccess`. - All public methods in `GitAccess` now return an instance of `GitAccessStatus`. Previously, some methods would return true/false as well, which was confusing. - It makes sense for these kinds of checks to be at the level of a user, so the `UserAccess` class was repurposed for this. The prior `UserAccess.allowed?` classmethod is converted into an instance method. - All external uses of these checks have been migrated to use the `UserAccess` class 4. Move the "change_access_check" into a separate class. - Create the `GitAccess::ChangeAccessCheck` class to run these checks, which are quite substantial. - `ChangeAccessCheck` returns an instance of `GitAccessStatus` as well. 5. Break out the boolean logic in `ChangeAccessCheck` into `if/else` chains - this seems more readable. 6. I can understand that this might look like overkill for !4892, but I think this is a good opportunity to clean it up. - http://martinfowler.com/bliki/OpportunisticRefactoring.html --- app/helpers/branches_helper.rb | 2 +- app/models/merge_request.rb | 2 +- app/services/commits/change_service.rb | 4 +- app/services/files/base_service.rb | 2 +- lib/api/helpers.rb | 2 +- lib/gitlab/git_access.rb | 163 ++++--------------- lib/gitlab/git_access/change_access_check.rb | 96 +++++++++++ lib/gitlab/git_access_wiki.rb | 2 +- lib/gitlab/user_access.rb | 48 +++++- spec/lib/gitlab/git_access_spec.rb | 82 ---------- spec/lib/gitlab/user_access_spec.rb | 90 ++++++++++ spec/requests/api/api_helpers_spec.rb | 4 +- 12 files changed, 272 insertions(+), 225 deletions(-) create mode 100644 lib/gitlab/git_access/change_access_check.rb create mode 100644 spec/lib/gitlab/user_access_spec.rb diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb index 601df5c18df..bfd23aa4e04 100644 --- a/app/helpers/branches_helper.rb +++ b/app/helpers/branches_helper.rb @@ -12,7 +12,7 @@ module BranchesHelper def can_push_branch?(project, branch_name) return false unless project.repository.branch_exists?(branch_name) - ::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(branch_name) + ::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(branch_name) end def project_branches diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 23d68706527..e5853bdd589 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -552,7 +552,7 @@ class MergeRequest < ActiveRecord::Base end def can_be_merged_by?(user) - access = ::Gitlab::GitAccess.new(user, project, 'web') + access = ::Gitlab::UserAccess.new(user, project: project) access.can_push_to_branch?(target_branch) || access.can_merge_to_branch?(target_branch) end diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index c578097376a..ed73d8cb8c2 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -23,7 +23,7 @@ module Commits private def check_push_permissions - allowed = ::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(@target_branch) + allowed = ::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(@target_branch) unless allowed raise ValidationError.new('You are not allowed to push into this branch') @@ -31,7 +31,7 @@ module Commits true end - + def create_target_branch(new_branch) # Temporary branch exists and contains the change commit return success if repository.find_branch(new_branch) diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 37c5e321b39..55da949f56a 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -42,7 +42,7 @@ module Files end def validate - allowed = ::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(@target_branch) + allowed = ::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(@target_branch) unless allowed raise_error("You are not allowed to push into this branch") diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 77e407b54c5..73557cf7db6 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -17,7 +17,7 @@ module API def current_user @current_user ||= (find_user_by_private_token || doorkeeper_guard) - unless @current_user && Gitlab::UserAccess.allowed?(@current_user) + unless @current_user && Gitlab::UserAccess.new(@current_user).allowed? return nil end diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index feaf845209e..cfb48ac2382 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -1,62 +1,17 @@ +# Check a user's access to perform a git action. All public methods in this +# class return an instance of `GitlabAccessStatus` module Gitlab class GitAccess DOWNLOAD_COMMANDS = %w{ git-upload-pack git-upload-archive } PUSH_COMMANDS = %w{ git-receive-pack } - attr_reader :actor, :project, :protocol + attr_reader :actor, :project, :protocol, :user_access def initialize(actor, project, protocol) @actor = actor @project = project @protocol = protocol - end - - def user - return @user if defined?(@user) - - @user = - case actor - when User - actor - when DeployKey - nil - when Key - actor.user - end - end - - def deploy_key - actor if actor.is_a?(DeployKey) - end - - def can_push_to_branch?(ref) - return false unless user - - if project.protected_branch?(ref) && !project.developers_can_push_to_protected_branch?(ref) - user.can?(:push_code_to_protected_branches, project) - else - user.can?(:push_code, project) - end - end - - def can_merge_to_branch?(ref) - return false unless user - - if project.protected_branch?(ref) && !project.developers_can_merge_to_protected_branch?(ref) - user.can?(:push_code_to_protected_branches, project) - else - user.can?(:push_code, project) - end - end - - def can_read_project? - if user - user.can?(:read_project, project) - elsif deploy_key - deploy_key.projects.include?(project) - else - false - end + @user_access = UserAccess.new(user, project: project) end def check(cmd, changes = nil) @@ -66,11 +21,11 @@ module Gitlab return build_status_object(false, "No user or key was provided.") end - if user && !user_allowed? + if user && !user_access.allowed? return build_status_object(false, "Your account has been blocked.") end - unless project && can_read_project? + unless project && (user_access.can_read_project? || deploy_key_can_read_project?) return build_status_object(false, 'The project you were looking for could not be found.') end @@ -105,7 +60,7 @@ module Gitlab end def user_download_access_check - unless user.can?(:download_code, project) + unless user_access.can_do_action?(:download_code) return build_status_object(false, "You are not allowed to download code from this project.") end @@ -135,103 +90,49 @@ module Gitlab build_status_object(true) end - def can_user_do_action?(action) - @permission_cache ||= {} - @permission_cache[action] ||= user.can?(action, project) - end - def change_access_check(change) - oldrev, newrev, ref = change.split(' ') - - action = - if project.protected_branch?(branch_name(ref)) - protected_branch_action(oldrev, newrev, branch_name(ref)) - elsif (tag_ref = tag_name(ref)) && protected_tag?(tag_ref) - # Prevent any changes to existing git tag unless user has permissions - :admin_project - else - :push_code - end - - unless can_user_do_action?(action) - status = - case action - when :force_push_code_to_protected_branches - build_status_object(false, "You are not allowed to force push code to a protected branch on this project.") - when :remove_protected_branches - build_status_object(false, "You are not allowed to deleted protected branches from this project.") - when :push_code_to_protected_branches - build_status_object(false, "You are not allowed to push code to protected branches on this project.") - when :admin_project - build_status_object(false, "You are not allowed to change existing tags on this project.") - else # :push_code - build_status_object(false, "You are not allowed to push code to this project.") - end - return status - end - - build_status_object(true) + ChangeAccessCheck.new(change, user_access: user_access, project: project).exec end - def forced_push?(oldrev, newrev) - Gitlab::ForcePushCheck.force_push?(project, oldrev, newrev) - end - - def protocol_allowed? Gitlab::ProtocolAccess.allowed?(protocol) end + private + def matching_merge_request?(newrev, branch_name) Checks::MatchingMergeRequest.new(newrev, branch_name, project).match? end - private + def deploy_key + actor if actor.is_a?(DeployKey) + end - def protected_branch_action(oldrev, newrev, branch_name) - # we dont allow force push to protected branch - if forced_push?(oldrev, newrev) - :force_push_code_to_protected_branches - elsif Gitlab::Git.blank_ref?(newrev) - # and we dont allow remove of protected branch - :remove_protected_branches - elsif matching_merge_request?(newrev, branch_name) && project.developers_can_merge_to_protected_branch?(branch_name) - :push_code - elsif project.developers_can_push_to_protected_branch?(branch_name) - :push_code + + def deploy_key_can_read_project? + if deploy_key + deploy_key.projects.include?(project) else - :push_code_to_protected_branches - end - end - - def protected_tag?(tag_name) - project.repository.tag_exists?(tag_name) - end - - def user_allowed? - Gitlab::UserAccess.allowed?(user) - end - - def branch_name(ref) - ref = ref.to_s - if Gitlab::Git.branch_ref?(ref) - Gitlab::Git.ref_name(ref) - else - nil - end - end - - def tag_name(ref) - ref = ref.to_s - if Gitlab::Git.tag_ref?(ref) - Gitlab::Git.ref_name(ref) - else - nil + false end end protected + def user + return @user if defined?(@user) + + @user = + case actor + when User + actor + when DeployKey + nil + when Key + actor.user + end + end + def build_status_object(status, message = '') GitAccessStatus.new(status, message) end diff --git a/lib/gitlab/git_access/change_access_check.rb b/lib/gitlab/git_access/change_access_check.rb new file mode 100644 index 00000000000..9268da4ec6e --- /dev/null +++ b/lib/gitlab/git_access/change_access_check.rb @@ -0,0 +1,96 @@ +module Gitlab + class GitAccess + class ChangeAccessCheck + attr_reader :user_access, :project + + def initialize(change, user_access:, project:) + @oldrev, @newrev, @ref = change.split(' ') + @branch_name = branch_name(@ref) + @user_access = user_access + @project = project + end + + def exec + error = protected_branch_checks || tag_checks || push_checks + + if error + GitAccessStatus.new(false, error) + else + GitAccessStatus.new(true) + end + end + + protected + + def protected_branch_checks + return unless project.protected_branch?(@branch_name) + + return unless project.protected_branch?(@branch_name) + + if forced_push? && user_access.cannot_do_action?(:force_push_code_to_protected_branches) + return "You are not allowed to force push code to a protected branch on this project." + elsif Gitlab::Git.blank_ref?(@newrev) && user_access.cannot_do_action?(:remove_protected_branches) + return "You are not allowed to deleted protected branches from this project." + end + + if matching_merge_request? + if user_access.can_merge_to_branch?(@branch_name) || user_access.can_push_to_branch?(@branch_name) + return + else + "You are not allowed to merge code into protected branches on this project." + end + else + if user_access.can_push_to_branch?(@branch_name) + return + else + "You are not allowed to push code to protected branches on this project." + end + end + end + + def tag_checks + if (tag_ref = tag_name(@ref)) && protected_tag?(tag_ref) && user_access.cannot_do_action?(:admin_project) + "You are not allowed to change existing tags on this project." + end + end + + def push_checks + if user_access.cannot_do_action?(:push_code) + "You are not allowed to push code to this project." + end + end + + private + + def protected_tag?(tag_name) + project.repository.tag_exists?(tag_name) + end + + def forced_push? + Gitlab::ForcePushCheck.force_push?(@project, @oldrev, @newrev) + end + + def matching_merge_request? + Checks::MatchingMergeRequest.new(@newrev, @branch_name, @project).match? + end + + def branch_name(ref) + ref = @ref.to_s + if Gitlab::Git.branch_ref?(ref) + Gitlab::Git.ref_name(ref) + else + nil + end + end + + def tag_name(ref) + ref = @ref.to_s + if Gitlab::Git.tag_ref?(ref) + Gitlab::Git.ref_name(ref) + else + nil + end + end + end + end +end diff --git a/lib/gitlab/git_access_wiki.rb b/lib/gitlab/git_access_wiki.rb index 8672cbc0ec4..f71d3575909 100644 --- a/lib/gitlab/git_access_wiki.rb +++ b/lib/gitlab/git_access_wiki.rb @@ -1,7 +1,7 @@ module Gitlab class GitAccessWiki < GitAccess def change_access_check(change) - if user.can?(:create_wiki, project) + if user_access.can_do_action?(:create_wiki) build_status_object(true) else build_status_object(false, "You are not allowed to write to this project's wiki.") diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb index d1b42c1f9b9..c0f85e9b3a8 100644 --- a/lib/gitlab/user_access.rb +++ b/lib/gitlab/user_access.rb @@ -1,7 +1,23 @@ module Gitlab - module UserAccess - def self.allowed?(user) - return false if user.blocked? + class UserAccess + attr_reader :user, :project + + def initialize(user, project: nil) + @user = user + @project = project + end + + def can_do_action?(action) + @permission_cache ||= {} + @permission_cache[action] ||= user.can?(action, project) + end + + def cannot_do_action?(action) + !can_do_action?(action) + end + + def allowed? + return false if user.blank? || user.blocked? if user.requires_ldap_check? && user.try_obtain_ldap_lease return false unless Gitlab::LDAP::Access.allowed?(user) @@ -9,5 +25,31 @@ module Gitlab true end + + def can_push_to_branch?(ref) + return false unless user + + if project.protected_branch?(ref) && !project.developers_can_push_to_protected_branch?(ref) + user.can?(:push_code_to_protected_branches, project) + else + user.can?(:push_code, project) + end + end + + def can_merge_to_branch?(ref) + return false unless user + + if project.protected_branch?(ref) && !project.developers_can_merge_to_protected_branch?(ref) + user.can?(:push_code_to_protected_branches, project) + else + user.can?(:push_code, project) + end + end + + def can_read_project? + return false unless user + + user.can?(:read_project, project) + end end end diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index 50cf2f1e93f..059d8a2c355 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -6,88 +6,6 @@ describe Gitlab::GitAccess, lib: true do let(:user) { create(:user) } let(:actor) { user } - describe 'can_push_to_branch?' do - describe 'push to none protected branch' do - it "returns true if user is a master" do - project.team << [user, :master] - expect(access.can_push_to_branch?("random_branch")).to be_truthy - end - - it "returns true if user is a developer" do - project.team << [user, :developer] - expect(access.can_push_to_branch?("random_branch")).to be_truthy - end - - it "returns false if user is a reporter" do - project.team << [user, :reporter] - expect(access.can_push_to_branch?("random_branch")).to be_falsey - end - end - - describe 'push to protected branch' do - before do - @branch = create :protected_branch, project: project - end - - it "returns true if user is a master" do - project.team << [user, :master] - expect(access.can_push_to_branch?(@branch.name)).to be_truthy - end - - it "returns false if user is a developer" do - project.team << [user, :developer] - expect(access.can_push_to_branch?(@branch.name)).to be_falsey - end - - it "returns false if user is a reporter" do - project.team << [user, :reporter] - expect(access.can_push_to_branch?(@branch.name)).to be_falsey - end - end - - describe 'push to protected branch if allowed for developers' do - before do - @branch = create :protected_branch, project: project, developers_can_push: true - end - - it "returns true if user is a master" do - project.team << [user, :master] - expect(access.can_push_to_branch?(@branch.name)).to be_truthy - end - - it "returns true if user is a developer" do - project.team << [user, :developer] - expect(access.can_push_to_branch?(@branch.name)).to be_truthy - end - - it "returns false if user is a reporter" do - project.team << [user, :reporter] - expect(access.can_push_to_branch?(@branch.name)).to be_falsey - end - end - - describe 'merge to protected branch if allowed for developers' do - before do - @branch = create :protected_branch, project: project, developers_can_merge: true - end - - it "returns true if user is a master" do - project.team << [user, :master] - expect(access.can_merge_to_branch?(@branch.name)).to be_truthy - end - - it "returns true if user is a developer" do - project.team << [user, :developer] - expect(access.can_merge_to_branch?(@branch.name)).to be_truthy - end - - it "returns false if user is a reporter" do - project.team << [user, :reporter] - expect(access.can_merge_to_branch?(@branch.name)).to be_falsey - end - end - end - describe '#check with single protocols allowed' do def disable_protocol(protocol) settings = ::ApplicationSetting.create_from_defaults diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb new file mode 100644 index 00000000000..c77b746cc88 --- /dev/null +++ b/spec/lib/gitlab/user_access_spec.rb @@ -0,0 +1,90 @@ +require 'spec_helper' + +describe Gitlab::UserAccess, lib: true do + let(:access) { Gitlab::UserAccess.new(user, project: project) } + let(:project) { create(:project) } + let(:user) { create(:user) } + + describe 'can_push_to_branch?' do + describe 'push to none protected branch' do + it "returns true if user is a master" do + project.team << [user, :master] + expect(access.can_push_to_branch?("random_branch")).to be_truthy + end + + it "returns true if user is a developer" do + project.team << [user, :developer] + expect(access.can_push_to_branch?("random_branch")).to be_truthy + end + + it "returns false if user is a reporter" do + project.team << [user, :reporter] + expect(access.can_push_to_branch?("random_branch")).to be_falsey + end + end + + describe 'push to protected branch' do + before do + @branch = create :protected_branch, project: project + end + + it "returns true if user is a master" do + project.team << [user, :master] + expect(access.can_push_to_branch?(@branch.name)).to be_truthy + end + + it "returns false if user is a developer" do + project.team << [user, :developer] + expect(access.can_push_to_branch?(@branch.name)).to be_falsey + end + + it "returns false if user is a reporter" do + project.team << [user, :reporter] + expect(access.can_push_to_branch?(@branch.name)).to be_falsey + end + end + + describe 'push to protected branch if allowed for developers' do + before do + @branch = create :protected_branch, project: project, developers_can_push: true + end + + it "returns true if user is a master" do + project.team << [user, :master] + expect(access.can_push_to_branch?(@branch.name)).to be_truthy + end + + it "returns true if user is a developer" do + project.team << [user, :developer] + expect(access.can_push_to_branch?(@branch.name)).to be_truthy + end + + it "returns false if user is a reporter" do + project.team << [user, :reporter] + expect(access.can_push_to_branch?(@branch.name)).to be_falsey + end + end + + describe 'merge to protected branch if allowed for developers' do + before do + @branch = create :protected_branch, project: project, developers_can_merge: true + end + + it "returns true if user is a master" do + project.team << [user, :master] + expect(access.can_merge_to_branch?(@branch.name)).to be_truthy + end + + it "returns true if user is a developer" do + project.team << [user, :developer] + expect(access.can_merge_to_branch?(@branch.name)).to be_truthy + end + + it "returns false if user is a reporter" do + project.team << [user, :reporter] + expect(access.can_merge_to_branch?(@branch.name)).to be_falsey + end + end + + end +end diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/api_helpers_spec.rb index 83025953889..3d5c19aeff3 100644 --- a/spec/requests/api/api_helpers_spec.rb +++ b/spec/requests/api/api_helpers_spec.rb @@ -49,7 +49,7 @@ describe API::Helpers, api: true do it "should return nil for a user without access" do env[API::Helpers::PRIVATE_TOKEN_HEADER] = user.private_token - allow(Gitlab::UserAccess).to receive(:allowed?).and_return(false) + allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false) expect(current_user).to be_nil end @@ -73,7 +73,7 @@ describe API::Helpers, api: true do it "should return nil for a user without access" do env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token - allow(Gitlab::UserAccess).to receive(:allowed?).and_return(false) + allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false) expect(current_user).to be_nil end From 959d63ab1a5559f5f60ba7378a59e2d0fdb17c73 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Fri, 24 Jun 2016 11:13:02 +0530 Subject: [PATCH 185/335] Clean up `protected_branches.js.coffee` - Only send a param for the currently changed checkbox. - Have the controller use strong parameters correctly, so that the PATCH works as expected. --- app/assets/javascripts/protected_branches.js.coffee | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/protected_branches.js.coffee b/app/assets/javascripts/protected_branches.js.coffee index ce2fc883620..14afef2e2ee 100644 --- a/app/assets/javascripts/protected_branches.js.coffee +++ b/app/assets/javascripts/protected_branches.js.coffee @@ -1,21 +1,18 @@ $ -> $(".protected-branches-list :checkbox").change (e) -> name = $(this).attr("name") - row = $(this).parents("tr") if name == "developers_can_push" || name == "developers_can_merge" id = $(this).val() - can_push = row.find("input[name=developers_can_push]").is(":checked") - can_merge = row.find("input[name=developers_can_merge]").is(":checked") + can_push = $(this).is(":checked") url = $(this).data("url") $.ajax - type: "PUT" + type: "PATCH" url: url dataType: "json" data: id: id protected_branch: - developers_can_push: can_push - developers_can_merge: can_merge + "#{name}": can_push success: -> row = $(e.target) From af7e75162efe07e9fcb1186462e56bd2325018de Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Mon, 4 Jul 2016 11:06:32 +0530 Subject: [PATCH 186/335] Don't ask the user to "merge this request manually". 1. If they are a developer with "Developers can Merge" switched on. --- app/models/merge_request.rb | 5 +++++ .../projects/merge_requests/widget/open/_conflicts.html.haml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index e5853bdd589..471e32f3b60 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -556,6 +556,11 @@ class MergeRequest < ActiveRecord::Base access.can_push_to_branch?(target_branch) || access.can_merge_to_branch?(target_branch) end + def can_be_merged_via_command_line_by?(user) + access = ::Gitlab::UserAccess.new(user, project: project) + access.can_push_to_branch?(target_branch) + end + def mergeable_ci_state? return true unless project.only_allow_merge_if_build_succeeds? diff --git a/app/views/projects/merge_requests/widget/open/_conflicts.html.haml b/app/views/projects/merge_requests/widget/open/_conflicts.html.haml index 06ab0a3fa00..f000cc38a65 100644 --- a/app/views/projects/merge_requests/widget/open/_conflicts.html.haml +++ b/app/views/projects/merge_requests/widget/open/_conflicts.html.haml @@ -4,7 +4,7 @@ %p Please resolve these conflicts or - - if @merge_request.can_be_merged_by?(current_user) + - if @merge_request.can_be_merged_via_command_line_by?(current_user) #{link_to "merge this request manually", "#modal_merge_info", class: "how_to_merge_link vlink", "data-toggle" => "modal"}. - else ask someone with write access to this repository to merge this request manually. From dffdc7b27c1f89e4e26b4714834e4f147c656206 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Mon, 4 Jul 2016 11:07:37 +0530 Subject: [PATCH 187/335] Add "Developers can Merge" (to protected branches) to the CHANGELOG. --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index e144ba8513f..b0d86e4acad 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -43,6 +43,7 @@ v 8.10.0 (unreleased) - Add "Enabled Git access protocols" to Application Settings - Diffs will create button/diff form on demand no on server side - Reduce size of HTML used by diff comment forms + - Protected branches have a "Developers can Merge" setting. !4892 (original implementation by Mathias Vestergaard) - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - Only show New Snippet button to users that can create snippets. - PipelinesFinder uses git cache data @@ -497,7 +498,6 @@ v 8.7.7 - Prevent unauthorized access to other projects build traces - Forbid scripting for wiki files - Only show notes through JSON on confidential issues that the user has access to - - Added protected branch setting that allows Developers to accept merge requests while push is still disallowed. !4220 (Mathias Vestergaard) v 8.7.6 - Fix links on wiki pages for relative url setups. !4131 (Artem Sidorenko) From 4d00ed21ebbc9fd4a1f1b13cbed9a0a9ad2a2a9e Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Tue, 5 Jul 2016 08:55:46 +0530 Subject: [PATCH 188/335] Appease rubocop. --- lib/gitlab/git_access.rb | 1 - spec/lib/gitlab/git_access_spec.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index cfb48ac2382..9f5bb9d62cd 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -108,7 +108,6 @@ module Gitlab actor if actor.is_a?(DeployKey) end - def deploy_key_can_read_project? if deploy_key deploy_key.projects.include?(project) diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index 059d8a2c355..db33c7a22bb 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -128,7 +128,6 @@ describe Gitlab::GitAccess, lib: true do rugged = project.repository.rugged author = { email: "email@example.com", time: Time.now, name: "Example Git User" } - merge_index = rugged.merge_commits(target_branch, source_branch) Rugged::Commit.create(rugged, author: author, committer: author, message: "commit message", parents: [target_branch, source_branch], tree: merge_index.write_tree(rugged)) end From ea9e8f4609f46f9c5713a8346f91dc19d310c2e1 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Thu, 7 Jul 2016 11:36:01 +0530 Subject: [PATCH 189/335] Move all "checks" under `GitLab::Checks`. - https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4892#note_12892160 - This is more consistent. --- app/services/merge_requests/refresh_service.rb | 2 +- .../change_access.rb} | 8 +++----- lib/gitlab/checks/force_push.rb | 17 +++++++++++++++++ lib/gitlab/force_push_check.rb | 15 --------------- lib/gitlab/git_access.rb | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) rename lib/gitlab/{git_access/change_access_check.rb => checks/change_access.rb} (93%) create mode 100644 lib/gitlab/checks/force_push.rb delete mode 100644 lib/gitlab/force_push_check.rb diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb index b11ecd97a57..1daf6bbf553 100644 --- a/app/services/merge_requests/refresh_service.rb +++ b/app/services/merge_requests/refresh_service.rb @@ -48,7 +48,7 @@ module MergeRequests end def force_push? - Gitlab::ForcePushCheck.force_push?(@project, @oldrev, @newrev) + Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev) end # Refresh merge request diff if we push to source or target branch of merge request diff --git a/lib/gitlab/git_access/change_access_check.rb b/lib/gitlab/checks/change_access.rb similarity index 93% rename from lib/gitlab/git_access/change_access_check.rb rename to lib/gitlab/checks/change_access.rb index 9268da4ec6e..cb8f4f2cbdd 100644 --- a/lib/gitlab/git_access/change_access_check.rb +++ b/lib/gitlab/checks/change_access.rb @@ -1,6 +1,6 @@ module Gitlab - class GitAccess - class ChangeAccessCheck + module Checks + class ChangeAccess attr_reader :user_access, :project def initialize(change, user_access:, project:) @@ -25,8 +25,6 @@ module Gitlab def protected_branch_checks return unless project.protected_branch?(@branch_name) - return unless project.protected_branch?(@branch_name) - if forced_push? && user_access.cannot_do_action?(:force_push_code_to_protected_branches) return "You are not allowed to force push code to a protected branch on this project." elsif Gitlab::Git.blank_ref?(@newrev) && user_access.cannot_do_action?(:remove_protected_branches) @@ -67,7 +65,7 @@ module Gitlab end def forced_push? - Gitlab::ForcePushCheck.force_push?(@project, @oldrev, @newrev) + Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev) end def matching_merge_request? diff --git a/lib/gitlab/checks/force_push.rb b/lib/gitlab/checks/force_push.rb new file mode 100644 index 00000000000..dfa83a0eab3 --- /dev/null +++ b/lib/gitlab/checks/force_push.rb @@ -0,0 +1,17 @@ +module Gitlab + module Checks + class ForcePush + def self.force_push?(project, oldrev, newrev) + return false if project.empty_repo? + + # Created or deleted branch + if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev) + false + else + missed_refs, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev})) + missed_refs.split("\n").size > 0 + end + end + end + end +end diff --git a/lib/gitlab/force_push_check.rb b/lib/gitlab/force_push_check.rb deleted file mode 100644 index 93c6a5bb7f5..00000000000 --- a/lib/gitlab/force_push_check.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Gitlab - class ForcePushCheck - def self.force_push?(project, oldrev, newrev) - return false if project.empty_repo? - - # Created or deleted branch - if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev) - false - else - missed_refs, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev})) - missed_refs.split("\n").size > 0 - end - end - end -end diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index 9f5bb9d62cd..308f23bc9bc 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -91,7 +91,7 @@ module Gitlab end def change_access_check(change) - ChangeAccessCheck.new(change, user_access: user_access, project: project).exec + Checks::ChangeAccess.new(change, user_access: user_access, project: project).exec end def protocol_allowed? From c607b1c941fbfaca22dd78dae2fd67d873b56828 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 13 Jul 2016 10:40:03 +0200 Subject: [PATCH 190/335] fix more specs --- app/models/project.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index f85c6a65858..3306fb86282 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -465,7 +465,7 @@ class Project < ActiveRecord::Base import_url = Gitlab::UrlSanitizer.new(value) super(import_url.sanitized_url) - create_or_update_import_data(credentials: import_url.credentials) unless errors.messages[:import_url] + create_or_update_import_data(credentials: import_url.credentials) if valid_import_url? end def import_url @@ -477,6 +477,10 @@ class Project < ActiveRecord::Base end end + def valid_import_url? + valid? || errors.messages[:import_url].nil? + end + def create_or_update_import_data(data: nil, credentials: nil) project_import_data = import_data || build_import_data if data From bb81f2afc1d82d6e88d7039025c8a8be0794aac6 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Tue, 12 Jul 2016 10:47:36 +0530 Subject: [PATCH 191/335] Implement last round of review comments from !4892. 1. Fix typos, minor styling errors. 2. Use single quotes rather than double quotes in `user_access_spec`. 3. Test formatting. --- .../_branches_list.html.haml | 4 +- lib/gitlab/checks/change_access.rb | 6 ++- spec/lib/gitlab/user_access_spec.rb | 40 +++++++++---------- spec/services/git_push_service_spec.rb | 3 +- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/app/views/projects/protected_branches/_branches_list.html.haml b/app/views/projects/protected_branches/_branches_list.html.haml index 181d1a27c73..720d67dff7c 100644 --- a/app/views/projects/protected_branches/_branches_list.html.haml +++ b/app/views/projects/protected_branches/_branches_list.html.haml @@ -8,7 +8,7 @@ .table-responsive %table.table.protected-branches-list %colgroup - %col{ width: "27%" } + %col{ width: "20%" } %col{ width: "30%" } %col{ width: "25%" } %col{ width: "25%" } @@ -19,7 +19,7 @@ %th Protected Branch %th Commit %th Developers Can Push - %th Developers can Merge + %th Developers Can Merge - if can_admin_project %th %tbody diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb index cb8f4f2cbdd..5551fac4b8b 100644 --- a/lib/gitlab/checks/change_access.rb +++ b/lib/gitlab/checks/change_access.rb @@ -28,7 +28,7 @@ module Gitlab if forced_push? && user_access.cannot_do_action?(:force_push_code_to_protected_branches) return "You are not allowed to force push code to a protected branch on this project." elsif Gitlab::Git.blank_ref?(@newrev) && user_access.cannot_do_action?(:remove_protected_branches) - return "You are not allowed to deleted protected branches from this project." + return "You are not allowed to delete protected branches from this project." end if matching_merge_request? @@ -47,7 +47,9 @@ module Gitlab end def tag_checks - if (tag_ref = tag_name(@ref)) && protected_tag?(tag_ref) && user_access.cannot_do_action?(:admin_project) + tag_ref = tag_name(@ref) + + if tag_ref && protected_tag?(tag_ref) && user_access.cannot_do_action?(:admin_project) "You are not allowed to change existing tags on this project." end end diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb index c77b746cc88..aa9ec243498 100644 --- a/spec/lib/gitlab/user_access_spec.rb +++ b/spec/lib/gitlab/user_access_spec.rb @@ -7,40 +7,38 @@ describe Gitlab::UserAccess, lib: true do describe 'can_push_to_branch?' do describe 'push to none protected branch' do - it "returns true if user is a master" do + it 'returns true if user is a master' do project.team << [user, :master] - expect(access.can_push_to_branch?("random_branch")).to be_truthy + expect(access.can_push_to_branch?('random_branch')).to be_truthy end - it "returns true if user is a developer" do + it 'returns true if user is a developer' do project.team << [user, :developer] - expect(access.can_push_to_branch?("random_branch")).to be_truthy + expect(access.can_push_to_branch?('random_branch')).to be_truthy end - it "returns false if user is a reporter" do + it 'returns false if user is a reporter' do project.team << [user, :reporter] - expect(access.can_push_to_branch?("random_branch")).to be_falsey + expect(access.can_push_to_branch?('random_branch')).to be_falsey end end describe 'push to protected branch' do - before do - @branch = create :protected_branch, project: project - end + let(:branch) { create :protected_branch, project: project } - it "returns true if user is a master" do + it 'returns true if user is a master' do project.team << [user, :master] - expect(access.can_push_to_branch?(@branch.name)).to be_truthy + expect(access.can_push_to_branch?(branch.name)).to be_truthy end - it "returns false if user is a developer" do + it 'returns false if user is a developer' do project.team << [user, :developer] - expect(access.can_push_to_branch?(@branch.name)).to be_falsey + expect(access.can_push_to_branch?(branch.name)).to be_falsey end - it "returns false if user is a reporter" do + it 'returns false if user is a reporter' do project.team << [user, :reporter] - expect(access.can_push_to_branch?(@branch.name)).to be_falsey + expect(access.can_push_to_branch?(branch.name)).to be_falsey end end @@ -49,17 +47,17 @@ describe Gitlab::UserAccess, lib: true do @branch = create :protected_branch, project: project, developers_can_push: true end - it "returns true if user is a master" do + it 'returns true if user is a master' do project.team << [user, :master] expect(access.can_push_to_branch?(@branch.name)).to be_truthy end - it "returns true if user is a developer" do + it 'returns true if user is a developer' do project.team << [user, :developer] expect(access.can_push_to_branch?(@branch.name)).to be_truthy end - it "returns false if user is a reporter" do + it 'returns false if user is a reporter' do project.team << [user, :reporter] expect(access.can_push_to_branch?(@branch.name)).to be_falsey end @@ -70,17 +68,17 @@ describe Gitlab::UserAccess, lib: true do @branch = create :protected_branch, project: project, developers_can_merge: true end - it "returns true if user is a master" do + it 'returns true if user is a master' do project.team << [user, :master] expect(access.can_merge_to_branch?(@branch.name)).to be_truthy end - it "returns true if user is a developer" do + it 'returns true if user is a developer' do project.team << [user, :developer] expect(access.can_merge_to_branch?(@branch.name)).to be_truthy end - it "returns false if user is a reporter" do + it 'returns false if user is a reporter' do project.team << [user, :reporter] expect(access.can_merge_to_branch?(@branch.name)).to be_falsey end diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index 0f30a84a2cf..47c0580e0f0 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -243,7 +243,8 @@ describe GitPushService, services: true do expect(project).to receive(:execute_hooks) expect(project.default_branch).to eq("master") expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: true, developers_can_merge: false }) - execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) + + execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master') end it "when pushing a branch for the first time with default branch protection set to 'developers can merge'" do From da47f20a025b27485a0b294ec92571aafe8438e5 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 13 Jul 2016 11:03:06 +0200 Subject: [PATCH 192/335] Fix Knapsack report generation for Spinach --- features/support/env.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/support/env.rb b/features/support/env.rb index ab3f0ca7aeb..f0a3dd8d2d0 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -13,7 +13,7 @@ require_relative 'rerun' if ENV['CI'] require 'knapsack' - Knapsack::Adapters::RSpecAdapter.bind + Knapsack::Adapters::SpinachAdapter.bind end %w(select2_helper test_env repo_helpers).each do |f| From cc752f241ccef3b13486544f03ae716de00cc363 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Wed, 13 Jul 2016 09:23:55 +0200 Subject: [PATCH 193/335] ObjectRenderer doesn't crash when no objects to cache with Rails.cache.read_multi --- lib/banzai/renderer.rb | 14 ++++++++++---- spec/lib/banzai/object_renderer_spec.rb | 11 +++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb index ea10b06439b..910687a7b6a 100644 --- a/lib/banzai/renderer.rb +++ b/lib/banzai/renderer.rb @@ -61,10 +61,16 @@ module Banzai end cacheable_items, non_cacheable_items = items_collection.partition { |item| item.key?(:cache_key) } - items_in_cache = Rails.cache.read_multi(*cacheable_items.map { |item| item[:cache_key] }) - items_not_in_cache = cacheable_items.reject do |item| - item[:rendered] = items_in_cache[item[:cache_key]] - items_in_cache.key?(item[:cache_key]) + + items_in_cache = [] + items_not_in_cache = [] + + unless cacheable_items.empty? + items_in_cache = Rails.cache.read_multi(*cacheable_items.map { |item| item[:cache_key] }) + items_not_in_cache = cacheable_items.reject do |item| + item[:rendered] = items_in_cache[item[:cache_key]] + items_in_cache.key?(item[:cache_key]) + end end (items_not_in_cache + non_cacheable_items).each do |item| diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb index cf6cdd33ebb..bcdb95250ca 100644 --- a/spec/lib/banzai/object_renderer_spec.rb +++ b/spec/lib/banzai/object_renderer_spec.rb @@ -109,6 +109,17 @@ describe Banzai::ObjectRenderer do expect(docs[1]).to be_an_instance_of(Nokogiri::HTML::DocumentFragment) expect(docs[1].to_html).to eq('

    bye

    ') end + + it 'returns when no objects to render' do + objects = [] + renderer = described_class.new(project, user, pipeline: :note) + + expect(Banzai).to receive(:cache_collection_render). + with([]). + and_call_original + + expect(renderer.render_attributes(objects, :note)).to eq([]) + end end describe '#base_context' do From 02e38466726730edd212411214a92319fe31df60 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Wed, 13 Jul 2016 10:30:13 +0100 Subject: [PATCH 194/335] deletes swn file --- lib/api/.projects.rb.swn | Bin 28672 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lib/api/.projects.rb.swn diff --git a/lib/api/.projects.rb.swn b/lib/api/.projects.rb.swn deleted file mode 100644 index 6a9e5f146eafe1548d561955a5915b48388486e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28672 zcmeI54~!hwS-_XL0a`b8nkb0M(7d}NxjTH`Gl?N(Q_Fwii)+Pp4%-)}b+60Z?%dt< z_FraZZC_lcpvXvs3N;m!P)dPD{HYrtftDCmv=DGoXrUx26(B`G)q;d6g@O}Agy8qy zyf^b^c6PnzI!0}0rJr~2&G+7$`QD#--}k;5FKoGI?|yMxd25N!wWU&f3Gu}zx__P76xU1A-{qmwa`GJfqV^g!^O>Sx~6pN zEkCeD3XF}8i0iML%a<)u3k?(+C^S%LpwK{}fkFd?1_})n8u+HvK-jsu^lq-~Dt&eD z)ZgEh`F@rD`-uKt$sE60|GlWcpUNEncKvrpe^2NNOg*?8)aQHk_am9(I=T2NG*D=u z&_JPqLIZ^c3Jnw*C^S%LpwK{}fkFd?1};GZPQ6sRj(lH`_BQ+f#{R#sp;Y=3JPjX# z-+&g(!zQ>2KJ~g%>1W_h_^)e9rIXNvdH50719!spupYkl+EVFn;m_d_@L(5=!*lCP zrE}oJBD@`r!U((pO7O+kluDn44?+{}gbS}OmCnOI!|%Wuco^=3x569YtKV5FeHwli zehMCf1$Z0mgqz^?@bBMIDm@DyhLiC9AmB#03jP}>#y`SY_$7D{I6ha;EnJy4wQd@$KU}7A%J^f7Tyf&;V*E6oPh`6ZSW?z4!($k=J((@Y=ReQFWF|# zX+Me8^um0`_~A7>Z9lAb{f3xmcS5h-avGDRNJ1Vz<^|q@*YLvCYC}d}SW;rM*di8I zMcrL=x{c7v)afoXyjoh+TNI(+bw%JbUEu^GaKq4RE%jEgP294@DyxNj&~a*R)vKpV z)b$1;Y>RH-`XUy!vIonK@7Ak+x7Bj}pz5}qg@$VvWXaartKE9z*ZPciQ`_lToE&^&#}ibCv}IV|GnqUl5|7MVHWG&>Df9E{p0zD&UYqqEtXI=t+P zy}LzwQ8;T-)E>@IUzpUhBLYSbRqCr^CQ=_;Yf(z}U!{wh)2cf4rq?oBsR)v`Pt>}; zk5;NuXi8L4B2y_fnn@yQ99zk~O*9(?XC0yCcGhZcKr6}&)N5B+iq6(F$Hm$~i;syb z)BwY1-SpKRx@B^@>rlGT*Cs?#9XmOufcFLZ5vF)(n+huNtCM3r|dKuadA#J zT&5>@HO5c9>I6}D8PUgO1C383KR#%rB<1yQAzk2@kR6;1!l+HCZZ7+%>L_^~e0WvI zmt|jeJUzsTxngTnrrn>*$2|AAyyH}Z&|zfN<0eVzQ6C(rODz+tt6z_g1<)sV*{E8h zRHakeRis+?GU#{ku+CNM70`bBc&nev)uDk3R}!%{hf%k1T0-SA>JCJMWkl4G?cvl{ z;py3X`0hQV`rSt0#%+;I+;R8sowav4fmhSh!)}+=Q6qQWjtga#*O7Po;AkaaY1we+ z<3n*Ruh=w}8hNsZw|(#a{0`9n_P)jzzf4W-grOhAsuCjI5rk03k5;m)@p*JPp;p@~ zV%s*gz@8M_MHDq%soWDU-uJO|XjCe*bG!EKy+c$6NF3aI&(6a$)~N_F#zlI^B@Um)$OKs|)RR14*ru0n;R)h-FDYU zK^1c+oDzBgDFfewia5!lvLdFBzT@rF^P8r{DVbB9=7P&T)8)85y^n}f9IQ2*ATT%j zK)hM(@tuxasqCEH%h9pqh)ig<>s^+X@~5=_pT&-Lq>YXJZ}#7x!M?A<7qIO=1iuJA z+zS7OE&nSZZTp+xb#M(liyi+AJPp4IzY6bx6HtZkfxo1l--c5VzzVn^>;F+GK7|Gf z4HOzEG*D=u&_JPqLIZ^czM(Y`S$f9aGv8?oFm?n;k7{KCLEwOJvpLt3EHMPVzR#{keYFN#3hs_DcrA6I}GnU(a-SsC%vtnZGWWYAfsZpcB zoT6)LX9d@7zd{p%VTzMGJblhiZT<{#Mqa&70ql|VW;g9YC$2eCnNc?!RVt}2td7nn z?ID$+I=gl~@h7g4ZDL&RUyb7t(LX9;+#w-u533H{#=85C(t&Yxh>7i!;_idJo0QR^ zNwM?5ZZV;*f8XA_W~BJ!=oIETgEVXOlQeqM*hw?O*vRu&=TF^aHDONetOFyRf|4n@V3)ueW;4%0Rtipa6 zfq%sZa2D=|-Eb}ZHTM7e;a>PYcoAFwlOXN?BQOHbW8a^J2VoR$fWO1{@N4i0tUwj! z;4rL%m)XDnCwLNm0`|fNIL}Fc3Vs1r;Sh|$OYGBs6i$N+yFl*auY)hMPk#m>Q`|wY|gK!tT0lvf@{BOZB?1%4$C)tNT1E=6VSb{~k4W?ludtK(yAx2mr1xBZcLXDgWqGfr-! zz~o!qmM(1rbcdcWlG=K`=zVV=Q(C{u7imf=2hK6KzCAu<(ix?=YxN5)DwSxP{16^i zujZE7WS@{%F%|iRC(G^$w}#s^E=BnlDPk>d$V5T8zqFgP8U-sPGfJ+oNvtH{CCSyB zgSp>5F79FTMc&q7rSro=hR&S{{1`T$9SSmRo^)`?u(|TXMTX6t4j>semyXA&F8EHX zwmf{UIKm{!V*0QARvQ9AmC38R;;shbXhq&{6InSB=<0KPl^4BMJzm4AaqiXUlfi1c z#e4U()l@nvb4^!t-c0;KWlT9&fU&cm47F=r}8;DxK{W2)z=K5jH3YN%rEn4QJOB zsuk^Qi=gAyyhV?&I$2g(h`U>jRpA_Cw^+tL$jv+zNEBIQm-lX;Hk1XQ%)+3o{$@YA z;WfRG2s)>>?AGU}#MUjhCNo3&o}8bh*YN!oS!&qkLb2qKeN27yiYU1gnFG1s>aJx1 zS%=M&Klu)uyZ>}NYzf&2*J1O0voCaVmMpoAZW1dUC$v^XYgyiy*irmAW-T9oE~voG zAfEyFGx#7>;da;n=du0&6dr{D_Q1>7{vU_;!Tsf)^a^gXIZ4|p2l!@ykKC_gnq=P`0Duw0;l$3sQ zBt9*(s`-C+I`*hBK1HL!-0wB6=Zm#@t`?KT$~U+ZGP#nRUzfb1?{wL($=RyO-k(cR zr9JDMIGq_*J!Yvr@|G*f63Gq)OA0?#a#TbQcji8oW-3bOWxBYe=Q;C-ja9aF_Wcdm zeEF=onlEJ=r}+|TpL@Pce&^1YP5aaHWxg)2pfoS7Vrg2H(x*Aqes%J+FVZTdk95{| zDC6}>%atDFK8$XY@);TT1W(1tXMgpQ+1w%R`=k9k8VR}os+;|#ty?lXs>vE6S-NCI z*1me7126IwX(Kk}OWOW7@8|np?0xwRz$f4dcpQEn9)?qJH~bJ>2QOj!e;R%cR^bHf0Qs!I zM%VyX!>iyc_yfKS&%&ed5Uju)$hZOdZh$|Ar{H1uN$A36cmdzQpMdlkc(50)h8OS; zoPitRT6iA+z&SVz@?8L@;UwG-v+x$!3jcz?;CXl)tQ{74Ijei;Nx%__QO879{vEof$=Lyf5Jf!upXYnPjC)ojKOheg7hcc0|%f2 zuZGX#BRC7vhfsqB*aTy+0X~Co;4~bD+u;U~Z7JUmFyIsQC>fVEIvs_EO;=RJN@hna z{bY1XvJ{oka|5#tb%L*WkUW0x05g$#8c3$HY2dqfym)XaE{TyTBg%R*wYtp(HUXKE z^o*k32|)I)Pb?KjWEQIwbtUP?vUl>Rq%Y?rbI(!XKk96vO?Wj&#$^ne=pro$27Gcl z_J9=2y#ByZ&p>mPd6Qq-x{zL*z5~>RMOAo8)t%3d^=L~|S^FJXOps|lnW>Ui#9^j) znJgP%fhXrxKG(R7)GH$h?d$VMyQQz8R5hnc7mlhiPZR0efHnsCzdlU(N5gBan7MSZ z+h|nHgvwU1AB1w3=ZBNIHDg;E_l+#1@7%t}Z+AQUkkA*Tc8XNBGIAqMR4GeRmT*4# zcspCtCe+JLHa=UyqoJI7bcow&R+@e5RM`lm3|rmNt5E^6tU!i^7#(J}#q?O{Rp6*> zZ(W#>Ycn|pRkk^?yEgs-*ALlm5LvL!KSCvIY zCutereSF$R8N7HP`Wb05QG{*F4tOG$1eiG$L!k+Aw_1$Lsm@5N5R`OjHy42|T z%jmToQaIhfyJz;z9G=O%wnK{P-2EFE&B^HHRC^}PVNG$&k8-p$9l5fT@3dhavnv>+ z`-AEtbq)s1qTg=(VoEbp zUb=)huFjfKM|Byzi-EoJ`l`Alx2^`iHI;H=>4(WPogxY@R*jgfdR5<;kUEN{2;EtE zvri^i+^bLNdX-{KH&B8)yHuD-FB3~%Qrc4gu!PR(Y^jpUEw7REK0TA=m7J2x5nx`H zK}Y6H;@~4&bj>kH@`f!7n69LYN%!zf+t? zhxE-W2S!9iPh$GqavizW{FQ0gytyk@ZofBC2&wgcv)0<)HKZpeee!u4OwS|vTY;Gg z!mPIJq1kuUW$NUj(qsAS-Na;Wup6{IaDP&_kaXAO?NH`5lajlVZ8g`DmtY2g(VN{q M_V2{EF=R9RAD`a$@c;k- From c826b7c3e52caee88de3e2320bb9f3b095b29f64 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 13 Jul 2016 11:58:58 +0100 Subject: [PATCH 195/335] Fixed Rubocop --- app/helpers/projects_helper.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index e64aa56d5e4..df5090327af 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -34,8 +34,7 @@ module ProjectsHelper author_html << content_tag(:span, sanitize("@#{author.username}"), class: opts[:author_class]) if opts[:name] else tooltip_data = { placement: 'top' } - author_html << content_tag(:span, sanitize(author.name), class: [opts[:author_class], ('has-tooltip' if opts[:tooltip])], - title: (author.to_reference if opts[:tooltip]), data: (tooltip_data if opts[:tooltip])) if opts[:name] + author_html << content_tag(:span, sanitize(author.name), class: [opts[:author_class], ('has-tooltip' if opts[:tooltip])], title: (author.to_reference if opts[:tooltip]), data: (tooltip_data if opts[:tooltip])) if opts[:name] end author_html << capture(&block) if block From dd63955032aeebfa76b774b008820879e7d37353 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 13 Jul 2016 13:57:43 +0200 Subject: [PATCH 196/335] updated create_or_update_import_data to use guard clause --- app/models/project.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index 72c4f591420..7dc9f396e9e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -465,7 +465,7 @@ class Project < ActiveRecord::Base import_url = Gitlab::UrlSanitizer.new(value) super(import_url.sanitized_url) - create_or_update_import_data(credentials: import_url.credentials) if valid_import_url? + create_or_update_import_data(credentials: import_url.credentials) end def import_url @@ -482,6 +482,8 @@ class Project < ActiveRecord::Base end def create_or_update_import_data(data: nil, credentials: nil) + return unless valid_import_url? + project_import_data = import_data || build_import_data if data project_import_data.data ||= {} From 0d4b1bb752c65946c89b4240602e91b06c3fad36 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 13 Jul 2016 06:41:06 -0700 Subject: [PATCH 197/335] Refresh branch cache after `git gc` Possible workaround for #15392 --- CHANGELOG | 2 +- app/workers/git_garbage_collect_worker.rb | 4 +++- spec/workers/git_garbage_collect_worker_spec.rb | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a50edf1a797..fa6044bd87c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,7 +4,7 @@ v 8.10.0 (unreleased) - Expose {should,force}_remove_source_branch (Ben Boeckel) - Fix commit builds API, return all builds for all pipelines for given commit. !4849 - Replace Haml with Hamlit to make view rendering faster. !3666 - - Expire the branch cache after `git gc` runs + - Refresh the branch cache after `git gc` runs - Refactor repository paths handling to allow multiple git mount points - Optimize system note visibility checking by memoizing the visible reference count !5070 - Add Application Setting to configure default Repository Path for new projects diff --git a/app/workers/git_garbage_collect_worker.rb b/app/workers/git_garbage_collect_worker.rb index 2fa3c838f55..a6cefd4d601 100644 --- a/app/workers/git_garbage_collect_worker.rb +++ b/app/workers/git_garbage_collect_worker.rb @@ -8,7 +8,9 @@ class GitGarbageCollectWorker project = Project.find(project_id) gitlab_shell.gc(project.repository_storage_path, project.path_with_namespace) - # Expire the branch cache in case garbage collection caused a ref lookup to fail + # Refresh the branch cache in case garbage collection caused a ref lookup to fail project.repository.after_create_branch + project.repository.branch_names + project.repository.has_visible_content? end end diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb index a9cce8b8b59..c9f5aae0815 100644 --- a/spec/workers/git_garbage_collect_worker_spec.rb +++ b/spec/workers/git_garbage_collect_worker_spec.rb @@ -16,7 +16,10 @@ describe GitGarbageCollectWorker do project.repository_storage_path, project.path_with_namespace). and_return(true) - expect_any_instance_of(Repository).to receive(:after_create_branch) + expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original + expect_any_instance_of(Repository).to receive(:branch_names).and_call_original + expect_any_instance_of(Repository).to receive(:branch_count).and_call_original + expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original subject.perform(project.id) end From a14ee9bef9050e9d4c4de63eec80e9ff33c7e039 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 11 Jul 2016 17:31:45 -0300 Subject: [PATCH 198/335] Keeps issue number when importing from Gitlab.com MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With these changes we don’t lost the issue references when importing from `GitLab.com`. --- lib/gitlab/gitlab_import/importer.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/gitlab/gitlab_import/importer.rb b/lib/gitlab/gitlab_import/importer.rb index 3f76ec97977..e6d31ea04c0 100644 --- a/lib/gitlab/gitlab_import/importer.rb +++ b/lib/gitlab/gitlab_import/importer.rb @@ -35,6 +35,7 @@ module Gitlab end project.issues.create!( + iid: issue["iid"], description: body, title: issue["title"], state: issue["state"], From d9564ed73369e35b5623ead35de5e7a8cda3f7ec Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 11 Jul 2016 18:32:42 -0300 Subject: [PATCH 199/335] Add spec for GitLab.com importer --- .../lib/gitlab/gitlab_import/importer_spec.rb | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 spec/lib/gitlab/gitlab_import/importer_spec.rb diff --git a/spec/lib/gitlab/gitlab_import/importer_spec.rb b/spec/lib/gitlab/gitlab_import/importer_spec.rb new file mode 100644 index 00000000000..5fa81b9716a --- /dev/null +++ b/spec/lib/gitlab/gitlab_import/importer_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +describe Gitlab::GitlabImport::Importer, lib: true do + describe '#execute' do + it 'persists issues' do + stub_request('issues', [ + { + 'id' => 2579857, + 'iid' => 3, + 'title' => 'Issue', + 'description' => 'Lorem ipsum', + 'state' => 'opened', + 'author' => { + 'id' => 283999, + 'name' => 'John Doe' + } + } + ]) + stub_request('issues/2579857/notes', []) + + project = create(:empty_project, import_source: 'asd/vim') + project.build_import_data(credentials: { password: 'password' }) + + subject = described_class.new(project) + subject.execute + + expected_attributes = { + iid: 3, + title: 'Issue', + description: "*Created by: John Doe*\n\nLorem ipsum", + state: 'opened', + author_id: project.creator_id + } + + expect(project.issues.first).to have_attributes(expected_attributes) + end + + def stub_request(path, body) + url = "https://gitlab.com/api/v3/projects/asd%2Fvim/#{path}?page=1&per_page=100" + + WebMock.stub_request(:get, url). + to_return( + headers: { 'Content-Type' => 'application/json' }, + body: body + ) + end + end +end From 780188296ad850b11f43ef7e25e067be219cbb39 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 11 Jul 2016 17:33:01 -0300 Subject: [PATCH 200/335] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index b0d86e4acad..23f2cd1d1c8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -95,6 +95,7 @@ v 8.9.6 - Fix commit avatar alignment in compare view. !5128 - Fix broken migration in MySQL. !5005 - Overwrite Host and X-Forwarded-Host headers in NGINX !5213 + - Keeps issue number when importing from Gitlab.com v 8.9.6 (unreleased) - Fix importing of events under notes for GitLab projects From 6d5fd7d9b71b975be937671f2ca4dd7b3b57f8b2 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 11 Jul 2016 19:03:06 -0300 Subject: [PATCH 201/335] Stub omniauth provider for GitLab --- spec/lib/gitlab/gitlab_import/importer_spec.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spec/lib/gitlab/gitlab_import/importer_spec.rb b/spec/lib/gitlab/gitlab_import/importer_spec.rb index 5fa81b9716a..d3f1deb3837 100644 --- a/spec/lib/gitlab/gitlab_import/importer_spec.rb +++ b/spec/lib/gitlab/gitlab_import/importer_spec.rb @@ -1,8 +1,11 @@ require 'spec_helper' describe Gitlab::GitlabImport::Importer, lib: true do + include ImportSpecHelper + describe '#execute' do - it 'persists issues' do + before do + stub_omniauth_provider('gitlab') stub_request('issues', [ { 'id' => 2579857, @@ -17,7 +20,9 @@ describe Gitlab::GitlabImport::Importer, lib: true do } ]) stub_request('issues/2579857/notes', []) + end + it 'persists issues' do project = create(:empty_project, import_source: 'asd/vim') project.build_import_data(credentials: { password: 'password' }) From c88075f46772d3c462969372fafbd7f3886872b8 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 12 Jul 2016 18:33:37 -0300 Subject: [PATCH 202/335] Fix markdown rendering for consecutive label references --- app/models/label.rb | 2 +- .../filter/label_reference_filter_spec.rb | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/app/models/label.rb b/app/models/label.rb index dc5586f5756..60c0fff44ce 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -59,7 +59,7 @@ class Label < ActiveRecord::Base (?\d+) | # Integer-based label ID, or (? [A-Za-z0-9_\-\?&]+ | # String-based single-word label title, or - "[^,]+" # String-based multi-word label surrounded in quotes + "([^"]*)" # String-based multi-word label surrounded in quotes ) ) }x diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb index 9e3d2f5825d..b16470718a0 100644 --- a/spec/lib/banzai/filter/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb @@ -178,6 +178,46 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do end end + describe 'consecutive references' do + let(:bug) { create(:label, name: 'bug', project: project) } + let(:feature_proposal) { create(:label, name: 'feature proposal', project: project) } + let(:technical_debt) { create(:label, name: 'technical debt', project: project) } + + let(:bug_reference) { "#{Label.reference_prefix}#{bug.name}" } + let(:feature_proposal_reference) { feature_proposal.to_reference(format: :name) } + let(:technical_debt_reference) { technical_debt.to_reference(format: :name) } + + context 'separated with a comma' do + let(:references) { "#{bug_reference}, #{feature_proposal_reference}, #{technical_debt_reference}" } + + it 'links to valid references' do + doc = reference_filter("See #{references}") + + expect(doc.css('a').map { |a| a.attr('href') }).to match_array([ + urls.namespace_project_issues_url(project.namespace, project, label_name: bug.name), + urls.namespace_project_issues_url(project.namespace, project, label_name: feature_proposal.name), + urls.namespace_project_issues_url(project.namespace, project, label_name: technical_debt.name) + ]) + expect(doc.text).to eq 'See bug, feature proposal, technical debt' + end + end + + context 'separated with a space' do + let(:references) { "#{bug_reference} #{feature_proposal_reference} #{technical_debt_reference}" } + + it 'links to valid references' do + doc = reference_filter("See #{references}") + + expect(doc.css('a').map { |a| a.attr('href') }).to match_array([ + urls.namespace_project_issues_url(project.namespace, project, label_name: bug.name), + urls.namespace_project_issues_url(project.namespace, project, label_name: feature_proposal.name), + urls.namespace_project_issues_url(project.namespace, project, label_name: technical_debt.name) + ]) + expect(doc.text).to eq 'See bug feature proposal technical debt' + end + end + end + describe 'edge cases' do it 'gracefully handles non-references matching the pattern' do exp = act = '(format nil "~0f" 3.0) ; 3.0' From f682c0975b3a589d9fc6dae585cf6e36fa9ac348 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 12 Jul 2016 21:33:25 -0300 Subject: [PATCH 203/335] Fix markdown rendering for label references that begin with a digit --- app/models/label.rb | 5 +- .../filter/label_reference_filter_spec.rb | 48 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/app/models/label.rb b/app/models/label.rb index 60c0fff44ce..9b8239d8757 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -52,11 +52,14 @@ class Label < ActiveRecord::Base # This pattern supports cross-project references. # def self.reference_pattern + # NOTE: The id pattern only matches when all characters on the expression + # are digits, so it will match ~2 but not ~2fa because that's probably a + # label name and we want it to be matched as such. @reference_pattern ||= %r{ (#{Project.reference_pattern})? #{Regexp.escape(reference_prefix)} (?: - (?\d+) | # Integer-based label ID, or + (?\d+(?!\S\w)\b) | # Integer-based label ID, or (? [A-Za-z0-9_\-\?&]+ | # String-based single-word label title, or "([^"]*)" # String-based multi-word label surrounded in quotes diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb index b16470718a0..763b8dbc46a 100644 --- a/spec/lib/banzai/filter/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb @@ -104,6 +104,30 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do end end + context 'String-based single-word references that begin with a digit' do + let(:label) { create(:label, name: '2fa', project: project) } + let(:reference) { "#{Label.reference_prefix}#{label.name}" } + + it 'links to a valid reference' do + doc = reference_filter("See #{reference}") + + expect(doc.css('a').first.attr('href')).to eq urls. + namespace_project_issues_url(project.namespace, project, label_name: label.name) + expect(doc.text).to eq 'See 2fa' + end + + it 'links with adjacent text' do + doc = reference_filter("Label (#{reference}.)") + expect(doc.to_html).to match(%r(\(#{label.name}\.\))) + end + + it 'ignores invalid label names' do + exp = act = "Label #{Label.reference_prefix}#{label.id}#{label.name.reverse}" + + expect(reference_filter(act).to_html).to eq exp + end + end + context 'String-based single-word references with special characters' do let(:label) { create(:label, name: '?gfm&', project: project) } let(:reference) { "#{Label.reference_prefix}#{label.name}" } @@ -153,6 +177,30 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do end end + context 'String-based multi-word references that begin with a digit' do + let(:label) { create(:label, name: '2 factor authentication', project: project) } + let(:reference) { label.to_reference(format: :name) } + + it 'links to a valid reference' do + doc = reference_filter("See #{reference}") + + expect(doc.css('a').first.attr('href')).to eq urls. + namespace_project_issues_url(project.namespace, project, label_name: label.name) + expect(doc.text).to eq 'See 2 factor authentication' + end + + it 'links with adjacent text' do + doc = reference_filter("Label (#{reference}.)") + expect(doc.to_html).to match(%r(\(#{label.name}\.\))) + end + + it 'ignores invalid label names' do + exp = act = "Label #{Label.reference_prefix}#{label.id}#{label.name.reverse}" + + expect(reference_filter(act).to_html).to eq exp + end + end + context 'String-based multi-word references with special characters in quotes' do let(:label) { create(:label, name: 'gfm & references?', project: project) } let(:reference) { label.to_reference(format: :name) } From 1167ef4089645e8c043cf9009ff384829421acd7 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 12 Jul 2016 21:48:31 -0300 Subject: [PATCH 204/335] Fix markdown rendering for label references that contains `.` --- app/models/label.rb | 4 +-- .../filter/label_reference_filter_spec.rb | 26 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/models/label.rb b/app/models/label.rb index 9b8239d8757..df38d763c96 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -61,8 +61,8 @@ class Label < ActiveRecord::Base (?: (?\d+(?!\S\w)\b) | # Integer-based label ID, or (? - [A-Za-z0-9_\-\?&]+ | # String-based single-word label title, or - "([^"]*)" # String-based multi-word label surrounded in quotes + [A-Za-z0-9_\-\?\.&]+ | # String-based single-word label title, or + "([^"]*)" # String-based multi-word label surrounded in quotes ) ) }x diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb index 763b8dbc46a..9276a154007 100644 --- a/spec/lib/banzai/filter/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb @@ -93,8 +93,8 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do end it 'links with adjacent text' do - doc = reference_filter("Label (#{reference}.)") - expect(doc.to_html).to match(%r(\(#{label.name}\.\))) + doc = reference_filter("Label (#{reference}).") + expect(doc.to_html).to match(%r(\(#{label.name}\)\.)) end it 'ignores invalid label names' do @@ -117,8 +117,8 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do end it 'links with adjacent text' do - doc = reference_filter("Label (#{reference}.)") - expect(doc.to_html).to match(%r(\(#{label.name}\.\))) + doc = reference_filter("Label (#{reference}).") + expect(doc.to_html).to match(%r(\(#{label.name}\)\.)) end it 'ignores invalid label names' do @@ -129,7 +129,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do end context 'String-based single-word references with special characters' do - let(:label) { create(:label, name: '?gfm&', project: project) } + let(:label) { create(:label, name: '?g.fm&', project: project) } let(:reference) { "#{Label.reference_prefix}#{label.name}" } it 'links to a valid reference' do @@ -137,17 +137,17 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do expect(doc.css('a').first.attr('href')).to eq urls. namespace_project_issues_url(project.namespace, project, label_name: label.name) - expect(doc.text).to eq 'See ?gfm&' + expect(doc.text).to eq 'See ?g.fm&' end it 'links with adjacent text' do - doc = reference_filter("Label (#{reference}.)") - expect(doc.to_html).to match(%r(\(\?gfm&\.\))) + doc = reference_filter("Label (#{reference}).") + expect(doc.to_html).to match(%r(\(\?g\.fm&\)\.)) end it 'ignores invalid label names' do act = "Label #{Label.reference_prefix}#{label.name.reverse}" - exp = "Label #{Label.reference_prefix}&mfg?" + exp = "Label #{Label.reference_prefix}&mf.g?" expect(reference_filter(act).to_html).to eq exp end @@ -202,7 +202,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do end context 'String-based multi-word references with special characters in quotes' do - let(:label) { create(:label, name: 'gfm & references?', project: project) } + let(:label) { create(:label, name: 'g.fm & references?', project: project) } let(:reference) { label.to_reference(format: :name) } it 'links to a valid reference' do @@ -210,17 +210,17 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do expect(doc.css('a').first.attr('href')).to eq urls. namespace_project_issues_url(project.namespace, project, label_name: label.name) - expect(doc.text).to eq 'See gfm & references?' + expect(doc.text).to eq 'See g.fm & references?' end it 'links with adjacent text' do doc = reference_filter("Label (#{reference}.)") - expect(doc.to_html).to match(%r(\(gfm & references\?\.\))) + expect(doc.to_html).to match(%r(\(g\.fm & references\?\.\))) end it 'ignores invalid label names' do act = %(Label #{Label.reference_prefix}"#{label.name.reverse}") - exp = %(Label #{Label.reference_prefix}"?secnerefer & mfg\") + exp = %(Label #{Label.reference_prefix}"?secnerefer & mf.g\") expect(reference_filter(act).to_html).to eq exp end From 677bc4438c84129d059a8c1d1e38d953f5c840ce Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 13 Jul 2016 11:48:21 -0300 Subject: [PATCH 205/335] Doesn't match empty label references surrounded in quotes --- app/models/label.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/label.rb b/app/models/label.rb index df38d763c96..1199793456d 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -62,7 +62,7 @@ class Label < ActiveRecord::Base (?\d+(?!\S\w)\b) | # Integer-based label ID, or (? [A-Za-z0-9_\-\?\.&]+ | # String-based single-word label title, or - "([^"]*)" # String-based multi-word label surrounded in quotes + "([^"]+)" # String-based multi-word label surrounded in quotes ) ) }x From 28f0ffe38717167d4cae2407eda2755b78c14357 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 12 Jul 2016 21:52:25 -0300 Subject: [PATCH 206/335] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index b0d86e4acad..e26721d901c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -88,6 +88,7 @@ v 8.10.0 (unreleased) - Optimistic locking for Issues and Merge Requests (Title and description overriding prevention) - Redesign Builds and Pipelines pages - Change status color and icon for running builds + - Fix markdown rendering for: consecutive labels references, label references that begin with a digit or contains `.` v 8.9.6 - Fix importing of events under notes for GitLab projects. !5154 From 228073986bfb900ef324379639e1c5cce6b74fe6 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Wed, 13 Jul 2016 15:55:22 +0100 Subject: [PATCH 207/335] formats my test properly --- spec/requests/api/projects_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 4ddab08ef14..152cd802839 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -82,10 +82,11 @@ describe API::API, api: true do end context 'GET /projects?simple=true' do - it 'should return a simplified version of all the projects' do + it 'returns a simplified version of all the projects' do expected_keys = ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace"] get api('/projects?simple=true', user) + expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.first.keys).to match_array expected_keys From e2d6521d97289a6e3fbccf6948fe44dcb587a8d4 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 13 Jul 2016 17:01:24 +0200 Subject: [PATCH 208/335] some JS magic to fix empty URL bug --- app/views/projects/new.html.haml | 10 +++++++++- app/views/shared/_import_form.html.haml | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 9b00bdedc27..37f559c1bed 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -154,4 +154,12 @@ $('.import_gitlab_project').attr('disabled',true); $('.import_gitlab_project').attr('title', 'Project path required.'); } - }) + }); + + $('.import_git').click(function( event ) { + if($('#project_import_url').attr('disabled')) { + $('#project_import_url').attr('disabled', false); + } else { + $('#project_import_url').attr('disabled', true); + } + }); \ No newline at end of file diff --git a/app/views/shared/_import_form.html.haml b/app/views/shared/_import_form.html.haml index 627814bcfae..65a3a6bddab 100644 --- a/app/views/shared/_import_form.html.haml +++ b/app/views/shared/_import_form.html.haml @@ -2,7 +2,7 @@ = f.label :import_url, class: 'control-label' do %span Git repository URL .col-sm-10 - = f.text_field :import_url, class: 'form-control', placeholder: 'https://username:password@gitlab.company.com/group/project.git' + = f.text_field :import_url, class: 'form-control', placeholder: 'https://username:password@gitlab.company.com/group/project.git', disabled: true .well.prepend-top-20 %ul From 1f90df083481975b7ceb0693a5bbb1164c5d2e1d Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 28 Jun 2016 16:59:36 +0100 Subject: [PATCH 209/335] Changed collapsed assignee tooltip to users name Fixes tooltip when updating the assignee Closes #19280 #19281 --- app/assets/javascripts/users_select.js.coffee | 6 +++++- app/views/shared/issuable/_sidebar.html.haml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index 4e032ab1ff1..344be811e0d 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -56,6 +56,11 @@ class @UsersSelect username: '' avatar: '' $value.html(assigneeTemplate(user)) + + $collapsedSidebar + .attr('title', user.name) + .tooltip('fixTitle') + $collapsedSidebar.html(collapsedAssigneeTemplate(user)) @@ -63,7 +68,6 @@ class @UsersSelect '<% if( avatar ) { %> - Toni Boehm <% } else { %> diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index adfab1af53e..e020a7d4d00 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -19,7 +19,7 @@ = form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, format: :json, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f| .block.assignee - .sidebar-collapsed-icon.sidebar-collapsed-user{data: {toggle: "tooltip", placement: "left", container: "body"}, title: (issuable.assignee.to_reference if issuable.assignee)} + .sidebar-collapsed-icon.sidebar-collapsed-user{data: {toggle: "tooltip", placement: "left", container: "body"}, title: (issuable.assignee.name if issuable.assignee)} - if issuable.assignee = link_to_member(@project, issuable.assignee, size: 24) - else From 0666515e1fe461ec1ddefffb4ffd2955b5a478e1 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 28 Jun 2016 17:57:31 +0100 Subject: [PATCH 210/335] CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index b0d86e4acad..15d105731d6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -30,6 +30,7 @@ v 8.10.0 (unreleased) - Fix pagination when sorting by columns with lots of ties (like priority) - The Markdown reference parsers now re-use query results to prevent running the same queries multiple times !5020 - Updated project header design + - Issuable collapsed assignee tooltip is now the users name - Exclude email check from the standard health check - Updated layout for Projects, Groups, Users on Admin area !4424 - Fix changing issue state columns in milestone view From ae6edf18fcf207a63a7130ec8d49966acd83de67 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Wed, 29 Jun 2016 18:00:22 +0200 Subject: [PATCH 211/335] Update rubocop to 0.41.2 https://github.com/bbatsov/rubocop/blob/v0.41.2/CHANGELOG.md --- .rubocop.yml | 6 ++--- .rubocop_todo.yml | 65 +++++++++++++++++++++++++++++++++++++++++++++++ Gemfile | 2 +- Gemfile.lock | 12 ++++----- 4 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 .rubocop_todo.yml diff --git a/.rubocop.yml b/.rubocop.yml index 3aac8401848..17802fbb307 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -2,6 +2,8 @@ require: - rubocop-rspec - ./rubocop/rubocop +inherit_from: .rubocop_todo.yml + AllCops: TargetRubyVersion: 2.1 # Cop names are not displayed in offense messages by default. Change behavior @@ -159,10 +161,6 @@ Style/ConstantName: Style/DefWithParentheses: Enabled: true -# Checks for use of deprecated Hash methods. -Style/DeprecatedHashMethods: - Enabled: false - # Document classes and non-namespace modules. Style/Documentation: Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 00000000000..9a791d74c15 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,65 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2016-06-29 18:24:55 +0200 using RuboCop version 0.41.1. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 1 +Lint/ShadowedException: + Exclude: + - 'app/models/u2f_registration.rb' + +# Offense count: 12 +# Cop supports --auto-correct. +Performance/PushSplat: + Exclude: + - 'app/controllers/projects/refs_controller.rb' + - 'app/helpers/page_layout_helper.rb' + - 'app/models/ability.rb' + - 'app/models/network/graph.rb' + - 'app/models/project_team.rb' + - 'app/models/user.rb' + - 'config/application.rb' + +# Offense count: 59 +Rails/OutputSafety: + Enabled: false + +# Offense count: 6 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles. +# SupportedOctalStyles: zero_with_o, zero_only +Style/NumericLiteralPrefix: + Exclude: + - 'config/initializers/1_settings.rb' + - 'config/initializers/secret_token.rb' + - 'lib/gitlab/backend/shell.rb' + - 'spec/support/test_env.rb' + - 'spec/tasks/gitlab/backup_rake_spec.rb' + +# Offense count: 28 +# Cop supports --auto-correct. +Style/PreferredHashMethods: + Exclude: + - 'app/helpers/dropdowns_helper.rb' + - 'app/models/application_setting.rb' + - 'app/models/members/project_member.rb' + - 'app/services/git_push_service.rb' + - 'lib/api/helpers.rb' + - 'lib/ci/api/builds.rb' + - 'lib/ci/gitlab_ci_yaml_processor.rb' + - 'lib/gitlab/ci/config/node/configurable.rb' + - 'lib/gitlab/ci/config/node/factory.rb' + - 'lib/gitlab/google_code_import/client.rb' + - 'lib/gitlab/google_code_import/importer.rb' + - 'lib/gitlab/visibility_level.rb' + - 'spec/requests/api/projects_spec.rb' + +# Offense count: 5 +# Cop supports --auto-correct. +Style/SpaceInsidePercentLiteralDelimiters: + Exclude: + - 'lib/event_filter.rb' + - 'lib/gitlab/git_access.rb' diff --git a/Gemfile b/Gemfile index 5c43015e52c..0769214a071 100644 --- a/Gemfile +++ b/Gemfile @@ -299,7 +299,7 @@ group :development, :test do gem 'spring-commands-spinach', '~> 1.1.0' gem 'spring-commands-teaspoon', '~> 0.0.2' - gem 'rubocop', '~> 0.40.0', require: false + gem 'rubocop', '~> 0.41.1', require: false gem 'rubocop-rspec', '~> 1.5.0', require: false gem 'scss_lint', '~> 0.47.0', require: false gem 'simplecov', '~> 0.11.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock index f8018e58a5e..6f93a534359 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -58,7 +58,7 @@ GEM faraday_middleware-multi_json (~> 0.0) oauth2 (~> 1.0) asciidoctor (1.5.3) - ast (2.2.0) + ast (2.3.0) attr_encrypted (3.0.1) encryptor (~> 3.0.0) attr_required (1.0.0) @@ -473,7 +473,7 @@ GEM orm_adapter (0.5.0) paranoia (2.1.4) activerecord (~> 4.0) - parser (2.3.1.0) + parser (2.3.1.2) ast (~> 2.2) pg (0.18.4) pkg-config (1.1.7) @@ -606,8 +606,8 @@ GEM rspec-retry (0.4.5) rspec-core rspec-support (3.5.0) - rubocop (0.40.0) - parser (>= 2.3.1.0, < 3.0) + rubocop (0.41.2) + parser (>= 2.3.1.1, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) ruby-progressbar (~> 1.7) @@ -758,7 +758,7 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.7.2) - unicode-display_width (1.0.5) + unicode-display_width (1.1.0) unicorn (4.9.0) kgio (~> 2.6) rack @@ -937,7 +937,7 @@ DEPENDENCIES rqrcode-rails3 (~> 0.1.7) rspec-rails (~> 3.5.0) rspec-retry (~> 0.4.5) - rubocop (~> 0.40.0) + rubocop (~> 0.41.1) rubocop-rspec (~> 1.5.0) ruby-fogbugz (~> 0.2.1) sanitize (~> 2.0) From fb4f3a473b633ebd165d351e7101898c2b87ad72 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Sun, 3 Jul 2016 14:18:39 -0600 Subject: [PATCH 212/335] Remove some disabled cops. --- .rubocop.yml | 363 +---------------------------- .rubocop_todo.yml | 567 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 552 insertions(+), 378 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 17802fbb307..ce4287a2796 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -37,10 +37,6 @@ AllCops: Style/AccessModifierIndentation: Enabled: true -# Check the naming of accessor methods for get_/set_. -Style/AccessorMethodName: - Enabled: false - # Use alias_method instead of alias. Style/Alias: EnforcedStyle: prefer_alias_method @@ -54,14 +50,6 @@ Style/AlignArray: Style/AlignHash: Enabled: true -# Align the parameters of a method call if they span more than one line. -Style/AlignParameters: - Enabled: false - -# Use &&/|| instead of and/or. -Style/AndOr: - Enabled: false - # Use `Array#join` instead of `Array#*`. Style/ArrayJoin: Enabled: true @@ -82,10 +70,6 @@ Style/Attr: Style/BeginBlock: Enabled: true -# Checks if usage of %() or %Q() matches configuration. -Style/BarePercentLiterals: - Enabled: false - # Do not use block comments. Style/BlockComments: Enabled: true @@ -99,14 +83,6 @@ Style/BlockEndNewline: Style/BlockDelimiters: Enabled: true -# Enforce braces style around hash parameters. -Style/BracesAroundHashParameters: - Enabled: false - -# Avoid explicit use of the case equality operator(===). -Style/CaseEquality: - Enabled: false - # Indentation of when in a case/when/[else/]end. Style/CaseIndentation: Enabled: true @@ -135,24 +111,10 @@ Style/ClassMethods: Style/ClassVars: Enabled: true -# Do not use :: for method call. -Style/ColonMethodCall: - Enabled: false - -# Checks formatting of special comments (TODO, FIXME, OPTIMIZE, HACK, REVIEW). -Style/CommentAnnotation: - Enabled: false - # Indentation of comments. Style/CommentIndentation: Enabled: true -# Use the return value of `if` and `case` statements for assignment to a -# variable and variable comparison instead of assigning that variable -# inside of each branch. -Style/ConditionalAssignment: - Enabled: false - # Constants should use SCREAMING_SNAKE_CASE. Style/ConstantName: Enabled: true @@ -165,26 +127,10 @@ Style/DefWithParentheses: Style/Documentation: Enabled: false -# Checks the position of the dot in multi-line method calls. -Style/DotPosition: - Enabled: false - -# Checks for uses of double negation (!!). -Style/DoubleNegation: - Enabled: false - -# Prefer `each_with_object` over `inject` or `reduce`. -Style/EachWithObject: - Enabled: false - # Align elses and elsifs correctly. Style/ElseAlignment: Enabled: true -# Avoid empty else-clauses. -Style/EmptyElse: - Enabled: false - # Use empty lines between defs. Style/EmptyLineBetweenDefs: Enabled: false @@ -213,10 +159,6 @@ Style/EmptyLinesAroundModuleBody: Style/EmptyLinesAroundMethodBody: Enabled: false -# Prefer literals to Array.new/Hash.new/String.new. -Style/EmptyLiteral: - Enabled: false - # Avoid the use of END blocks. Style/EndBlock: Enabled: true @@ -229,10 +171,6 @@ Style/EndOfLine: Style/EvenOdd: Enabled: true -# Do not use unnecessary spacing. -Style/ExtraSpacing: - Enabled: false - # Use snake_case for source file names. Style/FileName: Enabled: true @@ -250,31 +188,15 @@ Style/FlipFlop: Style/For: Enabled: true -# Enforce the use of Kernel#sprintf, Kernel#format or String#%. -Style/FormatString: - Enabled: false - # Do not introduce global variables. Style/GlobalVars: Enabled: true -# Check for conditionals that can be replaced with guard clauses. -Style/GuardClause: - Enabled: false - # Prefer Ruby 1.9 hash syntax `{ a: 1, b: 2 }` # over 1.8 syntax `{ :a => 1, :b => 2 }`. Style/HashSyntax: Enabled: true -# Finds if nodes inside else, which can be converted to elsif. -Style/IfInsideElse: - Enabled: false - -# Favor modifier if/unless usage when you have a single-line body. -Style/IfUnlessModifier: - Enabled: false - # Do not use if x; .... Use the ternary operator instead. Style/IfWithSemicolon: Enabled: true @@ -297,22 +219,10 @@ Style/IndentationConsistency: Style/IndentationWidth: Enabled: true -# Checks the indentation of the first element in an array literal. -Style/IndentArray: - Enabled: false - -# Checks the indentation of the first key in a hash literal. -Style/IndentHash: - Enabled: false - # Use Kernel#loop for infinite loops. Style/InfiniteLoop: Enabled: true -# Use the new lambda literal syntax for single-line blocks. -Style/Lambda: - Enabled: false - # Use lambda.call(...) instead of lambda.(...). Style/LambdaCall: Enabled: true @@ -321,14 +231,6 @@ Style/LambdaCall: Style/LeadingCommentSpace: Enabled: true -# Use \ instead of + or << to concatenate two string literals at line end. -Style/LineEndConcatenation: - Enabled: false - -# Do not use parentheses for method calls with no arguments. -Style/MethodCallParentheses: - Enabled: false - # Checks if the method definitions have or don't have parentheses. Style/MethodDefParentheses: Enabled: true @@ -337,10 +239,6 @@ Style/MethodDefParentheses: Style/MethodName: Enabled: true -# Checks for usage of `extend self` in modules. -Style/ModuleFunction: - Enabled: false - # Checks that the closing brace in an array literal is either on the same line # as the last array element, or a new line. Style/MultilineArrayBraceLayout: @@ -385,39 +283,18 @@ Style/MultilineMethodDefinitionBraceLayout: Style/MultilineOperationIndentation: Enabled: false -# Avoid multi-line `? :` (the ternary operator), use if/unless instead. -Style/MultilineTernaryOperator: - Enabled: false - -# Do not assign mutable objects to constants. -Style/MutableConstant: - Enabled: false - # Favor unless over if for negative conditions (or control flow or). Style/NegatedIf: Enabled: true -# Favor until over while for negative conditions. -Style/NegatedWhile: - Enabled: false - # Avoid using nested modifiers. Style/NestedModifier: Enabled: true -# Parenthesize method calls which are nested inside the argument list of -# another parenthesized method call. -Style/NestedParenthesizedCalls: - Enabled: false - # Use one expression per branch in a ternary operator. Style/NestedTernaryOperator: Enabled: true -# Use `next` to skip iteration instead of a condition at the end. -Style/Next: - Enabled: false - # Prefer x.nil? to x == nil. Style/NilComparison: Enabled: true @@ -442,51 +319,10 @@ Style/OneLineConditional: Style/OpMethod: Enabled: true -# Check for simple usages of parallel assignment. It will only warn when -# the number of variables matches on both sides of the assignment. -Style/ParallelAssignment: - Enabled: false - # Don't use parentheses around the condition of an if/unless/while. Style/ParenthesesAroundCondition: Enabled: true -# Use `%`-literal delimiters consistently. -Style/PercentLiteralDelimiters: - Enabled: false - -# Checks if uses of %Q/%q match the configured preference. -Style/PercentQLiterals: - Enabled: false - -# Avoid Perl-style regex back references. -Style/PerlBackrefs: - Enabled: false - -# Check the names of predicate methods. -Style/PredicateName: - Enabled: false - -# Use proc instead of Proc.new. -Style/Proc: - Enabled: false - -# Checks the arguments passed to raise/fail. -Style/RaiseArgs: - Enabled: false - -# Don't use begin blocks when they are not needed. -Style/RedundantBegin: - Enabled: false - -# Checks for an obsolete RuntimeException argument in raise/fail. -Style/RedundantException: - Enabled: false - -# Checks usages of Object#freeze on immutable objects. -Style/RedundantFreeze: - Enabled: false - # Checks for parentheses that seem not to serve any purpose. Style/RedundantParentheses: Enabled: true @@ -495,24 +331,6 @@ Style/RedundantParentheses: Style/RedundantReturn: Enabled: true -# Don't use self where it's not needed. -Style/RedundantSelf: - Enabled: false - -# Use %r for regular expressions matching more than `MaxSlashes` '/' -# characters. Use %r only for regular expressions matching more -# than `MaxSlashes` '/' character. -Style/RegexpLiteral: - Enabled: false - -# Avoid using rescue in its modifier form. -Style/RescueModifier: - Enabled: false - -# Checks for places where self-assignment shorthand should have been used. -Style/SelfAssignment: - Enabled: false - # Don't use semicolons to terminate expressions. Style/Semicolon: Enabled: true @@ -522,14 +340,6 @@ Style/SignalException: EnforcedStyle: only_raise Enabled: true -# Enforces the names of some block params. -Style/SingleLineBlockParams: - Enabled: false - -# Avoid single-line methods. -Style/SingleLineMethods: - Enabled: false - # Use spaces after colons. Style/SpaceAfterColon: Enabled: true @@ -551,11 +361,6 @@ Style/SpaceAfterNot: Style/SpaceAfterSemicolon: Enabled: true -# Checks that the equals signs in parameter default assignments have or don't -# have surrounding space depending on configuration. -Style/SpaceAroundEqualsInParameterDefault: - Enabled: false - # Use a space around keywords if appropriate. Style/SpaceAroundKeyword: Enabled: true @@ -564,10 +369,6 @@ Style/SpaceAroundKeyword: Style/SpaceAroundOperators: Enabled: true -# Checks that the left block brace has or doesn't have space before it. -Style/SpaceBeforeBlockBraces: - Enabled: false - # No spaces before commas. Style/SpaceBeforeComma: Enabled: true @@ -576,33 +377,14 @@ Style/SpaceBeforeComma: Style/SpaceBeforeComment: Enabled: true -# Checks that exactly one space is used between a method name and the first -# argument for method calls without parentheses. -Style/SpaceBeforeFirstArg: - Enabled: false - # No spaces before semicolons. Style/SpaceBeforeSemicolon: Enabled: true -# Checks that block braces have or don't have surrounding space. -# For blocks taking parameters, checks that the left brace has or doesn't -# have trailing space. -Style/SpaceInsideBlockBraces: - Enabled: false - -# No spaces after [ or before ]. -Style/SpaceInsideBrackets: - Enabled: false - # Use spaces inside hash literal braces - or don't. Style/SpaceInsideHashLiteralBraces: Enabled: true -# No spaces after ( or before ). -Style/SpaceInsideParens: - Enabled: false - # No spaces inside range literals. Style/SpaceInsideRangeLiteral: Enabled: true @@ -612,10 +394,6 @@ Style/SpaceInsideStringInterpolation: EnforcedStyle: no_space Enabled: true -# Avoid Perl-style global variables. -Style/SpecialGlobalVars: - Enabled: false - # Check for the usage of parentheses around stabby lambda arguments. Style/StabbyLambdaParentheses: EnforcedStyle: require_parentheses @@ -625,25 +403,12 @@ Style/StabbyLambdaParentheses: Style/StringLiterals: Enabled: false -# Checks if uses of quotes inside expressions in interpolated strings match the -# configured preference. -Style/StringLiteralsInInterpolation: - Enabled: false - # Checks if configured preferred methods are used over non-preferred. Style/StringMethods: PreferredMethods: intern: to_sym Enabled: true -# Use %i or %I for arrays of symbols. -Style/SymbolArray: - Enabled: false - -# Use symbols as procs instead of blocks when possible. -Style/SymbolProc: - Enabled: false - # No hard tabs. Style/Tab: Enabled: true @@ -652,40 +417,10 @@ Style/Tab: Style/TrailingBlankLines: Enabled: true -# Checks for trailing comma in array and hash literals. -Style/TrailingCommaInLiteral: - Enabled: false - -# Checks for trailing comma in argument lists. -Style/TrailingCommaInArguments: - Enabled: false - -# Avoid trailing whitespace. -Style/TrailingWhitespace: - Enabled: false - -# Checks for the usage of unneeded trailing underscores at the end of -# parallel variable assignment. -Style/TrailingUnderscoreVariable: - Enabled: false - -# Prefer attr_* methods to trivial readers/writers. -Style/TrivialAccessors: - Enabled: false - -# Do not use unless with else. Rewrite these with the positive case first. -Style/UnlessElse: - Enabled: false - # Checks for %W when interpolation is not needed. Style/UnneededCapitalW: Enabled: true -# TODO: Enable UnneededInterpolation Cop. -# Checks for strings that are just an interpolated expression. -Style/UnneededInterpolation: - Enabled: false - # Checks for %q/%Q when single quotes or double quotes would do. Style/UnneededPercentQ: Enabled: false @@ -715,12 +450,6 @@ Style/WhileUntilModifier: Style/WordArray: Enabled: false -# TODO: Enable ZeroLengthPredicate Cop. -# Use #empty? when testing for objects of length 0. -Style/ZeroLengthPredicate: - Enabled: false - - #################### Metrics ################################ # A calculated magnitude based on number of assignments, @@ -774,15 +503,6 @@ Metrics/PerceivedComplexity: Lint/AmbiguousOperator: Enabled: true -# Checks for ambiguous regexp literals in the first argument of a method -# invocation without parentheses. -Lint/AmbiguousRegexpLiteral: - Enabled: false - -# Don't use assignment in conditions. -Lint/AssignmentInCondition: - Enabled: false - # Align block ends correctly. Lint/BlockAlignment: Enabled: true @@ -808,14 +528,6 @@ Lint/DefEndAlignment: Lint/DeprecatedClassMethods: Enabled: true -# Check for duplicate method definitions. -Lint/DuplicateMethods: - Enabled: false - -# Check for duplicate keys in hash literals. -Lint/DuplicatedKey: - Enabled: false - # Check for immutable argument given to each_with_object. Lint/EachWithObjectArgument: Enabled: true @@ -828,10 +540,6 @@ Lint/ElseLayout: Lint/EmptyEnsure: Enabled: true -# Checks for empty string interpolation. -Lint/EmptyInterpolation: - Enabled: false - # Align ends correctly. Lint/EndAlignment: Enabled: true @@ -856,21 +564,11 @@ Lint/FloatOutOfRange: Lint/FormatParameterMismatch: Enabled: true -# Don't suppress exception. -Lint/HandleExceptions: - Enabled: false - # Checks for adjacent string literals on the same line, which could better be # represented as a single string literal. Lint/ImplicitStringConcatenation: Enabled: true -# TODO: Enable IneffectiveAccessModifier Cop. -# Checks for attempts to use `private` or `protected` to set the visibility -# of a class method, which does not work. -Lint/IneffectiveAccessModifier: - Enabled: false - # Checks for invalid character literals with a non-escaped whitespace # character. Lint/InvalidCharacterLiteral: @@ -884,11 +582,6 @@ Lint/LiteralInCondition: Lint/LiteralInInterpolation: Enabled: true -# Use Kernel#loop with break rather than begin/end/until or begin/end/while -# for post-loop tests. -Lint/Loop: - Enabled: false - # Do not use nested method definitions. Lint/NestedMethodDefinition: Enabled: true @@ -914,13 +607,8 @@ Lint/RequireParentheses: Lint/RescueException: Enabled: true -# Do not use the same name as outer local variable for block arguments -# or block local variables. -Lint/ShadowingOuterLocalVariable: - Enabled: false - -# 'Checks for Object#to_s usage in string interpolation. -Lint/StringConversionInInterpolation: +# Checks for the order which exceptions are rescued to avoid rescueing a less specific exception before a more specific exception. +Lint/ShadowedException: Enabled: false # Do not use prefix `_` for a variable that is used. @@ -933,22 +621,10 @@ Lint/UnderscorePrefixedVariableName: Lint/UnneededDisable: Enabled: false -# Checks for unused block arguments. -Lint/UnusedBlockArgument: - Enabled: false - -# Checks for unused method arguments. -Lint/UnusedMethodArgument: - Enabled: false - # Unreachable code. Lint/UnreachableCode: Enabled: true -# Checks for useless access modifiers. -Lint/UselessAccessModifier: - Enabled: false - # Checks for useless assignment to a local variable. Lint/UselessAssignment: Enabled: true @@ -981,11 +657,6 @@ Performance/Casecmp: Performance/DoubleStartEndWith: Enabled: true -# TODO: Enable EndWith Cop. -# Use `end_with?` instead of a regex match anchored to the end of a string. -Performance/EndWith: - Enabled: false - # Use `strip` instead of `lstrip.rstrip`. Performance/LstripRstrip: Enabled: true @@ -994,24 +665,6 @@ Performance/LstripRstrip: Performance/RangeInclude: Enabled: true -# TODO: Enable RedundantBlockCall Cop. -# Use `yield` instead of `block.call`. -Performance/RedundantBlockCall: - Enabled: false - -# TODO: Enable RedundantMatch Cop. -# Use `=~` instead of `String#match` or `Regexp#match` in a context where the -# returned `MatchData` is not needed. -Performance/RedundantMatch: - Enabled: false - -# TODO: Enable RedundantMerge Cop. -# Use `Hash#[]=`, rather than `Hash#merge!` with a single key-value pair. -Performance/RedundantMerge: - # Max number of key-value pairs to consider an offense - MaxKeyValuePairs: 2 - Enabled: false - # Use `sort` instead of `sort_by { |x| x }`. Performance/RedundantSortBy: Enabled: true @@ -1080,18 +733,6 @@ Rails/ReadWriteAttribute: Rails/ScopeArgs: Enabled: true -# Checks the correct usage of time zone aware methods. -# http://danilenko.org/2012/7/6/rails_timezones -Rails/TimeZone: - Enabled: false - -# Use validates :attribute, hash of validations. -Rails/Validation: - Enabled: false - -Rails/UniqBeforePluck: - Enabled: false - ##################### RSpec ################################## # Check that instances are not being stubbed globally. diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 9a791d74c15..cb6df9d88c2 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,15 +1,66 @@ # This configuration was generated by -# `rubocop --auto-gen-config` -# on 2016-06-29 18:24:55 +0200 using RuboCop version 0.41.1. +# `rubocop --auto-gen-config --exclude-limit 8` +# on 2016-07-03 15:32:25 -0600 using RuboCop version 0.41.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. +# Offense count: 152 +Lint/AmbiguousRegexpLiteral: + Enabled: false + +# Offense count: 42 +# Configuration parameters: AllowSafeAssignment. +Lint/AssignmentInCondition: + Enabled: false + # Offense count: 1 -Lint/ShadowedException: +Lint/DuplicateMethods: Exclude: - - 'app/models/u2f_registration.rb' + - 'lib/gitlab/github_import/branch_formatter.rb' + +# Offense count: 14 +Lint/HandleExceptions: + Enabled: false + +# Offense count: 20 +Lint/IneffectiveAccessModifier: + Enabled: false + +# Offense count: 2 +Lint/Loop: + Exclude: + - 'app/mailers/notify.rb' + - 'lib/gitlab/bitbucket_import/client.rb' + +# Offense count: 12 +Lint/ShadowingOuterLocalVariable: + Enabled: false + +# Offense count: 3 +# Cop supports --auto-correct. +Lint/StringConversionInInterpolation: + Exclude: + - 'app/models/commit_range.rb' + - 'app/services/system_hooks_service.rb' + - 'app/services/system_note_service.rb' + +# Offense count: 42 +# Cop supports --auto-correct. +# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments. +Lint/UnusedBlockArgument: + Enabled: false + +# Offense count: 125 +# Cop supports --auto-correct. +# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods. +Lint/UnusedMethodArgument: + Enabled: false + +# Offense count: 11 +Lint/UselessAccessModifier: + Enabled: false # Offense count: 12 # Cop supports --auto-correct. @@ -23,10 +74,263 @@ Performance/PushSplat: - 'app/models/user.rb' - 'config/application.rb' +# Offense count: 2 +# Cop supports --auto-correct. +Performance/RedundantBlockCall: + Exclude: + - 'app/controllers/application_controller.rb' + - 'lib/gitlab/backend/shell.rb' + +# Offense count: 5 +# Cop supports --auto-correct. +Performance/RedundantMatch: + Exclude: + - 'app/models/external_issue.rb' + - 'lib/extracts_path.rb' + - 'lib/gitlab/diff/highlight.rb' + - 'lib/gitlab/diff/inline_diff.rb' + - 'lib/gitlab/diff/parser.rb' + +# Offense count: 24 +# Cop supports --auto-correct. +# Configuration parameters: MaxKeyValuePairs. +Performance/RedundantMerge: + Enabled: false + # Offense count: 59 Rails/OutputSafety: Enabled: false +# Offense count: 125 +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: strict, flexible +Rails/TimeZone: + Enabled: false + +# Offense count: 12 +# Cop supports --auto-correct. +# Configuration parameters: Include. +# Include: app/models/**/*.rb +Rails/Validation: + Enabled: false + +# Offense count: 18 +Style/AccessorMethodName: + Enabled: false + +# Offense count: 208 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: with_first_parameter, with_fixed_indentation +Style/AlignParameters: + Enabled: false + +# Offense count: 32 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: always, conditionals +Style/AndOr: + Enabled: false + +# Offense count: 47 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: percent_q, bare_percent +Style/BarePercentLiterals: + Enabled: false + +# Offense count: 255 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: braces, no_braces, context_dependent +Style/BracesAroundHashParameters: + Enabled: false + +# Offense count: 4 +Style/CaseEquality: + Exclude: + - 'app/helpers/auth_helper.rb' + - 'app/models/commit.rb' + - 'app/services/projects/download_service.rb' + - 'config/initializers/trusted_proxies.rb' + +# Offense count: 19 +# Cop supports --auto-correct. +Style/ColonMethodCall: + Enabled: false + +# Offense count: 3 +# Cop supports --auto-correct. +# Configuration parameters: Keywords. +# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW +Style/CommentAnnotation: + Exclude: + - 'app/models/project.rb' + - 'lib/api/entities.rb' + - 'spec/requests/api/project_snippets_spec.rb' + +# Offense count: 35 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly. +# SupportedStyles: assign_to_condition, assign_inside_condition +Style/ConditionalAssignment: + Enabled: false + +# Offense count: 762 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: leading, trailing +Style/DotPosition: + Enabled: false + +# Offense count: 14 +Style/DoubleNegation: + Enabled: false + +# Offense count: 3 +Style/EachWithObject: + Exclude: + - 'app/models/commit_status.rb' + - 'lib/ci/ansi2html.rb' + - 'lib/gitlab/import_export/members_mapper.rb' + +# Offense count: 29 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: empty, nil, both +Style/EmptyElse: + Enabled: false + +# Offense count: 3 +# Cop supports --auto-correct. +Style/EmptyLiteral: + Exclude: + - 'features/steps/project/commits/commits.rb' + - 'lib/gitlab/fogbugz_import/importer.rb' + - 'spec/lib/gitlab/workhorse_spec.rb' + +# Offense count: 119 +# Cop supports --auto-correct. +# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. +Style/ExtraSpacing: + Enabled: false + +# Offense count: 7 +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: format, sprintf, percent +Style/FormatString: + Exclude: + - 'app/models/ci/pipeline.rb' + - 'app/services/gravatar_service.rb' + - 'config/initializers/rack_lineprof.rb' + - 'lib/ci/version_info.rb' + - 'lib/gitlab/version_info.rb' + - 'spec/requests/api/issues_spec.rb' + +# Offense count: 50 +# Configuration parameters: MinBodyLength. +Style/GuardClause: + Enabled: false + +# Offense count: 9 +Style/IdenticalConditionalBranches: + Exclude: + - 'app/controllers/projects_controller.rb' + - 'app/models/project_services/irker_service.rb' + - 'app/services/merge_requests/refresh_service.rb' + - 'lib/rouge/formatters/html_gitlab.rb' + +# Offense count: 10 +Style/IfInsideElse: + Enabled: false + +# Offense count: 178 +# Cop supports --auto-correct. +# Configuration parameters: MaxLineLength. +Style/IfUnlessModifier: + Enabled: false + +# Offense count: 48 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_brackets +Style/IndentArray: + Enabled: false + +# Offense count: 85 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_braces +Style/IndentHash: + Enabled: false + +# Offense count: 11 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: line_count_dependent, lambda, literal +Style/Lambda: + Exclude: + - 'app/models/ci/runner.rb' + - 'app/models/event.rb' + - 'app/models/note.rb' + - 'config/routes.rb' + - 'lib/api/entities.rb' + - 'spec/models/concerns/participable_spec.rb' + +# Offense count: 6 +# Cop supports --auto-correct. +Style/LineEndConcatenation: + Exclude: + - 'app/helpers/preferences_helper.rb' + - 'app/helpers/tree_helper.rb' + - 'app/models/merge_request.rb' + - 'app/models/user.rb' + - 'spec/lib/gitlab/gfm/reference_rewriter_spec.rb' + +# Offense count: 13 +# Cop supports --auto-correct. +Style/MethodCallParentheses: + Exclude: + - 'lib/api/helpers.rb' + - 'lib/ci/ansi2html.rb' + - 'spec/features/dashboard/datetime_on_tooltips_spec.rb' + - 'spec/helpers/submodule_helper_spec.rb' + - 'spec/workers/post_receive_spec.rb' + +# Offense count: 9 +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: module_function, extend_self +Style/ModuleFunction: + Enabled: false + +# Offense count: 3 +Style/MultilineTernaryOperator: + Exclude: + - 'lib/banzai/filter/relative_link_filter.rb' + - 'spec/support/api_helpers.rb' + +# Offense count: 62 +# Cop supports --auto-correct. +Style/MutableConstant: + Enabled: false + +# Offense count: 10 +# Cop supports --auto-correct. +Style/NestedParenthesizedCalls: + Exclude: + - 'app/helpers/commits_helper.rb' + - 'app/workers/irker_worker.rb' + - 'spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb' + - 'spec/lib/gitlab/email/message/repository_push_spec.rb' + - 'spec/services/ci/create_builds_service_spec.rb' + +# Offense count: 13 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles. +# SupportedStyles: skip_modifier_ifs, always +Style/Next: + Enabled: false + # Offense count: 6 # Cop supports --auto-correct. # Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles. @@ -39,23 +343,166 @@ Style/NumericLiteralPrefix: - 'spec/support/test_env.rb' - 'spec/tasks/gitlab/backup_rake_spec.rb' +# Offense count: 29 +# Cop supports --auto-correct. +Style/ParallelAssignment: + Enabled: false + +# Offense count: 201 +# Cop supports --auto-correct. +# Configuration parameters: PreferredDelimiters. +Style/PercentLiteralDelimiters: + Enabled: false + +# Offense count: 11 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: lower_case_q, upper_case_q +Style/PercentQLiterals: + Exclude: + - 'spec/helpers/gitlab_markdown_helper_spec.rb' + - 'spec/lib/gitlab/diff/highlight_spec.rb' + - 'spec/models/project_services/bamboo_service_spec.rb' + - 'spec/models/project_services/teamcity_service_spec.rb' + - 'spec/workers/repository_import_worker_spec.rb' + +# Offense count: 14 +# Cop supports --auto-correct. +Style/PerlBackrefs: + Enabled: false + +# Offense count: 30 +# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. +# NamePrefix: is_, has_, have_ +# NamePrefixBlacklist: is_, has_, have_ +# NameWhitelist: is_a? +Style/PredicateName: + Enabled: false + # Offense count: 28 # Cop supports --auto-correct. Style/PreferredHashMethods: + Enabled: false + +# Offense count: 6 +# Cop supports --auto-correct. +Style/Proc: Exclude: - - 'app/helpers/dropdowns_helper.rb' - - 'app/models/application_setting.rb' - - 'app/models/members/project_member.rb' - - 'app/services/git_push_service.rb' - - 'lib/api/helpers.rb' - - 'lib/ci/api/builds.rb' - - 'lib/ci/gitlab_ci_yaml_processor.rb' - - 'lib/gitlab/ci/config/node/configurable.rb' - - 'lib/gitlab/ci/config/node/factory.rb' - - 'lib/gitlab/google_code_import/client.rb' - - 'lib/gitlab/google_code_import/importer.rb' - - 'lib/gitlab/visibility_level.rb' - - 'spec/requests/api/projects_spec.rb' + - 'app/mailers/base_mailer.rb' + - 'app/models/label.rb' + - 'app/models/service.rb' + - 'lib/api/api_guard.rb' + - 'spec/initializers/trusted_proxies_spec.rb' + +# Offense count: 21 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: compact, exploded +Style/RaiseArgs: + Enabled: false + +# Offense count: 3 +# Cop supports --auto-correct. +Style/RedundantBegin: + Exclude: + - 'app/models/ci/build.rb' + - 'app/models/merge_request.rb' + - 'app/services/projects/import_service.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Style/RedundantException: + Exclude: + - 'app/helpers/preferences_helper.rb' + +# Offense count: 21 +# Cop supports --auto-correct. +Style/RedundantFreeze: + Enabled: false + +# Offense count: 312 +# Cop supports --auto-correct. +Style/RedundantSelf: + Enabled: false + +# Offense count: 92 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. +# SupportedStyles: slashes, percent_r, mixed +Style/RegexpLiteral: + Enabled: false + +# Offense count: 14 +# Cop supports --auto-correct. +Style/RescueModifier: + Enabled: false + +# Offense count: 2 +# Cop supports --auto-correct. +Style/SelfAssignment: + Exclude: + - 'app/services/notification_service.rb' + - 'lib/api/runners.rb' + +# Offense count: 2 +# Configuration parameters: Methods. +# Methods: {"reduce"=>["a", "e"]}, {"inject"=>["a", "e"]} +Style/SingleLineBlockParams: + Exclude: + - 'app/models/commit.rb' + - 'spec/support/services_shared_context.rb' + +# Offense count: 50 +# Cop supports --auto-correct. +# Configuration parameters: AllowIfMethodIsEmpty. +Style/SingleLineMethods: + Exclude: + - 'lib/ci/ansi2html.rb' + +# Offense count: 14 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: space, no_space +Style/SpaceAroundEqualsInParameterDefault: + Enabled: false + +# Offense count: 118 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: space, no_space +Style/SpaceBeforeBlockBraces: + Enabled: false + +# Offense count: 11 +# Cop supports --auto-correct. +# Configuration parameters: AllowForAlignment. +Style/SpaceBeforeFirstArg: + Exclude: + - 'config/initializers/doorkeeper.rb' + - 'config/routes.rb' + - 'features/steps/project/source/browse_files.rb' + - 'features/steps/project/source/markdown_render.rb' + - 'spec/routing/project_routing_spec.rb' + - 'spec/services/delete_user_service_spec.rb' + - 'spec/services/projects/fork_service_spec.rb' + - 'spec/services/system_note_service_spec.rb' + +# Offense count: 129 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. +# SupportedStyles: space, no_space +Style/SpaceInsideBlockBraces: + Enabled: false + +# Offense count: 92 +# Cop supports --auto-correct. +Style/SpaceInsideBrackets: + Enabled: false + +# Offense count: 60 +# Cop supports --auto-correct. +Style/SpaceInsideParens: + Enabled: false # Offense count: 5 # Cop supports --auto-correct. @@ -63,3 +510,89 @@ Style/SpaceInsidePercentLiteralDelimiters: Exclude: - 'lib/event_filter.rb' - 'lib/gitlab/git_access.rb' + +# Offense count: 33 +# Cop supports --auto-correct. +# Configuration parameters: SupportedStyles. +# SupportedStyles: use_perl_names, use_english_names +Style/SpecialGlobalVars: + EnforcedStyle: use_perl_names + +# Offense count: 30 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: single_quotes, double_quotes +Style/StringLiteralsInInterpolation: + Enabled: false + +# Offense count: 24 +# Cop supports --auto-correct. +# Configuration parameters: IgnoredMethods. +# IgnoredMethods: respond_to, define_method +Style/SymbolProc: + Enabled: false + +# Offense count: 23 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles. +# SupportedStyles: comma, consistent_comma, no_comma +Style/TrailingCommaInArguments: + Enabled: false + +# Offense count: 117 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles. +# SupportedStyles: comma, consistent_comma, no_comma +Style/TrailingCommaInLiteral: + Enabled: false + +# Offense count: 7 +# Cop supports --auto-correct. +# Configuration parameters: AllowNamedUnderscoreVariables. +Style/TrailingUnderscoreVariable: + Exclude: + - 'app/controllers/admin/background_jobs_controller.rb' + - 'app/controllers/invites_controller.rb' + - 'app/controllers/projects/git_http_controller.rb' + - 'app/helpers/tab_helper.rb' + - 'lib/gitlab/force_push_check.rb' + - 'lib/gitlab/logger.rb' + +# Offense count: 89 +# Cop supports --auto-correct. +Style/TrailingWhitespace: + Enabled: false + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist. +# Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym +Style/TrivialAccessors: + Exclude: + - 'app/models/external_issue.rb' + - 'lib/gitlab/ldap/person.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +Style/UnlessElse: + Exclude: + - 'lib/api/projects.rb' + - 'lib/gitlab/backend/grack_auth.rb' + - 'lib/gitlab/project_search_results.rb' + +# Offense count: 14 +# Cop supports --auto-correct. +Style/UnneededInterpolation: + Enabled: false + +# Offense count: 8 +# Cop supports --auto-correct. +Style/ZeroLengthPredicate: + Exclude: + - 'app/models/deploy_key.rb' + - 'app/models/network/commit.rb' + - 'app/models/network/graph.rb' + - 'app/models/project_services/asana_service.rb' + - 'app/models/repository.rb' + - 'lib/extracts_path.rb' + - 'lib/gitlab/force_push_check.rb' From c4cbf3effa2c19ebcdcd3943b46ed9296c6e609e Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Tue, 5 Jul 2016 10:33:50 -0600 Subject: [PATCH 213/335] Disable two cops as recommended. --- .rubocop.yml | 8 ++++++++ .rubocop_todo.yml | 42 ++++++++++++++++-------------------------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index ce4287a2796..db0bcfadcf4 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -37,6 +37,10 @@ AllCops: Style/AccessModifierIndentation: Enabled: true +# Check the naming of accessor methods for get_/set_. +Style/AccessorMethodName: + Enabled: false + # Use alias_method instead of alias. Style/Alias: EnforcedStyle: prefer_alias_method @@ -239,6 +243,10 @@ Style/MethodDefParentheses: Style/MethodName: Enabled: true +# Checks for usage of `extend self` in modules. +Style/ModuleFunction: + Enabled: false + # Checks that the closing brace in an array literal is either on the same line # as the last array element, or a new line. Style/MultilineArrayBraceLayout: diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index cb6df9d88c2..8204fd82a63 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,12 +1,12 @@ # This configuration was generated by # `rubocop --auto-gen-config --exclude-limit 8` -# on 2016-07-03 15:32:25 -0600 using RuboCop version 0.41.1. +# on 2016-07-05 10:30:07 -0600 using RuboCop version 0.41.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 152 +# Offense count: 154 Lint/AmbiguousRegexpLiteral: Enabled: false @@ -52,7 +52,7 @@ Lint/StringConversionInInterpolation: Lint/UnusedBlockArgument: Enabled: false -# Offense count: 125 +# Offense count: 129 # Cop supports --auto-correct. # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods. Lint/UnusedMethodArgument: @@ -114,11 +114,7 @@ Rails/TimeZone: Rails/Validation: Enabled: false -# Offense count: 18 -Style/AccessorMethodName: - Enabled: false - -# Offense count: 208 +# Offense count: 218 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. # SupportedStyles: with_first_parameter, with_fixed_indentation @@ -139,7 +135,7 @@ Style/AndOr: Style/BarePercentLiterals: Enabled: false -# Offense count: 255 +# Offense count: 256 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: braces, no_braces, context_dependent @@ -176,7 +172,7 @@ Style/CommentAnnotation: Style/ConditionalAssignment: Enabled: false -# Offense count: 762 +# Offense count: 773 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: leading, trailing @@ -194,7 +190,7 @@ Style/EachWithObject: - 'lib/ci/ansi2html.rb' - 'lib/gitlab/import_export/members_mapper.rb' -# Offense count: 29 +# Offense count: 30 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: empty, nil, both @@ -244,7 +240,7 @@ Style/IdenticalConditionalBranches: Style/IfInsideElse: Enabled: false -# Offense count: 178 +# Offense count: 179 # Cop supports --auto-correct. # Configuration parameters: MaxLineLength. Style/IfUnlessModifier: @@ -297,19 +293,13 @@ Style/MethodCallParentheses: - 'spec/helpers/submodule_helper_spec.rb' - 'spec/workers/post_receive_spec.rb' -# Offense count: 9 -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: module_function, extend_self -Style/ModuleFunction: - Enabled: false - # Offense count: 3 Style/MultilineTernaryOperator: Exclude: - 'lib/banzai/filter/relative_link_filter.rb' - 'spec/support/api_helpers.rb' -# Offense count: 62 +# Offense count: 61 # Cop supports --auto-correct. Style/MutableConstant: Enabled: false @@ -348,7 +338,7 @@ Style/NumericLiteralPrefix: Style/ParallelAssignment: Enabled: false -# Offense count: 201 +# Offense count: 206 # Cop supports --auto-correct. # Configuration parameters: PreferredDelimiters. Style/PercentLiteralDelimiters: @@ -379,7 +369,7 @@ Style/PerlBackrefs: Style/PredicateName: Enabled: false -# Offense count: 28 +# Offense count: 27 # Cop supports --auto-correct. Style/PreferredHashMethods: Enabled: false @@ -394,7 +384,7 @@ Style/Proc: - 'lib/api/api_guard.rb' - 'spec/initializers/trusted_proxies_spec.rb' -# Offense count: 21 +# Offense count: 20 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: compact, exploded @@ -420,7 +410,7 @@ Style/RedundantException: Style/RedundantFreeze: Enabled: false -# Offense count: 312 +# Offense count: 321 # Cop supports --auto-correct. Style/RedundantSelf: Enabled: false @@ -466,7 +456,7 @@ Style/SingleLineMethods: Style/SpaceAroundEqualsInParameterDefault: Enabled: false -# Offense count: 118 +# Offense count: 119 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: space, no_space @@ -494,7 +484,7 @@ Style/SpaceBeforeFirstArg: Style/SpaceInsideBlockBraces: Enabled: false -# Offense count: 92 +# Offense count: 98 # Cop supports --auto-correct. Style/SpaceInsideBrackets: Enabled: false @@ -558,7 +548,7 @@ Style/TrailingUnderscoreVariable: - 'lib/gitlab/force_push_check.rb' - 'lib/gitlab/logger.rb' -# Offense count: 89 +# Offense count: 88 # Cop supports --auto-correct. Style/TrailingWhitespace: Enabled: false From 9468b07925a1ab47fc485bf6baddaf4e89252b08 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Wed, 13 Jul 2016 12:08:45 -0600 Subject: [PATCH 214/335] Resolve feedback. --- .rubocop_todo.yml | 95 +++++++++++++++++++++-------------------------- Gemfile | 2 +- Gemfile.lock | 2 +- 3 files changed, 44 insertions(+), 55 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 8204fd82a63..3478d86f1fa 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config --exclude-limit 8` -# on 2016-07-05 10:30:07 -0600 using RuboCop version 0.41.1. +# on 2016-07-13 12:03:44 -0600 using RuboCop version 0.41.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -10,21 +10,16 @@ Lint/AmbiguousRegexpLiteral: Enabled: false -# Offense count: 42 +# Offense count: 43 # Configuration parameters: AllowSafeAssignment. Lint/AssignmentInCondition: Enabled: false -# Offense count: 1 -Lint/DuplicateMethods: - Exclude: - - 'lib/gitlab/github_import/branch_formatter.rb' - # Offense count: 14 Lint/HandleExceptions: Enabled: false -# Offense count: 20 +# Offense count: 21 Lint/IneffectiveAccessModifier: Enabled: false @@ -34,7 +29,7 @@ Lint/Loop: - 'app/mailers/notify.rb' - 'lib/gitlab/bitbucket_import/client.rb' -# Offense count: 12 +# Offense count: 15 Lint/ShadowingOuterLocalVariable: Enabled: false @@ -46,7 +41,7 @@ Lint/StringConversionInInterpolation: - 'app/services/system_hooks_service.rb' - 'app/services/system_note_service.rb' -# Offense count: 42 +# Offense count: 44 # Cop supports --auto-correct. # Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments. Lint/UnusedBlockArgument: @@ -81,14 +76,13 @@ Performance/RedundantBlockCall: - 'app/controllers/application_controller.rb' - 'lib/gitlab/backend/shell.rb' -# Offense count: 5 +# Offense count: 4 # Cop supports --auto-correct. Performance/RedundantMatch: Exclude: - 'app/models/external_issue.rb' - 'lib/extracts_path.rb' - 'lib/gitlab/diff/highlight.rb' - - 'lib/gitlab/diff/inline_diff.rb' - 'lib/gitlab/diff/parser.rb' # Offense count: 24 @@ -97,11 +91,11 @@ Performance/RedundantMatch: Performance/RedundantMerge: Enabled: false -# Offense count: 59 +# Offense count: 60 Rails/OutputSafety: Enabled: false -# Offense count: 125 +# Offense count: 128 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: strict, flexible Rails/TimeZone: @@ -114,7 +108,7 @@ Rails/TimeZone: Rails/Validation: Enabled: false -# Offense count: 218 +# Offense count: 217 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. # SupportedStyles: with_first_parameter, with_fixed_indentation @@ -135,18 +129,19 @@ Style/AndOr: Style/BarePercentLiterals: Enabled: false -# Offense count: 256 +# Offense count: 258 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: braces, no_braces, context_dependent Style/BracesAroundHashParameters: Enabled: false -# Offense count: 4 +# Offense count: 5 Style/CaseEquality: Exclude: - 'app/helpers/auth_helper.rb' - 'app/models/commit.rb' + - 'app/models/protected_branch.rb' - 'app/services/projects/download_service.rb' - 'config/initializers/trusted_proxies.rb' @@ -165,21 +160,21 @@ Style/CommentAnnotation: - 'lib/api/entities.rb' - 'spec/requests/api/project_snippets_spec.rb' -# Offense count: 35 +# Offense count: 34 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly. # SupportedStyles: assign_to_condition, assign_inside_condition Style/ConditionalAssignment: Enabled: false -# Offense count: 773 +# Offense count: 788 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: leading, trailing Style/DotPosition: Enabled: false -# Offense count: 14 +# Offense count: 13 Style/DoubleNegation: Enabled: false @@ -205,7 +200,7 @@ Style/EmptyLiteral: - 'lib/gitlab/fogbugz_import/importer.rb' - 'spec/lib/gitlab/workhorse_spec.rb' -# Offense count: 119 +# Offense count: 123 # Cop supports --auto-correct. # Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. Style/ExtraSpacing: @@ -223,44 +218,36 @@ Style/FormatString: - 'lib/gitlab/version_info.rb' - 'spec/requests/api/issues_spec.rb' -# Offense count: 50 +# Offense count: 48 # Configuration parameters: MinBodyLength. Style/GuardClause: Enabled: false -# Offense count: 9 -Style/IdenticalConditionalBranches: - Exclude: - - 'app/controllers/projects_controller.rb' - - 'app/models/project_services/irker_service.rb' - - 'app/services/merge_requests/refresh_service.rb' - - 'lib/rouge/formatters/html_gitlab.rb' - -# Offense count: 10 +# Offense count: 11 Style/IfInsideElse: Enabled: false -# Offense count: 179 +# Offense count: 177 # Cop supports --auto-correct. # Configuration parameters: MaxLineLength. Style/IfUnlessModifier: Enabled: false -# Offense count: 48 +# Offense count: 50 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. # SupportedStyles: special_inside_parentheses, consistent, align_brackets Style/IndentArray: Enabled: false -# Offense count: 85 +# Offense count: 89 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. # SupportedStyles: special_inside_parentheses, consistent, align_braces Style/IndentHash: Enabled: false -# Offense count: 11 +# Offense count: 12 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: line_count_dependent, lambda, literal @@ -269,6 +256,7 @@ Style/Lambda: - 'app/models/ci/runner.rb' - 'app/models/event.rb' - 'app/models/note.rb' + - 'app/models/notification_setting.rb' - 'config/routes.rb' - 'lib/api/entities.rb' - 'spec/models/concerns/participable_spec.rb' @@ -299,7 +287,7 @@ Style/MultilineTernaryOperator: - 'lib/banzai/filter/relative_link_filter.rb' - 'spec/support/api_helpers.rb' -# Offense count: 61 +# Offense count: 62 # Cop supports --auto-correct. Style/MutableConstant: Enabled: false @@ -314,14 +302,14 @@ Style/NestedParenthesizedCalls: - 'spec/lib/gitlab/email/message/repository_push_spec.rb' - 'spec/services/ci/create_builds_service_spec.rb' -# Offense count: 13 +# Offense count: 12 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles. # SupportedStyles: skip_modifier_ifs, always Style/Next: Enabled: false -# Offense count: 6 +# Offense count: 8 # Cop supports --auto-correct. # Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles. # SupportedOctalStyles: zero_with_o, zero_only @@ -330,6 +318,7 @@ Style/NumericLiteralPrefix: - 'config/initializers/1_settings.rb' - 'config/initializers/secret_token.rb' - 'lib/gitlab/backend/shell.rb' + - 'spec/lib/gitlab/git/hook_spec.rb' - 'spec/support/test_env.rb' - 'spec/tasks/gitlab/backup_rake_spec.rb' @@ -338,7 +327,7 @@ Style/NumericLiteralPrefix: Style/ParallelAssignment: Enabled: false -# Offense count: 206 +# Offense count: 208 # Cop supports --auto-correct. # Configuration parameters: PreferredDelimiters. Style/PercentLiteralDelimiters: @@ -356,12 +345,12 @@ Style/PercentQLiterals: - 'spec/models/project_services/teamcity_service_spec.rb' - 'spec/workers/repository_import_worker_spec.rb' -# Offense count: 14 +# Offense count: 13 # Cop supports --auto-correct. Style/PerlBackrefs: Enabled: false -# Offense count: 30 +# Offense count: 32 # Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. # NamePrefix: is_, has_, have_ # NamePrefixBlacklist: is_, has_, have_ @@ -369,7 +358,7 @@ Style/PerlBackrefs: Style/PredicateName: Enabled: false -# Offense count: 27 +# Offense count: 28 # Cop supports --auto-correct. Style/PreferredHashMethods: Enabled: false @@ -405,24 +394,24 @@ Style/RedundantException: Exclude: - 'app/helpers/preferences_helper.rb' -# Offense count: 21 +# Offense count: 23 # Cop supports --auto-correct. Style/RedundantFreeze: Enabled: false -# Offense count: 321 +# Offense count: 377 # Cop supports --auto-correct. Style/RedundantSelf: Enabled: false -# Offense count: 92 +# Offense count: 94 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. # SupportedStyles: slashes, percent_r, mixed Style/RegexpLiteral: Enabled: false -# Offense count: 14 +# Offense count: 17 # Cop supports --auto-correct. Style/RescueModifier: Enabled: false @@ -477,7 +466,7 @@ Style/SpaceBeforeFirstArg: - 'spec/services/projects/fork_service_spec.rb' - 'spec/services/system_note_service_spec.rb' -# Offense count: 129 +# Offense count: 130 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. # SupportedStyles: space, no_space @@ -501,7 +490,7 @@ Style/SpaceInsidePercentLiteralDelimiters: - 'lib/event_filter.rb' - 'lib/gitlab/git_access.rb' -# Offense count: 33 +# Offense count: 36 # Cop supports --auto-correct. # Configuration parameters: SupportedStyles. # SupportedStyles: use_perl_names, use_english_names @@ -529,7 +518,7 @@ Style/SymbolProc: Style/TrailingCommaInArguments: Enabled: false -# Offense count: 117 +# Offense count: 114 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyleForMultiline, SupportedStyles. # SupportedStyles: comma, consistent_comma, no_comma @@ -545,10 +534,10 @@ Style/TrailingUnderscoreVariable: - 'app/controllers/invites_controller.rb' - 'app/controllers/projects/git_http_controller.rb' - 'app/helpers/tab_helper.rb' - - 'lib/gitlab/force_push_check.rb' + - 'lib/gitlab/checks/force_push.rb' - 'lib/gitlab/logger.rb' -# Offense count: 88 +# Offense count: 90 # Cop supports --auto-correct. Style/TrailingWhitespace: Enabled: false @@ -570,7 +559,7 @@ Style/UnlessElse: - 'lib/gitlab/backend/grack_auth.rb' - 'lib/gitlab/project_search_results.rb' -# Offense count: 14 +# Offense count: 13 # Cop supports --auto-correct. Style/UnneededInterpolation: Enabled: false @@ -585,4 +574,4 @@ Style/ZeroLengthPredicate: - 'app/models/project_services/asana_service.rb' - 'app/models/repository.rb' - 'lib/extracts_path.rb' - - 'lib/gitlab/force_push_check.rb' + - 'lib/gitlab/checks/force_push.rb' diff --git a/Gemfile b/Gemfile index 0769214a071..7f16e0bd18c 100644 --- a/Gemfile +++ b/Gemfile @@ -299,7 +299,7 @@ group :development, :test do gem 'spring-commands-spinach', '~> 1.1.0' gem 'spring-commands-teaspoon', '~> 0.0.2' - gem 'rubocop', '~> 0.41.1', require: false + gem 'rubocop', '~> 0.41.2', require: false gem 'rubocop-rspec', '~> 1.5.0', require: false gem 'scss_lint', '~> 0.47.0', require: false gem 'simplecov', '~> 0.11.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 6f93a534359..cb3a3af47cd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -937,7 +937,7 @@ DEPENDENCIES rqrcode-rails3 (~> 0.1.7) rspec-rails (~> 3.5.0) rspec-retry (~> 0.4.5) - rubocop (~> 0.41.1) + rubocop (~> 0.41.2) rubocop-rspec (~> 1.5.0) ruby-fogbugz (~> 0.2.1) sanitize (~> 2.0) From bb0cb80879dd8a87886e3e227c0cb5afbefd7daa Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Wed, 13 Jul 2016 08:37:00 -0600 Subject: [PATCH 215/335] Upgrade Rails from 4.2.6 to 4.2.7. Primarily just bug fixes. Changelog: https://github.com/rails/rails/compare/v4.2.6...v4.2.7 --- CHANGELOG | 1 + Gemfile | 2 +- Gemfile.lock | 62 ++++++++++++++++++++++++++-------------------------- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a42f8c7b916..bfcec64da68 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,7 @@ v 8.10.0 (unreleased) - Display last commit of deleted branch in push events !4699 (winniehell) - Escape file extension when parsing search results !5141 (winniehell) - Apply the trusted_proxies config to the rack request object for use with rack_attack + - Upgrade to Rails 4.2.7. !5236 - Add Sidekiq queue duration to transaction metrics. - Add a new column `artifacts_size` to table `ci_builds` !4964 - Let Workhorse serve format-patch diffs diff --git a/Gemfile b/Gemfile index 5c43015e52c..ee23f712f05 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'rails', '4.2.6' +gem 'rails', '4.2.7' gem 'rails-deprecated_sanitizer', '~> 1.0.3' # Responders respond_to and respond_with diff --git a/Gemfile.lock b/Gemfile.lock index f8018e58a5e..67c0645c3d9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,34 +3,34 @@ GEM specs: RedCloth (4.3.2) ace-rails-ap (4.0.2) - actionmailer (4.2.6) - actionpack (= 4.2.6) - actionview (= 4.2.6) - activejob (= 4.2.6) + actionmailer (4.2.7) + actionpack (= 4.2.7) + actionview (= 4.2.7) + activejob (= 4.2.7) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.6) - actionview (= 4.2.6) - activesupport (= 4.2.6) + actionpack (4.2.7) + actionview (= 4.2.7) + activesupport (= 4.2.7) rack (~> 1.6) rack-test (~> 0.6.2) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.6) - activesupport (= 4.2.6) + actionview (4.2.7) + activesupport (= 4.2.7) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - activejob (4.2.6) - activesupport (= 4.2.6) + activejob (4.2.7) + activesupport (= 4.2.7) globalid (>= 0.3.0) - activemodel (4.2.6) - activesupport (= 4.2.6) + activemodel (4.2.7) + activesupport (= 4.2.7) builder (~> 3.1) - activerecord (4.2.6) - activemodel (= 4.2.6) - activesupport (= 4.2.6) + activerecord (4.2.7) + activemodel (= 4.2.7) + activesupport (= 4.2.7) arel (~> 6.0) activerecord-session_store (1.0.0) actionpack (>= 4.0, < 5.1) @@ -38,7 +38,7 @@ GEM multi_json (~> 1.11, >= 1.11.2) rack (>= 1.5.2, < 3) railties (>= 4.0, < 5.1) - activesupport (4.2.6) + activesupport (4.2.7) i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) @@ -515,16 +515,16 @@ GEM rack rack-test (0.6.3) rack (>= 1.0) - rails (4.2.6) - actionmailer (= 4.2.6) - actionpack (= 4.2.6) - actionview (= 4.2.6) - activejob (= 4.2.6) - activemodel (= 4.2.6) - activerecord (= 4.2.6) - activesupport (= 4.2.6) + rails (4.2.7) + actionmailer (= 4.2.7) + actionpack (= 4.2.7) + actionview (= 4.2.7) + activejob (= 4.2.7) + activemodel (= 4.2.7) + activerecord (= 4.2.7) + activesupport (= 4.2.7) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.6) + railties (= 4.2.7) sprockets-rails rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) @@ -534,9 +534,9 @@ GEM rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - railties (4.2.6) - actionpack (= 4.2.6) - activesupport (= 4.2.6) + railties (4.2.7) + actionpack (= 4.2.7) + activesupport (= 4.2.7) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (2.1.0) @@ -697,7 +697,7 @@ GEM spring (>= 0.9.1) spring-commands-teaspoon (0.0.2) spring (>= 0.9.1) - sprockets (3.6.2) + sprockets (3.6.3) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-rails (3.1.1) @@ -920,7 +920,7 @@ DEPENDENCIES rack-attack (~> 4.3.1) rack-cors (~> 0.4.0) rack-oauth2 (~> 1.2.1) - rails (= 4.2.6) + rails (= 4.2.7) rails-deprecated_sanitizer (~> 1.0.3) rainbow (~> 2.1.0) rblineprof (~> 0.3.6) From 82c500a2b69e985cb12ce89964c6ebdd289a0d23 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Wed, 13 Jul 2016 12:39:14 -0600 Subject: [PATCH 216/335] Disable all cops with offenses. --- .rubocop_todo.yml | 183 +++++++++------------------------------------- 1 file changed, 34 insertions(+), 149 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 3478d86f1fa..9310e711889 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by -# `rubocop --auto-gen-config --exclude-limit 8` -# on 2016-07-13 12:03:44 -0600 using RuboCop version 0.41.2. +# `rubocop --auto-gen-config --exclude-limit 0` +# on 2016-07-13 12:36:08 -0600 using RuboCop version 0.41.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -25,9 +25,7 @@ Lint/IneffectiveAccessModifier: # Offense count: 2 Lint/Loop: - Exclude: - - 'app/mailers/notify.rb' - - 'lib/gitlab/bitbucket_import/client.rb' + Enabled: false # Offense count: 15 Lint/ShadowingOuterLocalVariable: @@ -36,10 +34,7 @@ Lint/ShadowingOuterLocalVariable: # Offense count: 3 # Cop supports --auto-correct. Lint/StringConversionInInterpolation: - Exclude: - - 'app/models/commit_range.rb' - - 'app/services/system_hooks_service.rb' - - 'app/services/system_note_service.rb' + Enabled: false # Offense count: 44 # Cop supports --auto-correct. @@ -60,30 +55,17 @@ Lint/UselessAccessModifier: # Offense count: 12 # Cop supports --auto-correct. Performance/PushSplat: - Exclude: - - 'app/controllers/projects/refs_controller.rb' - - 'app/helpers/page_layout_helper.rb' - - 'app/models/ability.rb' - - 'app/models/network/graph.rb' - - 'app/models/project_team.rb' - - 'app/models/user.rb' - - 'config/application.rb' + Enabled: false # Offense count: 2 # Cop supports --auto-correct. Performance/RedundantBlockCall: - Exclude: - - 'app/controllers/application_controller.rb' - - 'lib/gitlab/backend/shell.rb' + Enabled: false # Offense count: 4 # Cop supports --auto-correct. Performance/RedundantMatch: - Exclude: - - 'app/models/external_issue.rb' - - 'lib/extracts_path.rb' - - 'lib/gitlab/diff/highlight.rb' - - 'lib/gitlab/diff/parser.rb' + Enabled: false # Offense count: 24 # Cop supports --auto-correct. @@ -138,12 +120,7 @@ Style/BracesAroundHashParameters: # Offense count: 5 Style/CaseEquality: - Exclude: - - 'app/helpers/auth_helper.rb' - - 'app/models/commit.rb' - - 'app/models/protected_branch.rb' - - 'app/services/projects/download_service.rb' - - 'config/initializers/trusted_proxies.rb' + Enabled: false # Offense count: 19 # Cop supports --auto-correct. @@ -155,10 +132,7 @@ Style/ColonMethodCall: # Configuration parameters: Keywords. # Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW Style/CommentAnnotation: - Exclude: - - 'app/models/project.rb' - - 'lib/api/entities.rb' - - 'spec/requests/api/project_snippets_spec.rb' + Enabled: false # Offense count: 34 # Cop supports --auto-correct. @@ -167,7 +141,7 @@ Style/CommentAnnotation: Style/ConditionalAssignment: Enabled: false -# Offense count: 788 +# Offense count: 789 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: leading, trailing @@ -180,10 +154,7 @@ Style/DoubleNegation: # Offense count: 3 Style/EachWithObject: - Exclude: - - 'app/models/commit_status.rb' - - 'lib/ci/ansi2html.rb' - - 'lib/gitlab/import_export/members_mapper.rb' + Enabled: false # Offense count: 30 # Cop supports --auto-correct. @@ -195,10 +166,7 @@ Style/EmptyElse: # Offense count: 3 # Cop supports --auto-correct. Style/EmptyLiteral: - Exclude: - - 'features/steps/project/commits/commits.rb' - - 'lib/gitlab/fogbugz_import/importer.rb' - - 'spec/lib/gitlab/workhorse_spec.rb' + Enabled: false # Offense count: 123 # Cop supports --auto-correct. @@ -210,13 +178,7 @@ Style/ExtraSpacing: # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: format, sprintf, percent Style/FormatString: - Exclude: - - 'app/models/ci/pipeline.rb' - - 'app/services/gravatar_service.rb' - - 'config/initializers/rack_lineprof.rb' - - 'lib/ci/version_info.rb' - - 'lib/gitlab/version_info.rb' - - 'spec/requests/api/issues_spec.rb' + Enabled: false # Offense count: 48 # Configuration parameters: MinBodyLength. @@ -233,7 +195,7 @@ Style/IfInsideElse: Style/IfUnlessModifier: Enabled: false -# Offense count: 50 +# Offense count: 52 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. # SupportedStyles: special_inside_parentheses, consistent, align_brackets @@ -252,40 +214,21 @@ Style/IndentHash: # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: line_count_dependent, lambda, literal Style/Lambda: - Exclude: - - 'app/models/ci/runner.rb' - - 'app/models/event.rb' - - 'app/models/note.rb' - - 'app/models/notification_setting.rb' - - 'config/routes.rb' - - 'lib/api/entities.rb' - - 'spec/models/concerns/participable_spec.rb' + Enabled: false # Offense count: 6 # Cop supports --auto-correct. Style/LineEndConcatenation: - Exclude: - - 'app/helpers/preferences_helper.rb' - - 'app/helpers/tree_helper.rb' - - 'app/models/merge_request.rb' - - 'app/models/user.rb' - - 'spec/lib/gitlab/gfm/reference_rewriter_spec.rb' + Enabled: false # Offense count: 13 # Cop supports --auto-correct. Style/MethodCallParentheses: - Exclude: - - 'lib/api/helpers.rb' - - 'lib/ci/ansi2html.rb' - - 'spec/features/dashboard/datetime_on_tooltips_spec.rb' - - 'spec/helpers/submodule_helper_spec.rb' - - 'spec/workers/post_receive_spec.rb' + Enabled: false # Offense count: 3 Style/MultilineTernaryOperator: - Exclude: - - 'lib/banzai/filter/relative_link_filter.rb' - - 'spec/support/api_helpers.rb' + Enabled: false # Offense count: 62 # Cop supports --auto-correct. @@ -295,12 +238,7 @@ Style/MutableConstant: # Offense count: 10 # Cop supports --auto-correct. Style/NestedParenthesizedCalls: - Exclude: - - 'app/helpers/commits_helper.rb' - - 'app/workers/irker_worker.rb' - - 'spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb' - - 'spec/lib/gitlab/email/message/repository_push_spec.rb' - - 'spec/services/ci/create_builds_service_spec.rb' + Enabled: false # Offense count: 12 # Cop supports --auto-correct. @@ -314,13 +252,7 @@ Style/Next: # Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles. # SupportedOctalStyles: zero_with_o, zero_only Style/NumericLiteralPrefix: - Exclude: - - 'config/initializers/1_settings.rb' - - 'config/initializers/secret_token.rb' - - 'lib/gitlab/backend/shell.rb' - - 'spec/lib/gitlab/git/hook_spec.rb' - - 'spec/support/test_env.rb' - - 'spec/tasks/gitlab/backup_rake_spec.rb' + Enabled: false # Offense count: 29 # Cop supports --auto-correct. @@ -338,12 +270,7 @@ Style/PercentLiteralDelimiters: # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: lower_case_q, upper_case_q Style/PercentQLiterals: - Exclude: - - 'spec/helpers/gitlab_markdown_helper_spec.rb' - - 'spec/lib/gitlab/diff/highlight_spec.rb' - - 'spec/models/project_services/bamboo_service_spec.rb' - - 'spec/models/project_services/teamcity_service_spec.rb' - - 'spec/workers/repository_import_worker_spec.rb' + Enabled: false # Offense count: 13 # Cop supports --auto-correct. @@ -366,12 +293,7 @@ Style/PreferredHashMethods: # Offense count: 6 # Cop supports --auto-correct. Style/Proc: - Exclude: - - 'app/mailers/base_mailer.rb' - - 'app/models/label.rb' - - 'app/models/service.rb' - - 'lib/api/api_guard.rb' - - 'spec/initializers/trusted_proxies_spec.rb' + Enabled: false # Offense count: 20 # Cop supports --auto-correct. @@ -383,16 +305,12 @@ Style/RaiseArgs: # Offense count: 3 # Cop supports --auto-correct. Style/RedundantBegin: - Exclude: - - 'app/models/ci/build.rb' - - 'app/models/merge_request.rb' - - 'app/services/projects/import_service.rb' + Enabled: false # Offense count: 1 # Cop supports --auto-correct. Style/RedundantException: - Exclude: - - 'app/helpers/preferences_helper.rb' + Enabled: false # Offense count: 23 # Cop supports --auto-correct. @@ -419,24 +337,19 @@ Style/RescueModifier: # Offense count: 2 # Cop supports --auto-correct. Style/SelfAssignment: - Exclude: - - 'app/services/notification_service.rb' - - 'lib/api/runners.rb' + Enabled: false # Offense count: 2 # Configuration parameters: Methods. # Methods: {"reduce"=>["a", "e"]}, {"inject"=>["a", "e"]} Style/SingleLineBlockParams: - Exclude: - - 'app/models/commit.rb' - - 'spec/support/services_shared_context.rb' + Enabled: false # Offense count: 50 # Cop supports --auto-correct. # Configuration parameters: AllowIfMethodIsEmpty. Style/SingleLineMethods: - Exclude: - - 'lib/ci/ansi2html.rb' + Enabled: false # Offense count: 14 # Cop supports --auto-correct. @@ -456,15 +369,7 @@ Style/SpaceBeforeBlockBraces: # Cop supports --auto-correct. # Configuration parameters: AllowForAlignment. Style/SpaceBeforeFirstArg: - Exclude: - - 'config/initializers/doorkeeper.rb' - - 'config/routes.rb' - - 'features/steps/project/source/browse_files.rb' - - 'features/steps/project/source/markdown_render.rb' - - 'spec/routing/project_routing_spec.rb' - - 'spec/services/delete_user_service_spec.rb' - - 'spec/services/projects/fork_service_spec.rb' - - 'spec/services/system_note_service_spec.rb' + Enabled: false # Offense count: 130 # Cop supports --auto-correct. @@ -486,9 +391,7 @@ Style/SpaceInsideParens: # Offense count: 5 # Cop supports --auto-correct. Style/SpaceInsidePercentLiteralDelimiters: - Exclude: - - 'lib/event_filter.rb' - - 'lib/gitlab/git_access.rb' + Enabled: false # Offense count: 36 # Cop supports --auto-correct. @@ -518,7 +421,7 @@ Style/SymbolProc: Style/TrailingCommaInArguments: Enabled: false -# Offense count: 114 +# Offense count: 113 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyleForMultiline, SupportedStyles. # SupportedStyles: comma, consistent_comma, no_comma @@ -529,13 +432,7 @@ Style/TrailingCommaInLiteral: # Cop supports --auto-correct. # Configuration parameters: AllowNamedUnderscoreVariables. Style/TrailingUnderscoreVariable: - Exclude: - - 'app/controllers/admin/background_jobs_controller.rb' - - 'app/controllers/invites_controller.rb' - - 'app/controllers/projects/git_http_controller.rb' - - 'app/helpers/tab_helper.rb' - - 'lib/gitlab/checks/force_push.rb' - - 'lib/gitlab/logger.rb' + Enabled: false # Offense count: 90 # Cop supports --auto-correct. @@ -547,17 +444,12 @@ Style/TrailingWhitespace: # Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist. # Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym Style/TrivialAccessors: - Exclude: - - 'app/models/external_issue.rb' - - 'lib/gitlab/ldap/person.rb' + Enabled: false # Offense count: 3 # Cop supports --auto-correct. Style/UnlessElse: - Exclude: - - 'lib/api/projects.rb' - - 'lib/gitlab/backend/grack_auth.rb' - - 'lib/gitlab/project_search_results.rb' + Enabled: false # Offense count: 13 # Cop supports --auto-correct. @@ -567,11 +459,4 @@ Style/UnneededInterpolation: # Offense count: 8 # Cop supports --auto-correct. Style/ZeroLengthPredicate: - Exclude: - - 'app/models/deploy_key.rb' - - 'app/models/network/commit.rb' - - 'app/models/network/graph.rb' - - 'app/models/project_services/asana_service.rb' - - 'app/models/repository.rb' - - 'lib/extracts_path.rb' - - 'lib/gitlab/checks/force_push.rb' + Enabled: false From 530f5158e297f3cde27f3566cfe13bad74ba3b50 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 13 Jul 2016 13:57:30 -0500 Subject: [PATCH 217/335] Revert "Merge branch '18193-developers-can-merge' into 'master' " This reverts commit 9ca633eb4c62231e4ddff5466c723cf8e2bdb25d, reversing changes made to fb229bbf7970ba908962b837b270adf56f14098f. --- CHANGELOG | 1 - .../javascripts/protected_branches.js.coffee | 8 +- .../projects/protected_branches_controller.rb | 2 +- app/helpers/branches_helper.rb | 2 +- app/models/merge_request.rb | 8 +- app/models/project.rb | 4 - app/models/repository.rb | 14 +- app/services/commits/change_service.rb | 4 +- app/services/files/base_service.rb | 2 +- app/services/git_push_service.rb | 3 +- app/services/merge_requests/merge_service.rb | 4 +- .../merge_requests/refresh_service.rb | 2 +- .../widget/open/_conflicts.html.haml | 2 +- .../_branches_list.html.haml | 2 - .../_protected_branch.html.haml | 2 - .../protected_branches/index.html.haml | 8 - ...elopers_can_merge_to_protected_branches.rb | 9 - ...ress_merge_commit_sha_to_merge_requests.rb | 8 - db/schema.rb | 8 +- lib/api/helpers.rb | 2 +- lib/gitlab/access.rb | 8 +- lib/gitlab/checks/change_access.rb | 96 ------- lib/gitlab/checks/force_push.rb | 17 -- lib/gitlab/checks/matching_merge_request.rb | 18 -- lib/gitlab/force_push_check.rb | 15 ++ lib/gitlab/git_access.rb | 151 ++++++++--- lib/gitlab/git_access_wiki.rb | 2 +- lib/gitlab/user_access.rb | 48 +--- spec/lib/gitlab/diff/position_tracer_spec.rb | 3 +- spec/lib/gitlab/git_access_spec.rb | 247 ++++++++++-------- spec/lib/gitlab/user_access_spec.rb | 88 ------- spec/models/repository_spec.rb | 9 +- spec/requests/api/api_helpers_spec.rb | 4 +- spec/services/git_push_service_spec.rb | 14 +- .../merge_requests/refresh_service_spec.rb | 3 +- 35 files changed, 307 insertions(+), 511 deletions(-) delete mode 100644 db/migrate/20160519203051_add_developers_can_merge_to_protected_branches.rb delete mode 100644 db/migrate/20160629025435_add_column_in_progress_merge_commit_sha_to_merge_requests.rb delete mode 100644 lib/gitlab/checks/change_access.rb delete mode 100644 lib/gitlab/checks/force_push.rb delete mode 100644 lib/gitlab/checks/matching_merge_request.rb create mode 100644 lib/gitlab/force_push_check.rb delete mode 100644 spec/lib/gitlab/user_access_spec.rb diff --git a/CHANGELOG b/CHANGELOG index a42f8c7b916..71987a4a695 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -44,7 +44,6 @@ v 8.10.0 (unreleased) - Add "Enabled Git access protocols" to Application Settings - Diffs will create button/diff form on demand no on server side - Reduce size of HTML used by diff comment forms - - Protected branches have a "Developers can Merge" setting. !4892 (original implementation by Mathias Vestergaard) - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - Only show New Snippet button to users that can create snippets. - PipelinesFinder uses git cache data diff --git a/app/assets/javascripts/protected_branches.js.coffee b/app/assets/javascripts/protected_branches.js.coffee index 14afef2e2ee..79c2306e4d2 100644 --- a/app/assets/javascripts/protected_branches.js.coffee +++ b/app/assets/javascripts/protected_branches.js.coffee @@ -1,18 +1,18 @@ $ -> $(".protected-branches-list :checkbox").change (e) -> name = $(this).attr("name") - if name == "developers_can_push" || name == "developers_can_merge" + if name == "developers_can_push" id = $(this).val() - can_push = $(this).is(":checked") + checked = $(this).is(":checked") url = $(this).data("url") $.ajax - type: "PATCH" + type: "PUT" url: url dataType: "json" data: id: id protected_branch: - "#{name}": can_push + developers_can_push: checked success: -> row = $(e.target) diff --git a/app/controllers/projects/protected_branches_controller.rb b/app/controllers/projects/protected_branches_controller.rb index 10dca47fded..80dad758afa 100644 --- a/app/controllers/projects/protected_branches_controller.rb +++ b/app/controllers/projects/protected_branches_controller.rb @@ -50,6 +50,6 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController end def protected_branch_params - params.require(:protected_branch).permit(:name, :developers_can_push, :developers_can_merge) + params.require(:protected_branch).permit(:name, :developers_can_push) end end diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb index bfd23aa4e04..601df5c18df 100644 --- a/app/helpers/branches_helper.rb +++ b/app/helpers/branches_helper.rb @@ -12,7 +12,7 @@ module BranchesHelper def can_push_branch?(project, branch_name) return false unless project.repository.branch_exists?(branch_name) - ::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(branch_name) + ::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(branch_name) end def project_branches diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 471e32f3b60..157901378d3 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -552,13 +552,7 @@ class MergeRequest < ActiveRecord::Base end def can_be_merged_by?(user) - access = ::Gitlab::UserAccess.new(user, project: project) - access.can_push_to_branch?(target_branch) || access.can_merge_to_branch?(target_branch) - end - - def can_be_merged_via_command_line_by?(user) - access = ::Gitlab::UserAccess.new(user, project: project) - access.can_push_to_branch?(target_branch) + ::Gitlab::GitAccess.new(user, project, 'web').can_push_to_branch?(target_branch) end def mergeable_ci_state? diff --git a/app/models/project.rb b/app/models/project.rb index 2bd97fc48f1..a66b750cd48 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -832,10 +832,6 @@ class Project < ActiveRecord::Base protected_branches.matching(branch_name).any?(&:developers_can_push) end - def developers_can_merge_to_protected_branch?(branch_name) - protected_branches.matching(branch_name).any?(&:developers_can_merge) - end - def forked? !(forked_project_link.nil? || forked_project_link.forked_from_project.nil?) end diff --git a/app/models/repository.rb b/app/models/repository.rb index 09487b62f98..5b670cb4b8f 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -769,9 +769,9 @@ class Repository end end - def merge(user, merge_request, options = {}) - our_commit = rugged.branches[merge_request.target_branch].target - their_commit = rugged.lookup(merge_request.diff_head_sha) + def merge(user, source_sha, target_branch, options = {}) + our_commit = rugged.branches[target_branch].target + their_commit = rugged.lookup(source_sha) raise "Invalid merge target" if our_commit.nil? raise "Invalid merge source" if their_commit.nil? @@ -779,16 +779,14 @@ class Repository merge_index = rugged.merge_commits(our_commit, their_commit) return false if merge_index.conflicts? - commit_with_hooks(user, merge_request.target_branch) do |tmp_ref| + commit_with_hooks(user, target_branch) do |ref| actual_options = options.merge( parents: [our_commit, their_commit], tree: merge_index.write_tree(rugged), - update_ref: tmp_ref + update_ref: ref ) - commit_id = Rugged::Commit.create(rugged, actual_options) - merge_request.update(in_progress_merge_commit_sha: commit_id) - commit_id + Rugged::Commit.create(rugged, actual_options) end end diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index ed73d8cb8c2..c578097376a 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -23,7 +23,7 @@ module Commits private def check_push_permissions - allowed = ::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(@target_branch) + allowed = ::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(@target_branch) unless allowed raise ValidationError.new('You are not allowed to push into this branch') @@ -31,7 +31,7 @@ module Commits true end - + def create_target_branch(new_branch) # Temporary branch exists and contains the change commit return success if repository.find_branch(new_branch) diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 55da949f56a..37c5e321b39 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -42,7 +42,7 @@ module Files end def validate - allowed = ::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(@target_branch) + allowed = ::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(@target_branch) unless allowed raise_error("You are not allowed to push into this branch") diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index e02b50ff9a2..a886f35981f 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -89,8 +89,7 @@ class GitPushService < BaseService # Set protection on the default branch if configured if current_application_settings.default_branch_protection != PROTECTION_NONE developers_can_push = current_application_settings.default_branch_protection == PROTECTION_DEV_CAN_PUSH ? true : false - developers_can_merge = current_application_settings.default_branch_protection == PROTECTION_DEV_CAN_MERGE ? true : false - @project.protected_branches.create({ name: @project.default_branch, developers_can_push: developers_can_push, developers_can_merge: developers_can_merge }) + @project.protected_branches.create({ name: @project.default_branch, developers_can_push: developers_can_push }) end end diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 0dac0614141..f1b1d90c457 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -34,7 +34,7 @@ module MergeRequests committer: committer } - commit_id = repository.merge(current_user, merge_request, options) + commit_id = repository.merge(current_user, merge_request.diff_head_sha, merge_request.target_branch, options) merge_request.update(merge_commit_sha: commit_id) rescue GitHooksService::PreReceiveError => e merge_request.update(merge_error: e.message) @@ -43,8 +43,6 @@ module MergeRequests merge_request.update(merge_error: "Something went wrong during merge") Rails.logger.error(e.message) false - ensure - merge_request.update(in_progress_merge_commit_sha: nil) end def after_merge diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb index 1daf6bbf553..b11ecd97a57 100644 --- a/app/services/merge_requests/refresh_service.rb +++ b/app/services/merge_requests/refresh_service.rb @@ -48,7 +48,7 @@ module MergeRequests end def force_push? - Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev) + Gitlab::ForcePushCheck.force_push?(@project, @oldrev, @newrev) end # Refresh merge request diff if we push to source or target branch of merge request diff --git a/app/views/projects/merge_requests/widget/open/_conflicts.html.haml b/app/views/projects/merge_requests/widget/open/_conflicts.html.haml index f000cc38a65..06ab0a3fa00 100644 --- a/app/views/projects/merge_requests/widget/open/_conflicts.html.haml +++ b/app/views/projects/merge_requests/widget/open/_conflicts.html.haml @@ -4,7 +4,7 @@ %p Please resolve these conflicts or - - if @merge_request.can_be_merged_via_command_line_by?(current_user) + - if @merge_request.can_be_merged_by?(current_user) #{link_to "merge this request manually", "#modal_merge_info", class: "how_to_merge_link vlink", "data-toggle" => "modal"}. - else ask someone with write access to this repository to merge this request manually. diff --git a/app/views/projects/protected_branches/_branches_list.html.haml b/app/views/projects/protected_branches/_branches_list.html.haml index 720d67dff7c..97cb1a9052b 100644 --- a/app/views/projects/protected_branches/_branches_list.html.haml +++ b/app/views/projects/protected_branches/_branches_list.html.haml @@ -8,7 +8,6 @@ .table-responsive %table.table.protected-branches-list %colgroup - %col{ width: "20%" } %col{ width: "30%" } %col{ width: "25%" } %col{ width: "25%" } @@ -19,7 +18,6 @@ %th Protected Branch %th Commit %th Developers Can Push - %th Developers Can Merge - if can_admin_project %th %tbody diff --git a/app/views/projects/protected_branches/_protected_branch.html.haml b/app/views/projects/protected_branches/_protected_branch.html.haml index 7fda7f96047..474aec3a97c 100644 --- a/app/views/projects/protected_branches/_protected_branch.html.haml +++ b/app/views/projects/protected_branches/_protected_branch.html.haml @@ -16,8 +16,6 @@ (branch was removed from repository) %td = check_box_tag("developers_can_push", protected_branch.id, protected_branch.developers_can_push, data: { url: url }) - %td - = check_box_tag("developers_can_merge", protected_branch.id, protected_branch.developers_can_merge, data: { url: url }) - if can_admin_project %td = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, protected_branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-warning btn-sm pull-right" diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml index 101b3f3b452..3fab95751e0 100644 --- a/app/views/projects/protected_branches/index.html.haml +++ b/app/views/projects/protected_branches/index.html.haml @@ -36,14 +36,6 @@ = f.label :developers_can_push, "Developers can push", class: "label-light append-bottom-0" %p.light.append-bottom-0 Allow developers to push to this branch - - .form-group - = f.check_box :developers_can_merge, class: "pull-left" - .prepend-left-20 - = f.label :developers_can_merge, "Developers can merge", class: "label-light append-bottom-0" - %p.light.append-bottom-0 - Allow developers to accept merge requests to this branch = f.submit "Protect", class: "btn-create btn protect-branch-btn", disabled: true - %hr = render "branches_list" diff --git a/db/migrate/20160519203051_add_developers_can_merge_to_protected_branches.rb b/db/migrate/20160519203051_add_developers_can_merge_to_protected_branches.rb deleted file mode 100644 index 15ad8e8bcbb..00000000000 --- a/db/migrate/20160519203051_add_developers_can_merge_to_protected_branches.rb +++ /dev/null @@ -1,9 +0,0 @@ -class AddDevelopersCanMergeToProtectedBranches < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - - disable_ddl_transaction! - - def change - add_column_with_default :protected_branches, :developers_can_merge, :boolean, default: false, allow_null: false - end -end diff --git a/db/migrate/20160629025435_add_column_in_progress_merge_commit_sha_to_merge_requests.rb b/db/migrate/20160629025435_add_column_in_progress_merge_commit_sha_to_merge_requests.rb deleted file mode 100644 index 7c5f76572ef..00000000000 --- a/db/migrate/20160629025435_add_column_in_progress_merge_commit_sha_to_merge_requests.rb +++ /dev/null @@ -1,8 +0,0 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - -class AddColumnInProgressMergeCommitShaToMergeRequests < ActiveRecord::Migration - def change - add_column :merge_requests, :in_progress_merge_commit_sha, :string - end -end diff --git a/db/schema.rb b/db/schema.rb index 64019cf79bb..f24e47b85b2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -626,7 +626,6 @@ ActiveRecord::Schema.define(version: 20160712171823) do t.string "merge_commit_sha" t.datetime "deleted_at" t.integer "lock_version", default: 0, null: false - t.string "in_progress_merge_commit_sha" end add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree @@ -861,12 +860,11 @@ ActiveRecord::Schema.define(version: 20160712171823) do add_index "projects", ["visibility_level"], name: "index_projects_on_visibility_level", using: :btree create_table "protected_branches", force: :cascade do |t| - t.integer "project_id", null: false - t.string "name", null: false + t.integer "project_id", null: false + t.string "name", null: false t.datetime "created_at" t.datetime "updated_at" - t.boolean "developers_can_push", default: false, null: false - t.boolean "developers_can_merge", default: false, null: false + t.boolean "developers_can_push", default: false, null: false end add_index "protected_branches", ["project_id"], name: "index_protected_branches_on_project_id", using: :btree diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 73557cf7db6..77e407b54c5 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -17,7 +17,7 @@ module API def current_user @current_user ||= (find_user_by_private_token || doorkeeper_guard) - unless @current_user && Gitlab::UserAccess.new(@current_user).allowed? + unless @current_user && Gitlab::UserAccess.allowed?(@current_user) return nil end diff --git a/lib/gitlab/access.rb b/lib/gitlab/access.rb index de41ea415a6..831f1e635ba 100644 --- a/lib/gitlab/access.rb +++ b/lib/gitlab/access.rb @@ -14,10 +14,9 @@ module Gitlab OWNER = 50 # Branch protection settings - PROTECTION_NONE = 0 - PROTECTION_DEV_CAN_PUSH = 1 - PROTECTION_FULL = 2 - PROTECTION_DEV_CAN_MERGE = 3 + PROTECTION_NONE = 0 + PROTECTION_DEV_CAN_PUSH = 1 + PROTECTION_FULL = 2 class << self def values @@ -55,7 +54,6 @@ module Gitlab def protection_options { "Not protected: Both developers and masters can push new commits, force push, or delete the branch." => PROTECTION_NONE, - "Protected against pushes: Developers cannot push new commits, but are allowed to accept merge requests to the branch." => PROTECTION_DEV_CAN_MERGE, "Partially protected: Developers can push new commits, but cannot force push or delete the branch. Masters can do all of those." => PROTECTION_DEV_CAN_PUSH, "Fully protected: Developers cannot push new commits, force push, or delete the branch. Only masters can do any of those." => PROTECTION_FULL, } diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb deleted file mode 100644 index 5551fac4b8b..00000000000 --- a/lib/gitlab/checks/change_access.rb +++ /dev/null @@ -1,96 +0,0 @@ -module Gitlab - module Checks - class ChangeAccess - attr_reader :user_access, :project - - def initialize(change, user_access:, project:) - @oldrev, @newrev, @ref = change.split(' ') - @branch_name = branch_name(@ref) - @user_access = user_access - @project = project - end - - def exec - error = protected_branch_checks || tag_checks || push_checks - - if error - GitAccessStatus.new(false, error) - else - GitAccessStatus.new(true) - end - end - - protected - - def protected_branch_checks - return unless project.protected_branch?(@branch_name) - - if forced_push? && user_access.cannot_do_action?(:force_push_code_to_protected_branches) - return "You are not allowed to force push code to a protected branch on this project." - elsif Gitlab::Git.blank_ref?(@newrev) && user_access.cannot_do_action?(:remove_protected_branches) - return "You are not allowed to delete protected branches from this project." - end - - if matching_merge_request? - if user_access.can_merge_to_branch?(@branch_name) || user_access.can_push_to_branch?(@branch_name) - return - else - "You are not allowed to merge code into protected branches on this project." - end - else - if user_access.can_push_to_branch?(@branch_name) - return - else - "You are not allowed to push code to protected branches on this project." - end - end - end - - def tag_checks - tag_ref = tag_name(@ref) - - if tag_ref && protected_tag?(tag_ref) && user_access.cannot_do_action?(:admin_project) - "You are not allowed to change existing tags on this project." - end - end - - def push_checks - if user_access.cannot_do_action?(:push_code) - "You are not allowed to push code to this project." - end - end - - private - - def protected_tag?(tag_name) - project.repository.tag_exists?(tag_name) - end - - def forced_push? - Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev) - end - - def matching_merge_request? - Checks::MatchingMergeRequest.new(@newrev, @branch_name, @project).match? - end - - def branch_name(ref) - ref = @ref.to_s - if Gitlab::Git.branch_ref?(ref) - Gitlab::Git.ref_name(ref) - else - nil - end - end - - def tag_name(ref) - ref = @ref.to_s - if Gitlab::Git.tag_ref?(ref) - Gitlab::Git.ref_name(ref) - else - nil - end - end - end - end -end diff --git a/lib/gitlab/checks/force_push.rb b/lib/gitlab/checks/force_push.rb deleted file mode 100644 index dfa83a0eab3..00000000000 --- a/lib/gitlab/checks/force_push.rb +++ /dev/null @@ -1,17 +0,0 @@ -module Gitlab - module Checks - class ForcePush - def self.force_push?(project, oldrev, newrev) - return false if project.empty_repo? - - # Created or deleted branch - if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev) - false - else - missed_refs, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev})) - missed_refs.split("\n").size > 0 - end - end - end - end -end diff --git a/lib/gitlab/checks/matching_merge_request.rb b/lib/gitlab/checks/matching_merge_request.rb deleted file mode 100644 index 849848515da..00000000000 --- a/lib/gitlab/checks/matching_merge_request.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Gitlab - module Checks - class MatchingMergeRequest - def initialize(newrev, branch_name, project) - @newrev = newrev - @branch_name = branch_name - @project = project - end - - def match? - @project.merge_requests - .with_state(:locked) - .where(in_progress_merge_commit_sha: @newrev, target_branch: @branch_name) - .exists? - end - end - end -end diff --git a/lib/gitlab/force_push_check.rb b/lib/gitlab/force_push_check.rb new file mode 100644 index 00000000000..93c6a5bb7f5 --- /dev/null +++ b/lib/gitlab/force_push_check.rb @@ -0,0 +1,15 @@ +module Gitlab + class ForcePushCheck + def self.force_push?(project, oldrev, newrev) + return false if project.empty_repo? + + # Created or deleted branch + if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev) + false + else + missed_refs, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev})) + missed_refs.split("\n").size > 0 + end + end + end +end diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index 308f23bc9bc..7679c7e4bb8 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -1,17 +1,52 @@ -# Check a user's access to perform a git action. All public methods in this -# class return an instance of `GitlabAccessStatus` module Gitlab class GitAccess DOWNLOAD_COMMANDS = %w{ git-upload-pack git-upload-archive } PUSH_COMMANDS = %w{ git-receive-pack } - attr_reader :actor, :project, :protocol, :user_access + attr_reader :actor, :project, :protocol def initialize(actor, project, protocol) @actor = actor @project = project @protocol = protocol - @user_access = UserAccess.new(user, project: project) + end + + def user + return @user if defined?(@user) + + @user = + case actor + when User + actor + when DeployKey + nil + when Key + actor.user + end + end + + def deploy_key + actor if actor.is_a?(DeployKey) + end + + def can_push_to_branch?(ref) + return false unless user + + if project.protected_branch?(ref) && !project.developers_can_push_to_protected_branch?(ref) + user.can?(:push_code_to_protected_branches, project) + else + user.can?(:push_code, project) + end + end + + def can_read_project? + if user + user.can?(:read_project, project) + elsif deploy_key + deploy_key.projects.include?(project) + else + false + end end def check(cmd, changes = nil) @@ -21,11 +56,11 @@ module Gitlab return build_status_object(false, "No user or key was provided.") end - if user && !user_access.allowed? + if user && !user_allowed? return build_status_object(false, "Your account has been blocked.") end - unless project && (user_access.can_read_project? || deploy_key_can_read_project?) + unless project && can_read_project? return build_status_object(false, 'The project you were looking for could not be found.') end @@ -60,7 +95,7 @@ module Gitlab end def user_download_access_check - unless user_access.can_do_action?(:download_code) + unless user.can?(:download_code, project) return build_status_object(false, "You are not allowed to download code from this project.") end @@ -90,8 +125,46 @@ module Gitlab build_status_object(true) end + def can_user_do_action?(action) + @permission_cache ||= {} + @permission_cache[action] ||= user.can?(action, project) + end + def change_access_check(change) - Checks::ChangeAccess.new(change, user_access: user_access, project: project).exec + oldrev, newrev, ref = change.split(' ') + + action = + if project.protected_branch?(branch_name(ref)) + protected_branch_action(oldrev, newrev, branch_name(ref)) + elsif (tag_ref = tag_name(ref)) && protected_tag?(tag_ref) + # Prevent any changes to existing git tag unless user has permissions + :admin_project + else + :push_code + end + + unless can_user_do_action?(action) + status = + case action + when :force_push_code_to_protected_branches + build_status_object(false, "You are not allowed to force push code to a protected branch on this project.") + when :remove_protected_branches + build_status_object(false, "You are not allowed to deleted protected branches from this project.") + when :push_code_to_protected_branches + build_status_object(false, "You are not allowed to push code to protected branches on this project.") + when :admin_project + build_status_object(false, "You are not allowed to change existing tags on this project.") + else # :push_code + build_status_object(false, "You are not allowed to push code to this project.") + end + return status + end + + build_status_object(true) + end + + def forced_push?(oldrev, newrev) + Gitlab::ForcePushCheck.force_push?(project, oldrev, newrev) end def protocol_allowed? @@ -100,38 +173,48 @@ module Gitlab private - def matching_merge_request?(newrev, branch_name) - Checks::MatchingMergeRequest.new(newrev, branch_name, project).match? - end - - def deploy_key - actor if actor.is_a?(DeployKey) - end - - def deploy_key_can_read_project? - if deploy_key - deploy_key.projects.include?(project) + def protected_branch_action(oldrev, newrev, branch_name) + # we dont allow force push to protected branch + if forced_push?(oldrev, newrev) + :force_push_code_to_protected_branches + elsif Gitlab::Git.blank_ref?(newrev) + # and we dont allow remove of protected branch + :remove_protected_branches + elsif project.developers_can_push_to_protected_branch?(branch_name) + :push_code else - false + :push_code_to_protected_branches + end + end + + def protected_tag?(tag_name) + project.repository.tag_exists?(tag_name) + end + + def user_allowed? + Gitlab::UserAccess.allowed?(user) + end + + def branch_name(ref) + ref = ref.to_s + if Gitlab::Git.branch_ref?(ref) + Gitlab::Git.ref_name(ref) + else + nil + end + end + + def tag_name(ref) + ref = ref.to_s + if Gitlab::Git.tag_ref?(ref) + Gitlab::Git.ref_name(ref) + else + nil end end protected - def user - return @user if defined?(@user) - - @user = - case actor - when User - actor - when DeployKey - nil - when Key - actor.user - end - end - def build_status_object(status, message = '') GitAccessStatus.new(status, message) end diff --git a/lib/gitlab/git_access_wiki.rb b/lib/gitlab/git_access_wiki.rb index f71d3575909..8672cbc0ec4 100644 --- a/lib/gitlab/git_access_wiki.rb +++ b/lib/gitlab/git_access_wiki.rb @@ -1,7 +1,7 @@ module Gitlab class GitAccessWiki < GitAccess def change_access_check(change) - if user_access.can_do_action?(:create_wiki) + if user.can?(:create_wiki, project) build_status_object(true) else build_status_object(false, "You are not allowed to write to this project's wiki.") diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb index c0f85e9b3a8..d1b42c1f9b9 100644 --- a/lib/gitlab/user_access.rb +++ b/lib/gitlab/user_access.rb @@ -1,23 +1,7 @@ module Gitlab - class UserAccess - attr_reader :user, :project - - def initialize(user, project: nil) - @user = user - @project = project - end - - def can_do_action?(action) - @permission_cache ||= {} - @permission_cache[action] ||= user.can?(action, project) - end - - def cannot_do_action?(action) - !can_do_action?(action) - end - - def allowed? - return false if user.blank? || user.blocked? + module UserAccess + def self.allowed?(user) + return false if user.blocked? if user.requires_ldap_check? && user.try_obtain_ldap_lease return false unless Gitlab::LDAP::Access.allowed?(user) @@ -25,31 +9,5 @@ module Gitlab true end - - def can_push_to_branch?(ref) - return false unless user - - if project.protected_branch?(ref) && !project.developers_can_push_to_protected_branch?(ref) - user.can?(:push_code_to_protected_branches, project) - else - user.can?(:push_code, project) - end - end - - def can_merge_to_branch?(ref) - return false unless user - - if project.protected_branch?(ref) && !project.developers_can_merge_to_protected_branch?(ref) - user.can?(:push_code_to_protected_branches, project) - else - user.can?(:push_code, project) - end - end - - def can_read_project? - return false unless user - - user.can?(:read_project, project) - end end end diff --git a/spec/lib/gitlab/diff/position_tracer_spec.rb b/spec/lib/gitlab/diff/position_tracer_spec.rb index c268f84c759..08312e60f4a 100644 --- a/spec/lib/gitlab/diff/position_tracer_spec.rb +++ b/spec/lib/gitlab/diff/position_tracer_spec.rb @@ -1639,8 +1639,7 @@ describe Gitlab::Diff::PositionTracer, lib: true do committer: committer } - merge_request = create(:merge_request, source_branch: second_create_file_commit.sha, target_branch: branch_name, source_project: project) - repository.merge(current_user, merge_request, options) + repository.merge(current_user, second_create_file_commit.sha, branch_name, options) project.commit(branch_name) end diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index db33c7a22bb..c79ba11f782 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -6,6 +6,67 @@ describe Gitlab::GitAccess, lib: true do let(:user) { create(:user) } let(:actor) { user } + describe 'can_push_to_branch?' do + describe 'push to none protected branch' do + it "returns true if user is a master" do + project.team << [user, :master] + expect(access.can_push_to_branch?("random_branch")).to be_truthy + end + + it "returns true if user is a developer" do + project.team << [user, :developer] + expect(access.can_push_to_branch?("random_branch")).to be_truthy + end + + it "returns false if user is a reporter" do + project.team << [user, :reporter] + expect(access.can_push_to_branch?("random_branch")).to be_falsey + end + end + + describe 'push to protected branch' do + before do + @branch = create :protected_branch, project: project + end + + it "returns true if user is a master" do + project.team << [user, :master] + expect(access.can_push_to_branch?(@branch.name)).to be_truthy + end + + it "returns false if user is a developer" do + project.team << [user, :developer] + expect(access.can_push_to_branch?(@branch.name)).to be_falsey + end + + it "returns false if user is a reporter" do + project.team << [user, :reporter] + expect(access.can_push_to_branch?(@branch.name)).to be_falsey + end + end + + describe 'push to protected branch if allowed for developers' do + before do + @branch = create :protected_branch, project: project, developers_can_push: true + end + + it "returns true if user is a master" do + project.team << [user, :master] + expect(access.can_push_to_branch?(@branch.name)).to be_truthy + end + + it "returns true if user is a developer" do + project.team << [user, :developer] + expect(access.can_push_to_branch?(@branch.name)).to be_truthy + end + + it "returns false if user is a reporter" do + project.team << [user, :reporter] + expect(access.can_push_to_branch?(@branch.name)).to be_falsey + end + end + end + describe '#check with single protocols allowed' do def disable_protocol(protocol) settings = ::ApplicationSetting.create_from_defaults @@ -99,46 +160,96 @@ describe Gitlab::GitAccess, lib: true do end describe 'push_access_check' do - before { merge_into_protected_branch } - let(:unprotected_branch) { FFaker::Internet.user_name } + def protect_feature_branch + create(:protected_branch, name: 'feature', project: project) + end - let(:changes) do - { push_new_branch: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow", + def changes + { + push_new_branch: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow", push_master: '6f6d7e7ed 570e7b2ab refs/heads/master', push_protected_branch: '6f6d7e7ed 570e7b2ab refs/heads/feature', push_remove_protected_branch: "570e7b2ab #{Gitlab::Git::BLANK_SHA} "\ 'refs/heads/feature', push_tag: '6f6d7e7ed 570e7b2ab refs/tags/v1.0.0', push_new_tag: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/tags/v7.8.9", - push_all: ['6f6d7e7ed 570e7b2ab refs/heads/master', '6f6d7e7ed 570e7b2ab refs/heads/feature'], - merge_into_protected_branch: "0b4bc9a #{merge_into_protected_branch} refs/heads/feature" } + push_all: ['6f6d7e7ed 570e7b2ab refs/heads/master', '6f6d7e7ed 570e7b2ab refs/heads/feature'] + } end - def stub_git_hooks - # Running the `pre-receive` hook is expensive, and not necessary for this test. - allow_any_instance_of(GitHooksService).to receive(:execute).and_yield + def self.permissions_matrix + { + master: { + push_new_branch: true, + push_master: true, + push_protected_branch: true, + push_remove_protected_branch: false, + push_tag: true, + push_new_tag: true, + push_all: true, + }, + + developer: { + push_new_branch: true, + push_master: true, + push_protected_branch: false, + push_remove_protected_branch: false, + push_tag: false, + push_new_tag: true, + push_all: false, + }, + + reporter: { + push_new_branch: false, + push_master: false, + push_protected_branch: false, + push_remove_protected_branch: false, + push_tag: false, + push_new_tag: false, + push_all: false, + }, + + guest: { + push_new_branch: false, + push_master: false, + push_protected_branch: false, + push_remove_protected_branch: false, + push_tag: false, + push_new_tag: false, + push_all: false, + } + } end - def merge_into_protected_branch - @protected_branch_merge_commit ||= begin - stub_git_hooks - project.repository.add_branch(user, unprotected_branch, 'feature') - target_branch = project.repository.lookup('feature') - source_branch = project.repository.commit_file(user, FFaker::InternetSE.login_user_name, FFaker::HipsterIpsum.paragraph, FFaker::HipsterIpsum.sentence, unprotected_branch, false) - rugged = project.repository.rugged - author = { email: "email@example.com", time: Time.now, name: "Example Git User" } + def self.updated_permissions_matrix + updated_permissions_matrix = permissions_matrix.dup + updated_permissions_matrix[:developer][:push_protected_branch] = true + updated_permissions_matrix[:developer][:push_all] = true + updated_permissions_matrix + end - merge_index = rugged.merge_commits(target_branch, source_branch) - Rugged::Commit.create(rugged, author: author, committer: author, message: "commit message", parents: [target_branch, source_branch], tree: merge_index.write_tree(rugged)) + permissions_matrix.keys.each do |role| + describe "#{role} access" do + before { protect_feature_branch } + before { project.team << [user, role] } + + permissions_matrix[role].each do |action, allowed| + context action do + subject { access.push_access_check(changes[action]) } + + it { expect(subject.allowed?).to allowed ? be_truthy : be_falsey } + end + end end end - def self.run_permission_checks(permissions_matrix) - permissions_matrix.keys.each do |role| + context "with enabled developers push to protected branches " do + updated_permissions_matrix.keys.each do |role| describe "#{role} access" do + before { create(:protected_branch, name: 'feature', developers_can_push: true, project: project) } before { project.team << [user, role] } - permissions_matrix[role].each do |action, allowed| + updated_permissions_matrix[role].each do |action, allowed| context action do subject { access.push_access_check(changes[action]) } @@ -148,97 +259,5 @@ describe Gitlab::GitAccess, lib: true do end end end - - permissions_matrix = { - master: { - push_new_branch: true, - push_master: true, - push_protected_branch: true, - push_remove_protected_branch: false, - push_tag: true, - push_new_tag: true, - push_all: true, - merge_into_protected_branch: true - }, - - developer: { - push_new_branch: true, - push_master: true, - push_protected_branch: false, - push_remove_protected_branch: false, - push_tag: false, - push_new_tag: true, - push_all: false, - merge_into_protected_branch: false - }, - - reporter: { - push_new_branch: false, - push_master: false, - push_protected_branch: false, - push_remove_protected_branch: false, - push_tag: false, - push_new_tag: false, - push_all: false, - merge_into_protected_branch: false - }, - - guest: { - push_new_branch: false, - push_master: false, - push_protected_branch: false, - push_remove_protected_branch: false, - push_tag: false, - push_new_tag: false, - push_all: false, - merge_into_protected_branch: false - } - } - - [['feature', 'exact'], ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type| - context do - before { create(:protected_branch, name: protected_branch_name, project: project) } - - run_permission_checks(permissions_matrix) - end - - context "when 'developers can push' is turned on for the #{protected_branch_type} protected branch" do - before { create(:protected_branch, name: protected_branch_name, developers_can_push: true, project: project) } - - run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true })) - end - - context "when 'developers can merge' is turned on for the #{protected_branch_type} protected branch" do - before { create(:protected_branch, name: protected_branch_name, developers_can_merge: true, project: project) } - - context "when a merge request exists for the given source/target branch" do - context "when the merge request is in progress" do - before do - create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', state: 'locked', in_progress_merge_commit_sha: merge_into_protected_branch) - end - - run_permission_checks(permissions_matrix.deep_merge(developer: { merge_into_protected_branch: true })) - end - - context "when the merge request is not in progress" do - before do - create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', in_progress_merge_commit_sha: nil) - end - - run_permission_checks(permissions_matrix.deep_merge(developer: { merge_into_protected_branch: false })) - end - end - - context "when a merge request does not exist for the given source/target branch" do - run_permission_checks(permissions_matrix.deep_merge(developer: { merge_into_protected_branch: false })) - end - end - - context "when 'developers can merge' and 'developers can push' are turned on for the #{protected_branch_type} protected branch" do - before { create(:protected_branch, name: protected_branch_name, developers_can_merge: true, developers_can_push: true, project: project) } - - run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true })) - end - end end end diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb deleted file mode 100644 index aa9ec243498..00000000000 --- a/spec/lib/gitlab/user_access_spec.rb +++ /dev/null @@ -1,88 +0,0 @@ -require 'spec_helper' - -describe Gitlab::UserAccess, lib: true do - let(:access) { Gitlab::UserAccess.new(user, project: project) } - let(:project) { create(:project) } - let(:user) { create(:user) } - - describe 'can_push_to_branch?' do - describe 'push to none protected branch' do - it 'returns true if user is a master' do - project.team << [user, :master] - expect(access.can_push_to_branch?('random_branch')).to be_truthy - end - - it 'returns true if user is a developer' do - project.team << [user, :developer] - expect(access.can_push_to_branch?('random_branch')).to be_truthy - end - - it 'returns false if user is a reporter' do - project.team << [user, :reporter] - expect(access.can_push_to_branch?('random_branch')).to be_falsey - end - end - - describe 'push to protected branch' do - let(:branch) { create :protected_branch, project: project } - - it 'returns true if user is a master' do - project.team << [user, :master] - expect(access.can_push_to_branch?(branch.name)).to be_truthy - end - - it 'returns false if user is a developer' do - project.team << [user, :developer] - expect(access.can_push_to_branch?(branch.name)).to be_falsey - end - - it 'returns false if user is a reporter' do - project.team << [user, :reporter] - expect(access.can_push_to_branch?(branch.name)).to be_falsey - end - end - - describe 'push to protected branch if allowed for developers' do - before do - @branch = create :protected_branch, project: project, developers_can_push: true - end - - it 'returns true if user is a master' do - project.team << [user, :master] - expect(access.can_push_to_branch?(@branch.name)).to be_truthy - end - - it 'returns true if user is a developer' do - project.team << [user, :developer] - expect(access.can_push_to_branch?(@branch.name)).to be_truthy - end - - it 'returns false if user is a reporter' do - project.team << [user, :reporter] - expect(access.can_push_to_branch?(@branch.name)).to be_falsey - end - end - - describe 'merge to protected branch if allowed for developers' do - before do - @branch = create :protected_branch, project: project, developers_can_merge: true - end - - it 'returns true if user is a master' do - project.team << [user, :master] - expect(access.can_merge_to_branch?(@branch.name)).to be_truthy - end - - it 'returns true if user is a developer' do - project.team << [user, :developer] - expect(access.can_merge_to_branch?(@branch.name)).to be_truthy - end - - it 'returns false if user is a reporter' do - project.team << [user, :reporter] - expect(access.can_merge_to_branch?(@branch.name)).to be_falsey - end - end - - end -end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index e14cec589fe..b39b958450c 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -4,17 +4,16 @@ describe Repository, models: true do include RepoHelpers TestBlob = Struct.new(:name) - let(:project) { create(:project) } - let(:repository) { project.repository } + let(:repository) { create(:project).repository } let(:user) { create(:user) } let(:commit_options) do author = repository.user_to_committer(user) { message: 'Test message', committer: author, author: author } end let(:merge_commit) do - merge_request = create(:merge_request, source_branch: 'feature', target_branch: 'master', source_project: project) - merge_commit_id = repository.merge(user, merge_request, commit_options) - repository.commit(merge_commit_id) + source_sha = repository.find_branch('feature').target + merge_commit_sha = repository.merge(user, source_sha, 'master', commit_options) + repository.commit(merge_commit_sha) end describe '#branch_names_contains' do diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/api_helpers_spec.rb index 3d5c19aeff3..83025953889 100644 --- a/spec/requests/api/api_helpers_spec.rb +++ b/spec/requests/api/api_helpers_spec.rb @@ -49,7 +49,7 @@ describe API::Helpers, api: true do it "should return nil for a user without access" do env[API::Helpers::PRIVATE_TOKEN_HEADER] = user.private_token - allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false) + allow(Gitlab::UserAccess).to receive(:allowed?).and_return(false) expect(current_user).to be_nil end @@ -73,7 +73,7 @@ describe API::Helpers, api: true do it "should return nil for a user without access" do env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token - allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false) + allow(Gitlab::UserAccess).to receive(:allowed?).and_return(false) expect(current_user).to be_nil end diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index 47c0580e0f0..afabeed4a80 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -224,7 +224,7 @@ describe GitPushService, services: true do it "when pushing a branch for the first time" do expect(project).to receive(:execute_hooks) expect(project.default_branch).to eq("master") - expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false, developers_can_merge: false }) + expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false }) execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) end @@ -242,17 +242,7 @@ describe GitPushService, services: true do expect(project).to receive(:execute_hooks) expect(project.default_branch).to eq("master") - expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: true, developers_can_merge: false }) - - execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master') - end - - it "when pushing a branch for the first time with default branch protection set to 'developers can merge'" do - stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE) - - expect(project).to receive(:execute_hooks) - expect(project.default_branch).to eq("master") - expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false, developers_can_merge: true }) + expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: true }) execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) end diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index ce643b3f860..06f56d85aa8 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -88,7 +88,8 @@ describe MergeRequests::RefreshService, services: true do # Merge master -> feature branch author = { email: 'test@gitlab.com', time: Time.now, name: "Me" } commit_options = { message: 'Test message', committer: author, author: author } - @project.repository.merge(@user, @merge_request, commit_options) + master_commit = @project.repository.commit('master') + @project.repository.merge(@user, master_commit.id, 'feature', commit_options) commit = @project.repository.commit('feature') service.new(@project, @user).execute(@oldrev, commit.id, 'refs/heads/feature') reload_mrs From a4147af674e851d50c71e982475f04195d1a3015 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 13 Jul 2016 16:01:27 -0300 Subject: [PATCH 218/335] Simplify regex for string-based multi-word label surrounded in quotes --- app/models/label.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/label.rb b/app/models/label.rb index 1199793456d..35e678001dc 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -62,7 +62,7 @@ class Label < ActiveRecord::Base (?\d+(?!\S\w)\b) | # Integer-based label ID, or (? [A-Za-z0-9_\-\?\.&]+ | # String-based single-word label title, or - "([^"]+)" # String-based multi-word label surrounded in quotes + ".+?" # String-based multi-word label surrounded in quotes ) ) }x From 81a34f2f5650ef64528867b78bab6a00ec177248 Mon Sep 17 00:00:00 2001 From: Mark Pundsack Date: Wed, 13 Jul 2016 23:54:38 +0000 Subject: [PATCH 219/335] Cleanup feature proposal template --- CONTRIBUTING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f4472214778..14ff05c9aa3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -145,7 +145,8 @@ might be edited to make them small and simple. You are encouraged to use the template below for feature proposals. ``` -## Description including problem, use cases, benefits, and/or goals +## Description +Include problem, use cases, benefits, and/or goals ## Proposal From d7c591915893c8c572e9135db4ec27dc174823fd Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 13 Jul 2016 19:17:17 -0700 Subject: [PATCH 220/335] Revert "Optimistic locking for Issue and Merge Requests" This reverts commit c39356998b1850f3dc26fe0b987cb419c1d1afb4. --- app/controllers/projects/issues_controller.rb | 6 +---- .../projects/merge_requests_controller.rb | 5 +---- app/models/concerns/issuable.rb | 6 ----- app/views/shared/issuable/_form.html.haml | 9 -------- .../20160707104333_add_lock_to_issuables.rb | 17 -------------- db/schema.rb | 22 +++++++++---------- features/project/merge_requests.feature | 2 +- spec/features/issues_spec.rb | 11 ---------- spec/features/merge_requests/edit_mr_spec.rb | 11 ---------- 9 files changed, 13 insertions(+), 76 deletions(-) delete mode 100644 db/migrate/20160707104333_add_lock_to_issuables.rb diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index f7ada5cfee4..b6e80762e3c 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -119,10 +119,6 @@ class Projects::IssuesController < Projects::ApplicationController render json: @issue.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } }) end end - - rescue ActiveRecord::StaleObjectError - @conflict = true - render :edit end def referenced_merge_requests @@ -220,7 +216,7 @@ class Projects::IssuesController < Projects::ApplicationController def issue_params params.require(:issue).permit( :title, :assignee_id, :position, :description, :confidential, - :milestone_id, :due_date, :state_event, :task_num, :lock_version, label_ids: [] + :milestone_id, :due_date, :state_event, :task_num, label_ids: [] ) end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 2deb7959700..df659bb8c3b 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -196,9 +196,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController else render "edit" end - rescue ActiveRecord::StaleObjectError - @conflict = true - render :edit end def remove_wip @@ -427,7 +424,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController :title, :assignee_id, :source_project_id, :source_branch, :target_project_id, :target_branch, :milestone_id, :state_event, :description, :task_num, :force_remove_source_branch, - :lock_version, label_ids: [] + label_ids: [] ) end diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index fb49bd7dd64..acb6f5a2998 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -87,12 +87,6 @@ module Issuable User.find(assignee_id_was).update_cache_counts if assignee_id_was assignee.update_cache_counts if assignee end - - # We want to use optimistic lock for cases when only title or description are involved - # http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html - def locking_enabled? - title_changed? || description_changed? - end end module ClassMethods diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index 98bbb12eaec..c30bdb0ae91 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -1,12 +1,5 @@ = form_errors(issuable) -- if @conflict - .alert.alert-danger - Someone edited the #{issuable.class.model_name.human.downcase} the same time you did. - Please check out - = link_to "the #{issuable.class.model_name.human.downcase}", polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), target: "_blank" - and make sure your changes will not unintentionally remove theirs - .form-group = f.label :title, class: 'control-label' .col-sm-10 @@ -156,5 +149,3 @@ = link_to 'Delete', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), data: { confirm: "#{issuable.class.name.titleize} will be removed! Are you sure?" }, method: :delete, class: 'btn btn-danger btn-grouped' = link_to 'Cancel', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), class: 'btn btn-grouped btn-cancel' - -= f.hidden_field :lock_version diff --git a/db/migrate/20160707104333_add_lock_to_issuables.rb b/db/migrate/20160707104333_add_lock_to_issuables.rb deleted file mode 100644 index cb516672800..00000000000 --- a/db/migrate/20160707104333_add_lock_to_issuables.rb +++ /dev/null @@ -1,17 +0,0 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - -class AddLockToIssuables < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - disable_ddl_transaction! - - def up - add_column_with_default :issues, :lock_version, :integer, default: 0 - add_column_with_default :merge_requests, :lock_version, :integer, default: 0 - end - - def down - remove_column :issues, :lock_version - remove_column :merge_requests, :lock_version - end -end diff --git a/db/schema.rb b/db/schema.rb index f24e47b85b2..8c12898eec9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -70,11 +70,11 @@ ActiveRecord::Schema.define(version: 20160712171823) do t.string "recaptcha_site_key" t.string "recaptcha_private_key" t.integer "metrics_port", default: 8089 + t.boolean "akismet_enabled", default: false + t.string "akismet_api_key" t.integer "metrics_sample_interval", default: 15 t.boolean "sentry_enabled", default: false t.string "sentry_dsn" - t.boolean "akismet_enabled", default: false - t.string "akismet_api_key" t.boolean "email_author_in_body", default: false t.integer "default_group_visibility" t.boolean "repository_checks_enabled", default: false @@ -84,10 +84,10 @@ ActiveRecord::Schema.define(version: 20160712171823) do t.string "health_check_access_token" t.boolean "send_user_confirmation_email", default: false t.integer "container_registry_token_expire_delay", default: 5 + t.boolean "user_default_external", default: false, null: false t.text "after_sign_up_text" t.string "repository_storage", default: "default" t.string "enabled_git_access_protocol" - t.boolean "user_default_external", default: false, null: false end create_table "audit_events", force: :cascade do |t| @@ -165,8 +165,8 @@ ActiveRecord::Schema.define(version: 20160712171823) do t.text "artifacts_metadata" t.integer "erased_by_id" t.datetime "erased_at" - t.datetime "artifacts_expire_at" t.string "environment" + t.datetime "artifacts_expire_at" t.integer "artifacts_size" end @@ -481,11 +481,10 @@ ActiveRecord::Schema.define(version: 20160712171823) do t.string "state" t.integer "iid" t.integer "updated_by_id" - t.integer "moved_to_id" t.boolean "confidential", default: false t.datetime "deleted_at" t.date "due_date" - t.integer "lock_version", default: 0, null: false + t.integer "moved_to_id" end add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree @@ -625,7 +624,6 @@ ActiveRecord::Schema.define(version: 20160712171823) do t.integer "merge_user_id" t.string "merge_commit_sha" t.datetime "deleted_at" - t.integer "lock_version", default: 0, null: false end add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree @@ -775,10 +773,10 @@ ActiveRecord::Schema.define(version: 20160712171823) do t.integer "user_id", null: false t.string "token", null: false t.string "name", null: false - t.boolean "revoked", default: false - t.datetime "expires_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.boolean "revoked", default: false + t.datetime "expires_at" end add_index "personal_access_tokens", ["token"], name: "index_personal_access_tokens_on_token", unique: true, using: :btree @@ -898,9 +896,9 @@ ActiveRecord::Schema.define(version: 20160712171823) do t.string "type" t.string "title" t.integer "project_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "active", null: false + t.datetime "created_at" + t.datetime "updated_at" + t.boolean "active", default: false, null: false t.text "properties" t.boolean "template", default: false t.boolean "push_events", default: true diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 8176ec5ab45..21768c15c17 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -89,7 +89,7 @@ Feature: Project Merge Requests Then The list should be sorted by "Oldest updated" @javascript - Scenario: Visiting Merge Requests from a different Project after sorting + Scenario: Visiting Merge Requests from a differente Project after sorting Given I visit project "Shop" merge requests page And I sort the list by "Oldest updated" And I visit dashboard merge requests page diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index cfe6349a1a1..d51c9abea19 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -121,17 +121,6 @@ describe 'Issues', feature: true do expect(page).to have_content date.to_s(:medium) end end - - it 'warns about version conflict' do - issue.update(title: "New title") - - fill_in 'issue_title', with: 'bug 345' - fill_in 'issue_description', with: 'bug description' - - click_button 'Save changes' - - expect(page).to have_content 'Someone edited the issue the same time you did' - end end end diff --git a/spec/features/merge_requests/edit_mr_spec.rb b/spec/features/merge_requests/edit_mr_spec.rb index 8ad884492d1..9e007ab7635 100644 --- a/spec/features/merge_requests/edit_mr_spec.rb +++ b/spec/features/merge_requests/edit_mr_spec.rb @@ -17,16 +17,5 @@ feature 'Edit Merge Request', feature: true do it 'form should have class js-quick-submit' do expect(page).to have_selector('.js-quick-submit') end - - it 'warns about version conflict' do - merge_request.update(title: "New title") - - fill_in 'merge_request_title', with: 'bug 345' - fill_in 'merge_request_description', with: 'bug description' - - click_button 'Save changes' - - expect(page).to have_content 'Someone edited the merge request the same time you did' - end end end From 4b33c4c6d1aa529ec22606995123cfa3a151ccee Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Mon, 11 Jul 2016 13:00:22 +0530 Subject: [PATCH 221/335] Load Javascript U2F library selectively. 1. Only on supported Chrome versions 2. Mainly, this lets us simplify the javascript-based U2F check to `window.u2f`, where `window.u2f` can either be loaded from the GitLab server (for Chrome) or from the Firefox extension. 3. This is a better way to provide browser detection for U2F. --- CHANGELOG | 1 + app/assets/javascripts/application.js.coffee | 1 - app/assets/javascripts/u2f/util.js.coffee.erb | 14 +------------- app/controllers/application_controller.rb | 4 ---- .../concerns/authenticates_with_two_factor.rb | 3 +-- .../profiles/two_factor_auths_controller.rb | 3 +-- app/helpers/u2f_helper.rb | 5 +++++ app/views/devise/sessions/two_factor.html.haml | 4 ++++ app/views/profiles/two_factor_auths/show.html.haml | 4 ++++ config/application.rb | 1 + 10 files changed, 18 insertions(+), 22 deletions(-) create mode 100644 app/helpers/u2f_helper.rb diff --git a/CHANGELOG b/CHANGELOG index 0eb7595fbfa..cd66281fddc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ v 8.10.0 (unreleased) - Make images fit to the size of the viewport !4810 - Fix check for New Branch button on Issue page !4630 (winniehell) - Fix MR-auto-close text added to description. !4836 + - Support U2F devices in Firefox. !5177 - Fix issue, preventing users w/o push access to sort tags !5105 (redetection) - Add Spring EmojiOne updates. - Add syntax for multiline blockquote using `>>>` fence !3954 diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index 64da503c35f..4393fece329 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -54,7 +54,6 @@ #= require_directory ./u2f #= require_directory . #= require fuzzaldrin-plus -#= require u2f window.slugify = (text) -> text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase() diff --git a/app/assets/javascripts/u2f/util.js.coffee.erb b/app/assets/javascripts/u2f/util.js.coffee.erb index d59341c38b9..be1d3286b01 100644 --- a/app/assets/javascripts/u2f/util.js.coffee.erb +++ b/app/assets/javascripts/u2f/util.js.coffee.erb @@ -1,15 +1,3 @@ -# Helper class for U2F (universal 2nd factor) device registration and authentication. - class @U2FUtil @isU2FSupported: -> - if @testMode - true - else - gon.u2f.browser_supports_u2f - - @enableTestMode: -> - @testMode = true - -<% if Rails.env.test? %> -U2FUtil.enableTestMode(); -<% end %> + window.u2f diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9cc31620d9f..a1004d9bcea 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -344,10 +344,6 @@ class ApplicationController < ActionController::Base session[:skip_tfa] && session[:skip_tfa] > Time.current end - def browser_supports_u2f? - browser.chrome? && browser.version.to_i >= 41 && !browser.device.mobile? - end - def redirect_to_home_page_url? # If user is not signed-in and tries to access root_path - redirect him to landing page # Don't redirect to the default URL to prevent endless redirections diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index 998b8adc411..0c755894790 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -80,8 +80,7 @@ module AuthenticatesWithTwoFactor challenges = sign_requests.map(&:challenge) session[:challenges] = challenges gon.push(u2f: { challenges: challenges, app_id: u2f_app_id, - sign_requests: sign_requests, - browser_supports_u2f: browser_supports_u2f? }) + sign_requests: sign_requests }) end end end diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb index 6a358fdcc05..e37e9e136db 100644 --- a/app/controllers/profiles/two_factor_auths_controller.rb +++ b/app/controllers/profiles/two_factor_auths_controller.rb @@ -100,7 +100,6 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController gon.push(u2f: { challenges: session[:challenges], app_id: u2f_app_id, register_requests: registration_requests, - sign_requests: sign_requests, - browser_supports_u2f: browser_supports_u2f? }) + sign_requests: sign_requests }) end end diff --git a/app/helpers/u2f_helper.rb b/app/helpers/u2f_helper.rb new file mode 100644 index 00000000000..143b4ca6b51 --- /dev/null +++ b/app/helpers/u2f_helper.rb @@ -0,0 +1,5 @@ +module U2fHelper + def inject_u2f_api? + browser.chrome? && browser.version.to_i >= 41 && !browser.device.mobile? + end +end diff --git a/app/views/devise/sessions/two_factor.html.haml b/app/views/devise/sessions/two_factor.html.haml index a373f61bd3c..dbf4d699d01 100644 --- a/app/views/devise/sessions/two_factor.html.haml +++ b/app/views/devise/sessions/two_factor.html.haml @@ -1,3 +1,7 @@ +- content_for :page_specific_javascripts do + - if inject_u2f_api? + = page_specific_javascript_tag('u2f.js') + %div .login-box .login-heading diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml index 5890456bee2..0e9a80a6267 100644 --- a/app/views/profiles/two_factor_auths/show.html.haml +++ b/app/views/profiles/two_factor_auths/show.html.haml @@ -2,6 +2,10 @@ - header_title "Two-Factor Authentication", profile_two_factor_auth_path = render 'profiles/head' +- content_for :page_specific_javascripts do + - if inject_u2f_api? + = page_specific_javascript_tag('u2f.js') + .row.prepend-top-default .col-lg-3 %h4.prepend-top-0 diff --git a/config/application.rb b/config/application.rb index 21e7cc7b6e8..5f7b6a3c049 100644 --- a/config/application.rb +++ b/config/application.rb @@ -87,6 +87,7 @@ module Gitlab config.assets.precompile << "profile/application.js" config.assets.precompile << "lib/utils/*.js" config.assets.precompile << "lib/*.js" + config.assets.precompile << "u2f.js" # Version of your assets, change this if you want to expire all your assets config.assets.version = '1.0' From 3572582dd2568cd473676563077ab3985b9803f7 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Mon, 11 Jul 2016 13:02:24 +0530 Subject: [PATCH 222/335] Use a single challenge for U2F authentication. 1. According to the spec, either we have a single challenge with a number of `signRequests`, or a number of `signRequests`, each with it's own challenge. 2. Previously, we had both these - per-request challenges, as well as a single extra challenge. 3. This commit changes this so that the per-request challenges are removed, leaving only a single challenge, as per the v1.1 U2F API. 4. The existing implementation didn't work in Firefox, because the Firefox (extension) implementation is less flexible with regard to the inputs. 5. Fix teaspoon specs. 6. References: https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-u2f-javascript-api.html#h2_background --- app/assets/javascripts/u2f/authenticate.js.coffee | 15 ++++++++++++--- .../concerns/authenticates_with_two_factor.rb | 7 +++---- spec/javascripts/u2f/authenticate_spec.coffee | 3 +-- spec/javascripts/u2f/register_spec.js.coffee | 1 - spec/support/fake_u2f_device.rb | 4 ++-- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/u2f/authenticate.js.coffee b/app/assets/javascripts/u2f/authenticate.js.coffee index 6deb902c8de..be10e911c83 100644 --- a/app/assets/javascripts/u2f/authenticate.js.coffee +++ b/app/assets/javascripts/u2f/authenticate.js.coffee @@ -6,8 +6,17 @@ class @U2FAuthenticate constructor: (@container, u2fParams) -> @appId = u2fParams.app_id - @challenges = u2fParams.challenges - @signRequests = u2fParams.sign_requests + @challenge = u2fParams.challenge + + # The U2F Javascript API v1.1 requires a single challenge, with _no + # challenges per-request_. + # + # The U2F Javascript API v1.0 requires a challenge per-request, which + # is done by copying the single challenge into every request. + # + # In either case, we don't need the per-request challenges that the server + # has generated, so we can remove them. + @signRequests = u2fParams.sign_requests.map (request) -> _(request).omit('challenge') start: () => if U2FUtil.isU2FSupported() @@ -16,7 +25,7 @@ class @U2FAuthenticate @renderNotSupported() authenticate: () => - u2f.sign(@appId, @challenges, @signRequests, (response) => + u2f.sign(@appId, @challenge, @signRequests, (response) => if response.errorCode error = new U2FError(response.errorCode) @renderError(error); diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index 0c755894790..ba07cea569c 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -57,7 +57,7 @@ module AuthenticatesWithTwoFactor # Authenticate using the response from a U2F (universal 2nd factor) device def authenticate_with_two_factor_via_u2f(user) - if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenges]) + if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge]) # Remove any lingering user data from login session.delete(:otp_user_id) session.delete(:challenges) @@ -77,9 +77,8 @@ module AuthenticatesWithTwoFactor if key_handles.present? sign_requests = u2f.authentication_requests(key_handles) - challenges = sign_requests.map(&:challenge) - session[:challenges] = challenges - gon.push(u2f: { challenges: challenges, app_id: u2f_app_id, + session[:challenge] ||= u2f.challenge + gon.push(u2f: { challenge: session[:challenge], app_id: u2f_app_id, sign_requests: sign_requests }) end end diff --git a/spec/javascripts/u2f/authenticate_spec.coffee b/spec/javascripts/u2f/authenticate_spec.coffee index e8a2892d678..8ffeda11704 100644 --- a/spec/javascripts/u2f/authenticate_spec.coffee +++ b/spec/javascripts/u2f/authenticate_spec.coffee @@ -5,13 +5,12 @@ #= require ./mock_u2f_device describe 'U2FAuthenticate', -> - U2FUtil.enableTestMode() fixture.load('u2f/authenticate') beforeEach -> @u2fDevice = new MockU2FDevice @container = $("#js-authenticate-u2f") - @component = new U2FAuthenticate(@container, {}, "token") + @component = new U2FAuthenticate(@container, {sign_requests: []}, "token") @component.start() it 'allows authenticating via a U2F device', -> diff --git a/spec/javascripts/u2f/register_spec.js.coffee b/spec/javascripts/u2f/register_spec.js.coffee index 0858abeca1a..87dc769792b 100644 --- a/spec/javascripts/u2f/register_spec.js.coffee +++ b/spec/javascripts/u2f/register_spec.js.coffee @@ -5,7 +5,6 @@ #= require ./mock_u2f_device describe 'U2FRegister', -> - U2FUtil.enableTestMode() fixture.load('u2f/register') beforeEach -> diff --git a/spec/support/fake_u2f_device.rb b/spec/support/fake_u2f_device.rb index 553fe9f1fbc..f550e9a0160 100644 --- a/spec/support/fake_u2f_device.rb +++ b/spec/support/fake_u2f_device.rb @@ -18,8 +18,8 @@ class FakeU2fDevice def respond_to_u2f_authentication app_id = @page.evaluate_script('gon.u2f.app_id') - challenges = @page.evaluate_script('gon.u2f.challenges') - json_response = u2f_device(app_id).sign_response(challenges[0]) + challenge = @page.evaluate_script('gon.u2f.challenge') + json_response = u2f_device(app_id).sign_response(challenge) @page.execute_script(" u2f.sign = function(appId, challenges, signRequests, callback) { From 341d8bc3f7fbe3763250af1e89020b81dad34bb8 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Mon, 11 Jul 2016 13:23:02 +0530 Subject: [PATCH 223/335] Add a U2F feature spec for multiple devices owned by the same user. 1. This scenario was previously tested for the registration flow, but not authentication. --- .../javascripts/u2f/authenticate.js.coffee | 13 +++-- .../{util.js.coffee.erb => util.js.coffee} | 2 +- .../devise/sessions/two_factor.html.haml | 4 +- .../profiles/two_factor_auths/show.html.haml | 4 +- spec/features/u2f_spec.rb | 55 +++++++++++++++---- 5 files changed, 57 insertions(+), 21 deletions(-) rename app/assets/javascripts/u2f/{util.js.coffee.erb => util.js.coffee} (68%) diff --git a/app/assets/javascripts/u2f/authenticate.js.coffee b/app/assets/javascripts/u2f/authenticate.js.coffee index be10e911c83..918c0a560fd 100644 --- a/app/assets/javascripts/u2f/authenticate.js.coffee +++ b/app/assets/javascripts/u2f/authenticate.js.coffee @@ -8,14 +8,17 @@ class @U2FAuthenticate @appId = u2fParams.app_id @challenge = u2fParams.challenge - # The U2F Javascript API v1.1 requires a single challenge, with _no - # challenges per-request_. - # - # The U2F Javascript API v1.0 requires a challenge per-request, which - # is done by copying the single challenge into every request. + # The U2F Javascript API v1.1 requires a single challenge, with + # _no challenges per-request_. The U2F Javascript API v1.0 requires a + # challenge per-request, which is done by copying the single challenge + # into every request. # # In either case, we don't need the per-request challenges that the server # has generated, so we can remove them. + # + # Note: The server library fixes this behaviour in (unreleased) version 1.0.0. + # This can be removed once we upgrade. + # https://github.com/castle/ruby-u2f/commit/103f428071a81cd3d5f80c2e77d522d5029946a4 @signRequests = u2fParams.sign_requests.map (request) -> _(request).omit('challenge') start: () => diff --git a/app/assets/javascripts/u2f/util.js.coffee.erb b/app/assets/javascripts/u2f/util.js.coffee similarity index 68% rename from app/assets/javascripts/u2f/util.js.coffee.erb rename to app/assets/javascripts/u2f/util.js.coffee index be1d3286b01..5ef324f609d 100644 --- a/app/assets/javascripts/u2f/util.js.coffee.erb +++ b/app/assets/javascripts/u2f/util.js.coffee @@ -1,3 +1,3 @@ class @U2FUtil @isU2FSupported: -> - window.u2f + window.u2f diff --git a/app/views/devise/sessions/two_factor.html.haml b/app/views/devise/sessions/two_factor.html.haml index dbf4d699d01..4debd3d608f 100644 --- a/app/views/devise/sessions/two_factor.html.haml +++ b/app/views/devise/sessions/two_factor.html.haml @@ -1,5 +1,5 @@ -- content_for :page_specific_javascripts do - - if inject_u2f_api? +- if inject_u2f_api? + - content_for :page_specific_javascripts do = page_specific_javascript_tag('u2f.js') %div diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml index 0e9a80a6267..355bfcf1d62 100644 --- a/app/views/profiles/two_factor_auths/show.html.haml +++ b/app/views/profiles/two_factor_auths/show.html.haml @@ -2,8 +2,8 @@ - header_title "Two-Factor Authentication", profile_two_factor_auth_path = render 'profiles/head' -- content_for :page_specific_javascripts do - - if inject_u2f_api? +- if inject_u2f_api? + - content_for :page_specific_javascripts do = page_specific_javascript_tag('u2f.js') .row.prepend-top-default diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb index 14613754f74..9335f5bf120 100644 --- a/spec/features/u2f_spec.rb +++ b/spec/features/u2f_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: true, js: true do + before { allow_any_instance_of(U2fHelper).to receive(:inject_u2f_api?).and_return(true) } + def register_u2f_device(u2f_device = nil) u2f_device ||= FakeU2fDevice.new(page) u2f_device.respond_to_u2f_registration @@ -208,21 +210,52 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: expect(page.body).to match('Authentication via U2F device failed') end end - end - describe "when two-factor authentication is disabled" do - let(:user) { create(:user) } + describe "when more than one device has been registered by the same user" do + it "allows logging in with either device" do + # Register first device + user = login_as(:user) + user.update_attribute(:otp_required_for_login, true) + visit profile_two_factor_auth_path + expect(page).to have_content("Your U2F device needs to be set up.") + first_device = register_u2f_device - before do - login_as(user) - user.update_attribute(:otp_required_for_login, true) - visit profile_account_path - click_on 'Manage Two-Factor Authentication' - register_u2f_device + # Register second device + visit profile_two_factor_auth_path + expect(page).to have_content("Your U2F device needs to be set up.") + second_device = register_u2f_device + logout + + # Authenticate as both devices + [first_device, second_device].each do |device| + login_as(user) + device.respond_to_u2f_authentication + click_on "Login Via U2F Device" + expect(page.body).to match('We heard back from your U2F device') + click_on "Authenticate via U2F Device" + + expect(page.body).to match('Signed in successfully') + + logout + end + end end - it "deletes u2f registrations" do - expect { click_on "Disable" }.to change { U2fRegistration.count }.from(1).to(0) + describe "when two-factor authentication is disabled" do + let(:user) { create(:user) } + + before do + user = login_as(:user) + user.update_attribute(:otp_required_for_login, true) + visit profile_account_path + click_on 'Manage Two-Factor Authentication' + expect(page).to have_content("Your U2F device needs to be set up.") + register_u2f_device + end + + it "deletes u2f registrations" do + expect { click_on "Disable" }.to change { U2fRegistration.count }.by(-1) + end end end end From e21492b810bf9cd30f0e60836c056a72e830f427 Mon Sep 17 00:00:00 2001 From: dixpac Date: Sun, 3 Jul 2016 16:04:22 +0200 Subject: [PATCH 224/335] Fix not normalized emoji paths * There where path where +1 was stored as +1 not as thumbsup that was causing problems such as showing thumbsup icon 2 time. I fixed this to always normalize and store +1 as tumbsup --- CHANGELOG | 1 + app/models/concerns/awardable.rb | 9 ++++++-- app/models/note.rb | 3 +-- app/services/notes/create_service.rb | 1 - lib/api/award_emoji.rb | 4 ++-- spec/requests/api/award_emoji_spec.rb | 32 +++++++++++++++++++++++++++ 6 files changed, 43 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 19286abd74f..139444ef70e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -74,6 +74,7 @@ v 8.10.0 (unreleased) - Add basic system information like memory and disk usage to the admin panel - Don't garbage collect commits that have related DB records like comments - More descriptive message for git hooks and file locks + - Aliases of award emoji should be stored as original name. !5060 (dixpac) - Handle custom Git hook result in GitLab UI - Allow '?', or '&' for label names - Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests diff --git a/app/models/concerns/awardable.rb b/app/models/concerns/awardable.rb index 06beff177b1..800a16ab246 100644 --- a/app/models/concerns/awardable.rb +++ b/app/models/concerns/awardable.rb @@ -65,8 +65,7 @@ module Awardable def create_award_emoji(name, current_user) return unless emoji_awardable? - - award_emoji.create(name: name, user: current_user) + award_emoji.create(name: normalize_name(name), user: current_user) end def remove_award_emoji(name, current_user) @@ -80,4 +79,10 @@ module Awardable create_award_emoji(emoji_name, current_user) end end + + private + + def normalize_name(name) + Gitlab::AwardEmoji.normalize_emoji_name(name) + end end diff --git a/app/models/note.rb b/app/models/note.rb index 8dca2ef09a8..0ce10c77de9 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -229,8 +229,7 @@ class Note < ActiveRecord::Base end def award_emoji_name - original_name = note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1] - Gitlab::AwardEmoji.normalize_emoji_name(original_name) + note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1] end private diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb index 02fca5c0ea3..18971bd0be3 100644 --- a/app/services/notes/create_service.rb +++ b/app/services/notes/create_service.rb @@ -8,7 +8,6 @@ module Notes if note.award_emoji? noteable = note.noteable todo_service.new_award_emoji(noteable, current_user) - return noteable.create_award_emoji(note.award_emoji_name, current_user) end diff --git a/lib/api/award_emoji.rb b/lib/api/award_emoji.rb index c4fa1838b5a..2efe7e3adf3 100644 --- a/lib/api/award_emoji.rb +++ b/lib/api/award_emoji.rb @@ -56,9 +56,9 @@ module API not_found!('Award Emoji') unless can_read_awardable? - award = awardable.award_emoji.new(name: params[:name], user: current_user) + award = awardable.create_award_emoji(params[:name], current_user) - if award.save + if award.persisted? present award, with: Entities::AwardEmoji else not_found!("Award Emoji #{award.errors.messages}") diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb index 72a6d45f47d..2b74dd4bbb0 100644 --- a/spec/requests/api/award_emoji_spec.rb +++ b/spec/requests/api/award_emoji_spec.rb @@ -135,6 +135,22 @@ describe API::API, api: true do expect(response).to have_http_status(401) end + + it "normalizes +1 as thumbsup award" do + post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user), name: '+1' + + expect(issue.award_emoji.last.name).to eq("thumbsup") + end + + context 'when the emoji already has been awarded' do + it 'returns a 404 status code' do + post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user), name: 'thumbsup' + post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user), name: 'thumbsup' + + expect(response).to have_http_status(404) + expect(json_response["message"]).to match("has already been taken") + end + end end end @@ -147,6 +163,22 @@ describe API::API, api: true do expect(response).to have_http_status(201) expect(json_response['user']['username']).to eq(user.username) end + + it "normalizes +1 as thumbsup award" do + post api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user), name: '+1' + + expect(note.award_emoji.last.name).to eq("thumbsup") + end + + context 'when the emoji already has been awarded' do + it 'returns a 404 status code' do + post api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user), name: 'rocket' + post api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user), name: 'rocket' + + expect(response).to have_http_status(404) + expect(json_response["message"]).to match("has already been taken") + end + end end describe 'DELETE /projects/:id/awardable/:awardable_id/award_emoji/:award_id' do From ef892bc2bfa29046dd58441d8d9afe8b3cde0007 Mon Sep 17 00:00:00 2001 From: Katarzyna Kobierska Date: Thu, 14 Jul 2016 10:53:56 +0200 Subject: [PATCH 225/335] When Issue author assign or mention himself Todos are created --- CHANGELOG | 1 + app/services/todo_service.rb | 3 +-- spec/services/todo_service_spec.rb | 35 +++++++++++++++++------------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 19286abd74f..aaab3551ea8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -91,6 +91,7 @@ v 8.10.0 (unreleased) - Redesign Builds and Pipelines pages - Change status color and icon for running builds - Fix markdown rendering for: consecutive labels references, label references that begin with a digit or contains `.` + - Create Todos for Issue author when assign or mention himself (Katarzyna Kobierska) v 8.9.6 - Fix importing of events under notes for GitLab projects. !5154 diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb index 6bb0a72d30e..6b48d68cccb 100644 --- a/app/services/todo_service.rb +++ b/app/services/todo_service.rb @@ -194,7 +194,7 @@ class TodoService end def create_assignment_todo(issuable, author) - if issuable.assignee && issuable.assignee != author + if issuable.assignee attributes = attributes_for_todo(issuable.project, issuable, author, Todo::ASSIGNED) create_todos(issuable.assignee, attributes) end @@ -239,7 +239,6 @@ class TodoService def filter_mentioned_users(project, target, author) mentioned_users = target.mentioned_users(author) mentioned_users = reject_users_without_access(mentioned_users, project, target) - mentioned_users.delete(author) mentioned_users.uniq end diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index b4522536724..b8c62e3d1dc 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -35,8 +35,11 @@ describe TodoService, services: true do should_not_create_any_todo { service.new_issue(unassigned_issue, author) } end - it 'does not create a todo if assignee is the current user' do - should_not_create_any_todo { service.new_issue(unassigned_issue, john_doe) } + it 'creates a todo if assignee is the current user' do + unassigned_issue.update_attribute(:assignee, john_doe) + service.new_issue(unassigned_issue, john_doe) + + should_create_todo(user: john_doe, target: unassigned_issue, author: john_doe, action: Todo::ASSIGNED) end it 'creates a todo for each valid mentioned user' do @@ -44,7 +47,7 @@ describe TodoService, services: true do should_create_todo(user: member, target: issue, action: Todo::MENTIONED) should_create_todo(user: guest, target: issue, action: Todo::MENTIONED) - should_not_create_todo(user: author, target: issue, action: Todo::MENTIONED) + should_create_todo(user: author, target: issue, action: Todo::MENTIONED) should_not_create_todo(user: john_doe, target: issue, action: Todo::MENTIONED) should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED) end @@ -57,7 +60,7 @@ describe TodoService, services: true do should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) - should_not_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) + should_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) end context 'when a private group is mentioned' do @@ -87,7 +90,7 @@ describe TodoService, services: true do should_create_todo(user: member, target: issue, action: Todo::MENTIONED) should_create_todo(user: guest, target: issue, action: Todo::MENTIONED) should_create_todo(user: john_doe, target: issue, action: Todo::MENTIONED) - should_not_create_todo(user: author, target: issue, action: Todo::MENTIONED) + should_create_todo(user: author, target: issue, action: Todo::MENTIONED) should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED) end @@ -105,7 +108,7 @@ describe TodoService, services: true do should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) - should_not_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) + should_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) end context 'issues with a task list' do @@ -156,10 +159,11 @@ describe TodoService, services: true do should_not_create_any_todo { service.reassigned_issue(issue, author) } end - it 'does not create a todo if new assignee is the current user' do + it 'creates a todo if new assignee is the current user' do unassigned_issue.update_attribute(:assignee, john_doe) + service.reassigned_issue(unassigned_issue, john_doe) - should_not_create_any_todo { service.reassigned_issue(unassigned_issue, john_doe) } + should_create_todo(user: john_doe, target: unassigned_issue, author: john_doe, action: Todo::ASSIGNED) end end @@ -250,7 +254,7 @@ describe TodoService, services: true do should_create_todo(user: member, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) should_create_todo(user: guest, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) should_create_todo(user: author, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) - should_not_create_todo(user: john_doe, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) + should_create_todo(user: john_doe, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) should_not_create_todo(user: non_member, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) end @@ -262,7 +266,7 @@ describe TodoService, services: true do should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue) should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue) should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue) - should_not_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue) + should_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue) end it 'creates a todo for each valid mentioned user when leaving a note on commit' do @@ -270,7 +274,7 @@ describe TodoService, services: true do should_create_todo(user: member, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit) should_create_todo(user: author, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit) - should_not_create_todo(user: john_doe, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit) + should_create_todo(user: john_doe, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit) should_not_create_todo(user: non_member, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit) end @@ -312,7 +316,7 @@ describe TodoService, services: true do should_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED) should_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) - should_not_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED) + should_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED) end @@ -325,7 +329,7 @@ describe TodoService, services: true do should_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED) should_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) should_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED) - should_not_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED) + should_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED) end @@ -382,10 +386,11 @@ describe TodoService, services: true do should_not_create_any_todo { service.reassigned_merge_request(mr_assigned, author) } end - it 'does not create a todo if new assignee is the current user' do + it 'creates a todo if new assignee is the current user' do mr_assigned.update_attribute(:assignee, john_doe) + service.reassigned_merge_request(mr_assigned, john_doe) - should_not_create_any_todo { service.reassigned_merge_request(mr_assigned, john_doe) } + should_create_todo(user: john_doe, target: mr_assigned, author: john_doe, action: Todo::ASSIGNED) end end From 9290c755f3ba22a899e00288d4cba0b5929d6e2d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 14 Jul 2016 09:10:15 +0000 Subject: [PATCH 226/335] Include default callback URL (OAuth) --- doc/integration/oauth_provider.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md index 5f8bb57365c..0c53584d201 100644 --- a/doc/integration/oauth_provider.md +++ b/doc/integration/oauth_provider.md @@ -28,7 +28,8 @@ GitLab supports two ways of adding a new OAuth2 application to an instance. You can either add an application as a regular user or add it in the admin area. What this means is that GitLab can actually have instance-wide and a user-wide applications. There is no difference between them except for the different -permission levels they are set (user/admin). +permission levels they are set (user/admin). The default callback URL is +`http://your-gitlab.example.com/users/auth/gitlab/callback` ## Adding an application through the profile From d61bf3b977b303f838c243645b5003256622a77d Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 14 Jul 2016 11:04:03 +0100 Subject: [PATCH 227/335] Update permissons links to new page permissions/permissions just links to user/permissions since https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5210 --- app/helpers/search_helper.rb | 2 +- app/views/admin/groups/show.html.haml | 2 +- app/views/errors/access_denied.html.haml | 2 +- app/views/groups/group_members/_new_group_member.html.haml | 2 +- .../projects/project_members/_new_project_member.html.haml | 2 +- app/views/projects/protected_branches/index.html.haml | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index b165b569372..fcb2703e837 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -45,7 +45,7 @@ module SearchHelper [ { category: "Help", label: "API Help", url: help_page_path("api/README") }, { category: "Help", label: "Markdown Help", url: help_page_path("markdown/markdown") }, - { category: "Help", label: "Permissions Help", url: help_page_path("permissions/permissions") }, + { category: "Help", label: "Permissions Help", url: help_page_path("user/permissions") }, { category: "Help", label: "Public Access Help", url: help_page_path("public_access/public_access") }, { category: "Help", label: "Rake Tasks Help", url: help_page_path("raketasks/README") }, { category: "Help", label: "SSH Keys Help", url: help_page_path("ssh/README") }, diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 40c8169ad9d..bb374694400 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -79,7 +79,7 @@ .panel-body.form-holder %p.light Read more about project permissions - %strong= link_to "here", help_page_path("permissions/permissions"), class: "vlink" + %strong= link_to "here", help_page_path("user/permissions"), class: "vlink" = form_tag members_update_admin_group_path(@group), id: "new_project_member", class: "bulk_import", method: :put do %div diff --git a/app/views/errors/access_denied.html.haml b/app/views/errors/access_denied.html.haml index 2febeef99d3..c034bbe430e 100644 --- a/app/views/errors/access_denied.html.haml +++ b/app/views/errors/access_denied.html.haml @@ -3,4 +3,4 @@ %h3 Access Denied %hr %p You are not allowed to access this page. -%p Read more about project permissions #{link_to "here", help_page_path("permissions/permissions"), class: "vlink"} +%p Read more about project permissions #{link_to "here", help_page_path("user/permissions"), class: "vlink"} diff --git a/app/views/groups/group_members/_new_group_member.html.haml b/app/views/groups/group_members/_new_group_member.html.haml index 13ded2bc455..9bb9f962177 100644 --- a/app/views/groups/group_members/_new_group_member.html.haml +++ b/app/views/groups/group_members/_new_group_member.html.haml @@ -12,7 +12,7 @@ = select_tag :access_level, options_for_select(GroupMember.access_level_roles, @group_member.access_level), class: "project-access-select select2" .help-block Read more about role permissions - %strong= link_to "here", help_page_path("permissions/permissions"), class: "vlink" + %strong= link_to "here", help_page_path("user/permissions"), class: "vlink" .form-actions = f.submit 'Add users to group', class: "btn btn-create" diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml index ea3d82d858e..978c4dfc5ec 100644 --- a/app/views/projects/project_members/_new_project_member.html.haml +++ b/app/views/projects/project_members/_new_project_member.html.haml @@ -12,7 +12,7 @@ = select_tag :access_level, options_for_select(ProjectMember.access_level_roles, @project_member.access_level), class: "project-access-select select2" .help-block Read more about role permissions - %strong= link_to "here", help_page_path("permissions/permissions"), class: "vlink" + %strong= link_to "here", help_page_path("user/permissions"), class: "vlink" .form-actions = f.submit 'Add users to project', class: "btn btn-create" diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml index 3fab95751e0..883d3e3af1e 100644 --- a/app/views/projects/protected_branches/index.html.haml +++ b/app/views/projects/protected_branches/index.html.haml @@ -8,10 +8,10 @@ %p.prepend-top-20 Protected branches are designed to: %ul - %li prevent pushes from everybody except #{link_to "masters", help_page_path("permissions/permissions"), class: "vlink"} + %li prevent pushes from everybody except #{link_to "masters", help_page_path("user/permissions"), class: "vlink"} %li prevent anyone from force pushing to the branch %li prevent anyone from deleting the branch - %p.append-bottom-0 Read more about #{link_to "project permissions", help_page_path("permissions/permissions"), class: "underlined-link"} + %p.append-bottom-0 Read more about #{link_to "project permissions", help_page_path("user/permissions"), class: "underlined-link"} .col-lg-9 %h5.prepend-top-0 Protect a branch From 097706b4588ca8ace9dfaab44f03d62ac6b3a2be Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 14 Jul 2016 12:07:54 +0200 Subject: [PATCH 228/335] fix EE => CE project import, and updated JSON spec --- lib/gitlab/import_export/relation_factory.rb | 8 ++++++-- spec/lib/gitlab/import_export/project.json | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index 9824df3f274..6ba25a31641 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -87,7 +87,7 @@ module Gitlab project_id = @relation_hash.delete('project_id') # project_id may not be part of the export, but we always need to populate it if required. - @relation_hash['project_id'] = project_id if relation_class.column_names.include?('project_id') + @relation_hash['project_id'] = project_id @relation_hash['gl_project_id'] = project_id if @relation_hash['gl_project_id'] @relation_hash['target_project_id'] = project_id if @relation_hash['target_project_id'] @relation_hash['source_project_id'] = -1 if @relation_hash['source_project_id'] @@ -111,7 +111,7 @@ module Gitlab end def imported_object - imported_object = relation_class.new(@relation_hash) + imported_object = relation_class.new(parsed_relation_hash) yield(imported_object) if block_given? imported_object.importing = true if imported_object.respond_to?(:importing) imported_object @@ -125,6 +125,10 @@ module Gitlab def admin_user? @user.is_admin? end + + def parsed_relation_hash + @relation_hash.reject { |k, _v| !relation_class.attribute_method?(k) } + end end end end diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index 7286b0c39c0..4113d829c3c 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -26,6 +26,7 @@ "deleted_at": null, "due_date": null, "moved_to_id": null, + "test_ee_field": "test", "notes": [ { "id": 351, From 37d1e65a2deb64d95183e69c3680a6eeb1770fdb Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 14 Jul 2016 12:18:16 +0200 Subject: [PATCH 229/335] added changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 19286abd74f..6acecf94420 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -91,6 +91,7 @@ v 8.10.0 (unreleased) - Redesign Builds and Pipelines pages - Change status color and icon for running builds - Fix markdown rendering for: consecutive labels references, label references that begin with a digit or contains `.` + - Fix issues importing projects from EE to CE v 8.9.6 - Fix importing of events under notes for GitLab projects. !5154 From c7818ed70db953c1bde491e85252154d9cb06584 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Jul 2016 14:58:25 +0300 Subject: [PATCH 230/335] Improves left static sidebar behaviour List of changes: * removed bottom 50px space that is no longer necessary with pin button at the top * increased side padding so sidebar links are closer to counters * use fixed weight pin icon so it correctly aligned with counters Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/sidebar.scss | 8 ++------ app/assets/stylesheets/framework/variables.scss | 1 + app/views/layouts/_page.html.haml | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index cec52678495..d52e8f00172 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -55,10 +55,6 @@ overflow-y: auto; overflow-x: hidden; - @media (min-width: $sidebar-breakpoint) { - bottom: 50px; - } - &.navbar-collapse { padding: 0 !important; } @@ -76,7 +72,7 @@ } a { - padding: 7px 16px; + padding: 7px $gl-sidebar-padding; font-size: $gl-font-size; line-height: 24px; display: block; @@ -143,7 +139,7 @@ } .nav-header-btn { - padding: 10px 16px; + padding: 10px $gl-sidebar-padding; color: inherit; transition-duration: .3s; position: absolute; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 09d3caa0e6a..f0e7002e4cd 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -64,6 +64,7 @@ $gl-btn-padding: 10px; $gl-input-padding: 10px; $gl-vert-padding: 6px; $gl-padding-top: 10px; +$gl-sidebar-padding: 22px; /* * Misc diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index 90c1fa4c87c..a1a71c2fb33 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -6,7 +6,7 @@ = icon('bars') = link_to '#', class: "nav-header-btn pin-nav-btn has-tooltip #{'is-active' if pinned_nav?} js-nav-pin", title: pinned_nav? ? "Unpin navigation" : "Pin Navigation", data: {placement: 'right', container: 'body'} do %span.sr-only Toggle navigation pinning - = icon('thumb-tack') + = icon('fw thumb-tack') - if defined?(sidebar) && sidebar = render "layouts/nav/#{sidebar}" From 0054b7ccf46ce5aa5192838d13c0a327a410f43c Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Thu, 14 Jul 2016 14:04:23 +0200 Subject: [PATCH 231/335] Fix duplicated entry in changelog [ci skip] --- CHANGELOG | 3 --- 1 file changed, 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 19286abd74f..43f8f522f41 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -79,7 +79,6 @@ v 8.10.0 (unreleased) - Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests - Add date when user joined the team on the member page - Fix 404 redirect after validation fails importing a GitLab project - - Fix 404 redirect after validation fails importing a GitLab project - Added setting to set new users by default as external !4545 (Dravere) - Add min value for project limit field on user's form !3622 (jastkand) - Reset project pushes_since_gc when we enqueue the git gc call @@ -2223,8 +2222,6 @@ v 7.7.0 - Fixes for edit comments: drag-n-drop images, preview mode, selecting images, save & update - Remove password strength indicator - - v 7.6.0 - Fork repository to groups - New rugged version From 82ad9cf0e9a10a24e58fd68d33359f27d66a02f9 Mon Sep 17 00:00:00 2001 From: winniehell Date: Sat, 9 Jul 2016 03:26:32 +0200 Subject: [PATCH 232/335] Use default cursor for table header of project files (!5165) --- CHANGELOG | 1 + app/assets/stylesheets/pages/tree.scss | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 43f8f522f41..197e3c7bac0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ v 8.10.0 (unreleased) - Wrap code blocks on Activies and Todos page. !4783 (winniehell) - Align flash messages with left side of page content !4959 (winniehell) - Display tooltip for "Copy to Clipboard" button !5164 (winniehell) + - Use default cursor for table header of project files !5165 (winniehell) - Display last commit of deleted branch in push events !4699 (winniehell) - Escape file extension when parsing search results !5141 (winniehell) - Apply the trusted_proxies config to the rack request object for use with rack_attack diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 5b61270daa8..42a20e9775f 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -23,12 +23,11 @@ } &:hover { - cursor: pointer; - td { background-color: $row-hover; border-top: 1px solid $row-hover-border; border-bottom: 1px solid $row-hover-border; + cursor: pointer; } } From b1ab079fae3fbebd0277e16682872632463cd0e2 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 14 Jul 2016 16:03:00 +0200 Subject: [PATCH 233/335] fix updated_at not preserved after import - for GitLab projects --- lib/gitlab/import_export/project_tree_restorer.rb | 5 ++++- .../gitlab/import_export/project_tree_restorer_spec.rb | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb index 025ecc12f9f..051110c23cf 100644 --- a/lib/gitlab/import_export/project_tree_restorer.rb +++ b/lib/gitlab/import_export/project_tree_restorer.rb @@ -12,7 +12,10 @@ module Gitlab json = IO.read(@path) @tree_hash = ActiveSupport::JSON.decode(json) @project_members = @tree_hash.delete('project_members') - create_relations + + ActiveRecord::Base.no_touching do + create_relations + end rescue => e @shared.error(e) false diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index 05ffec8ea0a..877be300262 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -30,6 +30,14 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do expect(Event.where.not(data: nil).first.data[:ref]).not_to be_empty end + it 'preserves updated_at on issues' do + restored_project_json + + issue = Issue.where(description: 'Aliquam enim illo et possimus.').first + + expect(issue.reload.updated_at.to_s).to eq('2016-06-14 15:02:47 UTC') + end + context 'event at forth level of the tree' do let(:event) { Event.where(title: 'test levels').first } From 001c9aa3137e6648fe3994eca4237f9283d0ee6e Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 14 Jul 2016 16:14:30 +0200 Subject: [PATCH 234/335] udpated JS based on feedback --- app/views/projects/new.html.haml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 37f559c1bed..c72d0140bb9 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -157,9 +157,6 @@ }); $('.import_git').click(function( event ) { - if($('#project_import_url').attr('disabled')) { - $('#project_import_url').attr('disabled', false); - } else { - $('#project_import_url').attr('disabled', true); - } + $projectImportUrl = $('#project_import_url') + $projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled')) }); \ No newline at end of file From 37e363c9cff8a0dd0dac7eff42316c3ba589bf55 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 14 Jul 2016 17:06:48 +0200 Subject: [PATCH 235/335] fixed similar issue with gitlab.com importer because why not! --- lib/gitlab/gitlab_import/importer.rb | 45 +++++++++++++++------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/lib/gitlab/gitlab_import/importer.rb b/lib/gitlab/gitlab_import/importer.rb index e6d31ea04c0..46d40f75be6 100644 --- a/lib/gitlab/gitlab_import/importer.rb +++ b/lib/gitlab/gitlab_import/importer.rb @@ -15,32 +15,35 @@ module Gitlab end def execute - project_identifier = CGI.escape(project.import_source) + ActiveRecord::Base.no_touching do + project_identifier = CGI.escape(project.import_source) - # Issues && Comments - issues = client.issues(project_identifier) + # Issues && Comments + issues = client.issues(project_identifier) - issues.each do |issue| - body = @formatter.author_line(issue["author"]["name"]) - body += issue["description"] + issues.each do |issue| + body = @formatter.author_line(issue["author"]["name"]) + body += issue["description"] - comments = client.issue_comments(project_identifier, issue["id"]) + comments = client.issue_comments(project_identifier, issue["id"]) - if comments.any? - body += @formatter.comments_header + if comments.any? + body += @formatter.comments_header + end + + comments.each do |comment| + body += @formatter.comment(comment["author"]["name"], comment["created_at"], comment["body"]) + end + + project.issues.create!( + iid: issue["iid"], + description: body, + title: issue["title"], + state: issue["state"], + updated_at: issue["updated_at"], + author_id: gl_user_id(project, issue["author"]["id"]) + ) end - - comments.each do |comment| - body += @formatter.comment(comment["author"]["name"], comment["created_at"], comment["body"]) - end - - project.issues.create!( - iid: issue["iid"], - description: body, - title: issue["title"], - state: issue["state"], - author_id: gl_user_id(project, issue["author"]["id"]) - ) end true From cc6d3a83c2c50be88110938e11e872b7c29f4696 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 14 Jul 2016 17:13:00 +0200 Subject: [PATCH 236/335] updated changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 19286abd74f..fdad63bf323 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -91,6 +91,7 @@ v 8.10.0 (unreleased) - Redesign Builds and Pipelines pages - Change status color and icon for running builds - Fix markdown rendering for: consecutive labels references, label references that begin with a digit or contains `.` + - Fix last update timestamp on issues not preserved on gitlab.com and project imports v 8.9.6 - Fix importing of events under notes for GitLab projects. !5154 From 905d60b42980832933bebed43d4df1d227e36f15 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 14 Jul 2016 16:26:26 +0100 Subject: [PATCH 237/335] Reduce padding on collapsed diff message --- app/assets/stylesheets/framework/blocks.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 24b1ebab4b0..cf2417fdf63 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -17,6 +17,7 @@ font-size: 16px; line-height: 36px; &.diff-collapsed { + padding: 5px; cursor: pointer; } } From d3653f07227e73e3035c7895ab12a5e0345af744 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Thu, 14 Jul 2016 10:53:48 -0500 Subject: [PATCH 238/335] Change bg color of collapsed diff to blue on hover --- app/assets/stylesheets/framework/blocks.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index cf2417fdf63..ad94e457cfd 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -16,9 +16,14 @@ font-weight: normal; font-size: 16px; line-height: 36px; + &.diff-collapsed { padding: 5px; cursor: pointer; + + &:hover { + background-color: $row-hover; + } } } From 94a08ec1060063e881afccf5187625702839f3ff Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Thu, 14 Jul 2016 12:00:09 -0500 Subject: [PATCH 239/335] Add margin between labels; remove underline hover style on status button --- app/assets/stylesheets/pages/pipelines.scss | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index cbf8297f387..1dc96e440b8 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -43,6 +43,13 @@ border-top-width: 1px; } + .commit-link { + + a:hover { + text-decoration: none; + } + } + .branch-commit { .branch-name { @@ -80,7 +87,12 @@ margin-left: 0; } + .label { + margin-right: 4px; + } + .label-container { + font-size: 0; .label { margin-top: 5px; From 7d456ad436c95a6b081da59cd61cc9672e1e3f5a Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Wed, 15 Jun 2016 10:27:39 -0700 Subject: [PATCH 240/335] update rouge, gollum-lib, and github-markup --- Gemfile | 6 +++--- Gemfile.lock | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index ee23f712f05..3c0b8edabc6 100644 --- a/Gemfile +++ b/Gemfile @@ -61,7 +61,7 @@ gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: 'omniauth-ldap' # Git Wiki # Required manually in config/initializers/gollum.rb to control load order -gem 'gollum-lib', '~> 4.1.0', require: false +gem 'gollum-lib', '~> 4.2', require: false gem 'gollum-rugged_adapter', '~> 0.4.2', require: false # Language detection @@ -105,7 +105,7 @@ gem 'seed-fu', '~> 2.3.5' # Markdown and HTML processing gem 'html-pipeline', '~> 1.11.0' gem 'task_list', '~> 1.0.2', require: 'task_list/railtie' -gem 'github-markup', '~> 1.3.1' +gem 'github-markup', '~> 1.4' gem 'redcarpet', '~> 3.3.3' gem 'RedCloth', '~> 4.3.2' gem 'rdoc', '~>3.6' @@ -113,7 +113,7 @@ gem 'org-ruby', '~> 0.9.12' gem 'creole', '~> 0.5.0' gem 'wikicloth', '0.8.1' gem 'asciidoctor', '~> 1.5.2' -gem 'rouge', '~> 1.11' +gem 'rouge', '~> 2.0' # See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s # and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM diff --git a/Gemfile.lock b/Gemfile.lock index 67c0645c3d9..1514bde61ab 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -264,7 +264,7 @@ GEM escape_utils (~> 1.1.0) mime-types (>= 1.19) rugged (>= 0.23.0b) - github-markup (1.3.3) + github-markup (1.4.0) gitlab-flowdock-git-hook (1.0.1) flowdock (~> 0.7) gitlab-grit (>= 2.4.1) @@ -287,13 +287,13 @@ GEM rubyntlm (~> 0.3) globalid (0.3.6) activesupport (>= 4.1.0) - gollum-grit_adapter (1.0.0) + gollum-grit_adapter (1.0.1) gitlab-grit (~> 2.7, >= 2.7.1) - gollum-lib (4.1.0) - github-markup (~> 1.3.3) + gollum-lib (4.2.1) + github-markup (~> 1.4.0) gollum-grit_adapter (~> 1.0) nokogiri (~> 1.6.4) - rouge (~> 1.9) + rouge (~> 2.0) sanitize (~> 2.1.0) stringex (~> 2.5.1) gollum-rugged_adapter (0.4.2) @@ -578,7 +578,7 @@ GEM railties (>= 4.2.0, < 5.1) rinku (2.0.0) rotp (2.1.2) - rouge (1.11.0) + rouge (2.0.1) rqrcode (0.7.0) chunky_png rqrcode-rails3 (0.1.7) @@ -859,12 +859,12 @@ DEPENDENCIES gemnasium-gitlab-service (~> 0.2) gemojione (~> 2.6) github-linguist (~> 4.7.0) - github-markup (~> 1.3.1) + github-markup (~> 1.4) gitlab-flowdock-git-hook (~> 1.0.1) gitlab_git (~> 10.2) gitlab_meta (= 7.0) gitlab_omniauth-ldap (~> 1.2.1) - gollum-lib (~> 4.1.0) + gollum-lib (~> 4.2) gollum-rugged_adapter (~> 0.4.2) gon (~> 6.0.1) grape (~> 0.13.0) @@ -933,7 +933,7 @@ DEPENDENCIES request_store (~> 1.3.0) rerun (~> 0.11.0) responders (~> 2.0) - rouge (~> 1.11) + rouge (~> 2.0) rqrcode-rails3 (~> 0.1.7) rspec-rails (~> 3.5.0) rspec-retry (~> 0.4.5) From 96c68c503340bf650a545872cb4e8767a1b00f5b Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Wed, 15 Jun 2016 11:29:19 -0700 Subject: [PATCH 241/335] deprecate @anchorlinenos --- lib/rouge/formatters/html_gitlab.rb | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb index 3358ed6773e..2833dbddcf3 100644 --- a/lib/rouge/formatters/html_gitlab.rb +++ b/lib/rouge/formatters/html_gitlab.rb @@ -26,9 +26,6 @@ module Rouge # [+lineanchorsid+] If lineanchors is true the name of the anchors can # be changed with lineanchorsid to e.g. foo-linenumber # (default: 'L'). - # [+anchorlinenos+] If set to true, will wrap line numbers in - # tags. Used in combination with linenos and lineanchors - # (default: false). # [+inline_theme+] Inline CSS styles for the
     tag (default: false).
           def initialize(
               nowrap: false,
    @@ -37,7 +34,6 @@ module Rouge
               linenostart: 1,
               lineanchors: false,
               lineanchorsid: 'L',
    -          anchorlinenos: false,
               inline_theme: nil
           )
             @nowrap = nowrap
    @@ -46,7 +42,6 @@ module Rouge
             @linenostart = linenostart
             @lineanchors = lineanchors
             @lineanchorsid = lineanchorsid
    -        @anchorlinenos = anchorlinenos
             @inline_theme = Theme.find(inline_theme).new if inline_theme.is_a?(String)
           end
     
    @@ -120,11 +115,6 @@ module Rouge
           end
     
           def wrap_linenos(numbers)
    -        if @anchorlinenos
    -          numbers.map! do |number|
    -            "#{number}"
    -          end
    -        end
             numbers.join("\n")
           end
     
    
    From 95d6174a0818230a9811d5d302c77760b49597b1 Mon Sep 17 00:00:00 2001
    From: "http://jneen.net/" 
    Date: Wed, 15 Jun 2016 11:32:08 -0700
    Subject: [PATCH 242/335] remove the unused inline_theme feature
    
    ---
     lib/rouge/formatters/html_gitlab.rb | 12 ++----------
     1 file changed, 2 insertions(+), 10 deletions(-)
    
    diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb
    index 2833dbddcf3..50b1db88c0e 100644
    --- a/lib/rouge/formatters/html_gitlab.rb
    +++ b/lib/rouge/formatters/html_gitlab.rb
    @@ -26,15 +26,13 @@ module Rouge
           # [+lineanchorsid+]   If lineanchors is true the name of the anchors can
           #                     be changed with lineanchorsid to e.g. foo-linenumber
           #                     (default: 'L').
    -      # [+inline_theme+]    Inline CSS styles for the 
     tag (default: false).
           def initialize(
               nowrap: false,
               cssclass: 'highlight',
               linenos: nil,
               linenostart: 1,
               lineanchors: false,
    -          lineanchorsid: 'L',
    -          inline_theme: nil
    +          lineanchorsid: 'L'
           )
             @nowrap = nowrap
             @cssclass = cssclass
    @@ -42,7 +40,6 @@ module Rouge
             @linenostart = linenostart
             @lineanchors = lineanchors
             @lineanchorsid = lineanchorsid
    -        @inline_theme = Theme.find(inline_theme).new if inline_theme.is_a?(String)
           end
     
           def render(tokens)
    @@ -150,12 +147,7 @@ module Rouge
             if tok.shortname.empty?
               val
             else
    -          if @inline_theme
    -            rules = @inline_theme.style_for(tok).rendered_rules
    -            ""
    -          else
    -            "#{val}"
    -          end
    +          "#{val}"
             end
           end
         end
    
    From 681b5af586eb847651af075b325a8b6ef69f4ec6 Mon Sep 17 00:00:00 2001
    From: "http://jneen.net/" 
    Date: Wed, 15 Jun 2016 11:32:27 -0700
    Subject: [PATCH 243/335] do this thing in a clearer way
    
    ---
     lib/gitlab/highlight.rb | 9 ++++++---
     1 file changed, 6 insertions(+), 3 deletions(-)
    
    diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb
    index 41296415e35..adac216b337 100644
    --- a/lib/gitlab/highlight.rb
    +++ b/lib/gitlab/highlight.rb
    @@ -28,11 +28,14 @@ module Gitlab
         end
     
         def highlight(text, continue: true, plain: false)
    +      lexer = @lexer
    +
           if plain
    -        @formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe
    -      else
    -        @formatter.format(@lexer.lex(text, continue: continue)).html_safe
    +        lexer = Rouge::Lexers::PlainText
    +        continue = false
           end
    +
    +      @formatter.format(@lexer.lex(text, continue: continue)).html_safe
         rescue
           @formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe
         end
    
    From 7e8a92fbd1cdaaf1011b301124c0d3f471c871fd Mon Sep 17 00:00:00 2001
    From: "http://jneen.net/" 
    Date: Wed, 15 Jun 2016 11:44:12 -0700
    Subject: [PATCH 244/335] the call site always specifies this option
    
    ---
     lib/gitlab/highlight.rb | 1 -
     1 file changed, 1 deletion(-)
    
    diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb
    index adac216b337..7230a85bc9f 100644
    --- a/lib/gitlab/highlight.rb
    +++ b/lib/gitlab/highlight.rb
    @@ -52,7 +52,6 @@ module Gitlab
     
         def rouge_formatter(options = {})
           options = options.reverse_merge(
    -        nowrap: true,
             cssclass: 'code highlight',
             lineanchors: true,
             lineanchorsid: 'LC'
    
    From e2c9770e03681edafe14212d3db1035a675ba47d Mon Sep 17 00:00:00 2001
    From: "http://jneen.net/" 
    Date: Wed, 15 Jun 2016 11:49:22 -0700
    Subject: [PATCH 245/335] rm dead `highlighter` method
    
    ---
     app/helpers/blob_helper.rb | 4 ----
     1 file changed, 4 deletions(-)
    
    diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
    index 428a42266d0..d639a56f487 100644
    --- a/app/helpers/blob_helper.rb
    +++ b/app/helpers/blob_helper.rb
    @@ -1,8 +1,4 @@
     module BlobHelper
    -  def highlighter(blob_name, blob_content, repository: nil, nowrap: false)
    -    Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap, repository: repository)
    -  end
    -
       def highlight(blob_name, blob_content, repository: nil, nowrap: false, plain: false)
         Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap, plain: plain, repository: repository)
       end
    
    From 7214a221e082c569b4804eb4729e097d4e4b069c Mon Sep 17 00:00:00 2001
    From: "http://jneen.net/" 
    Date: Wed, 15 Jun 2016 11:52:23 -0700
    Subject: [PATCH 246/335] kill the nowrap option
    
    the 
     wrapping is *always* used by the helper, and *never* by
    anywhere else, so pull the wrapping into the helper
    ---
     app/helpers/blob_helper.rb |  5 +++--
     lib/gitlab/highlight.rb    | 16 +++++-----------
     2 files changed, 8 insertions(+), 13 deletions(-)
    
    diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
    index d639a56f487..39f9f935d31 100644
    --- a/app/helpers/blob_helper.rb
    +++ b/app/helpers/blob_helper.rb
    @@ -1,6 +1,7 @@
     module BlobHelper
    -  def highlight(blob_name, blob_content, repository: nil, nowrap: false, plain: false)
    -    Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap, plain: plain, repository: repository)
    +  def highlight(blob_name, blob_content, repository: nil, plain: false)
    +    highlighted = Gitlab::Highlight.highlight(blob_name, blob_content, plain: plain, repository: repository)
    +    raw %<
    #{highlighted}
    > end def no_highlight_files diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index 7230a85bc9f..ad928fec970 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -1,7 +1,7 @@ module Gitlab class Highlight - def self.highlight(blob_name, blob_content, repository: nil, nowrap: true, plain: false) - new(blob_name, blob_content, nowrap: nowrap, repository: repository). + def self.highlight(blob_name, blob_content, repository: nil, plain: false) + new(blob_name, blob_content, repository: repository). highlight(blob_content, continue: false, plain: plain) end @@ -13,13 +13,9 @@ module Gitlab highlight(file_name, blob.data, repository: repository).lines.map!(&:html_safe) end - attr_reader :lexer - def initialize(blob_name, blob_content, repository: nil, nowrap: true) - @blob_name = blob_name - @blob_content = blob_content + def initialize(blob_name, blob_content, repository: nil) + @formatter = rouge_formatter @repository = repository - @formatter = rouge_formatter(nowrap: nowrap) - @lexer = custom_language || begin Rouge::Lexer.guess(filename: blob_name, source: blob_content).new rescue Rouge::Lexer::AmbiguousGuess => e @@ -51,13 +47,11 @@ module Gitlab end def rouge_formatter(options = {}) - options = options.reverse_merge( + Rouge::Formatters::HTMLGitlab.new( cssclass: 'code highlight', lineanchors: true, lineanchorsid: 'LC' ) - - Rouge::Formatters::HTMLGitlab.new(options) end end end From 2ae837f9c9c62272efae4f6dbb1d33cbba325389 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Wed, 15 Jun 2016 11:58:47 -0700 Subject: [PATCH 247/335] kill the nowrap option in HTMLGitlab itself --- lib/rouge/formatters/html_gitlab.rb | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb index 50b1db88c0e..04943c173bd 100644 --- a/lib/rouge/formatters/html_gitlab.rb +++ b/lib/rouge/formatters/html_gitlab.rb @@ -7,8 +7,6 @@ module Rouge # Creates a new Rouge::Formatter::HTMLGitlab instance. # - # [+nowrap+] If set to True, don't wrap the output at all, not - # even inside a
     tag (default: false).
           # [+cssclass+]        CSS class for the wrapping 
    tag # (default: 'highlight'). # [+linenos+] If set to 'table', output line numbers as a table @@ -27,14 +25,12 @@ module Rouge # be changed with lineanchorsid to e.g. foo-linenumber # (default: 'L'). def initialize( - nowrap: false, cssclass: 'highlight', linenos: nil, linenostart: 1, lineanchors: false, lineanchorsid: 'L' ) - @nowrap = nowrap @cssclass = cssclass @linenos = linenos @linenostart = linenostart @@ -60,18 +56,13 @@ module Rouge def render_untableized(tokens) data = process_tokens(tokens) - html = '' - html << "
    " unless @nowrap
    -        html << wrap_lines(data[:code])
    -        html << "
    \n" unless @nowrap - html + wrap_lines(data[:code]) end def render_tableized(tokens) data = process_tokens(tokens) html = '' - html << "
    " unless @nowrap html << '' html << "' html << '
    "
             html << wrap_linenos(data[:numbers])
    @@ -80,7 +71,6 @@ module Rouge
             html << wrap_lines(data[:code])
             html << '
    ' - html << '
    ' unless @nowrap html end From 96274c2765ad4daa23af667b27dc647a3406d7c0 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Wed, 15 Jun 2016 12:04:25 -0700 Subject: [PATCH 248/335] add the wrapping back in for the banzai filter --- lib/banzai/filter/syntax_highlight_filter.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb index 536b478979f..c06de2e5b37 100644 --- a/lib/banzai/filter/syntax_highlight_filter.rb +++ b/lib/banzai/filter/syntax_highlight_filter.rb @@ -20,7 +20,7 @@ module Banzai code = node.text begin - highlighted = block_code(code, language) + highlighted = %<
    #{block_code(code, language)}
    > rescue # Gracefully handle syntax highlighter bugs/errors to ensure # users can still access an issue/comment/etc. @@ -31,6 +31,10 @@ module Banzai replace_parent_pre_element(node, highlighted) end + def css_classes + "code highlight js-syntax-highlight #{lexer.tag}" + end + private def replace_parent_pre_element(node, highlighted) From 504a048b0824aecb81faa3ca4a9503a05c93faac Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Wed, 15 Jun 2016 12:08:04 -0700 Subject: [PATCH 249/335] remove the dead linenos and linenostart options and the methods that relied on them --- lib/rouge/formatters/html_gitlab.rb | 46 ++--------------------------- 1 file changed, 2 insertions(+), 44 deletions(-) diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb index 04943c173bd..b76021eef77 100644 --- a/lib/rouge/formatters/html_gitlab.rb +++ b/lib/rouge/formatters/html_gitlab.rb @@ -9,14 +9,6 @@ module Rouge # # [+cssclass+] CSS class for the wrapping
    tag # (default: 'highlight'). - # [+linenos+] If set to 'table', output line numbers as a table - # with two cells, one containing the line numbers, - # the other the whole code. This is copy paste friendly, - # but may cause alignment problems with some browsers - # or fonts. If set to 'inline', the line numbers will - # be integrated in the
     tag that contains
    -      #                     the code (default: nil).
    -      # [+linenostart+]     The line number for the first line (default: 1).
           # [+lineanchors+]     If set to true the formatter will wrap each output
           #                     line in an anchor tag with a name of L-linenumber.
           #                     This allows easy linking to certain lines
    @@ -26,53 +18,23 @@ module Rouge
           #                     (default: 'L').
           def initialize(
               cssclass: 'highlight',
    -          linenos: nil,
    -          linenostart: 1,
               lineanchors: false,
               lineanchorsid: 'L'
           )
             @cssclass = cssclass
    -        @linenos = linenos
    -        @linenostart = linenostart
             @lineanchors = lineanchors
             @lineanchorsid = lineanchorsid
           end
     
           def render(tokens)
    -        case @linenos
    -        when 'table'
    -          render_tableized(tokens)
    -        when 'inline'
    -          render_untableized(tokens)
    -        else
    -          render_untableized(tokens)
    -        end
    -      end
    -
    -      alias_method :format, :render
    -
    -      private
    -
    -      def render_untableized(tokens)
             data = process_tokens(tokens)
     
             wrap_lines(data[:code])
           end
     
    -      def render_tableized(tokens)
    -        data = process_tokens(tokens)
    +      alias_method :format, :render
     
    -        html = ''
    -        html << ''
    -        html << "'
    -        html << "'
    -        html << '
    "
    -        html << wrap_linenos(data[:numbers])
    -        html << '
    "
    -        html << wrap_lines(data[:code])
    -        html << '
    ' - html - end + private def process_tokens(tokens) rendered = [] @@ -101,10 +63,6 @@ module Rouge { numbers: numbers, code: rendered } end - def wrap_linenos(numbers) - numbers.join("\n") - end - def wrap_lines(lines) if @lineanchors lines = lines.each_with_index.map do |line, index| From 55dc7d09b35c43679d0c298885c10aa59818bf66 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Wed, 15 Jun 2016 12:12:48 -0700 Subject: [PATCH 250/335] trim more dead code --- lib/rouge/formatters/html_gitlab.rb | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb index b76021eef77..791a9523884 100644 --- a/lib/rouge/formatters/html_gitlab.rb +++ b/lib/rouge/formatters/html_gitlab.rb @@ -57,10 +57,7 @@ module Rouge # Add leftover text rendered << current_line if current_line.present? - num_lines = rendered.size - numbers = (@linenostart..num_lines + @linenostart - 1).to_a - - { numbers: numbers, code: rendered } + { code: rendered } end def wrap_lines(lines) @@ -68,20 +65,8 @@ module Rouge lines = lines.each_with_index.map do |line, index| number = index + @linenostart - if @linenos == 'inline' - "" \ - "#{number}" \ - "#{line}" \ - '' - else - "#{line}" \ - '' - end - end - elsif @linenos == 'inline' - lines = lines.each_with_index.map do |line, index| - number = index + @linenostart - "#{number}#{line}" + "#{line}" \ + '' end end From 3bb65815b0cb7731b3262ff216506582951a6f6f Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Thu, 14 Jul 2016 09:51:10 -0700 Subject: [PATCH 251/335] kill the :cssclass option --- lib/banzai/filter/syntax_highlight_filter.rb | 3 +-- lib/gitlab/highlight.rb | 1 - lib/rouge/formatters/html_gitlab.rb | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb index c06de2e5b37..7f838ef4c08 100644 --- a/lib/banzai/filter/syntax_highlight_filter.rb +++ b/lib/banzai/filter/syntax_highlight_filter.rb @@ -44,8 +44,7 @@ module Banzai # Override Rouge::Plugins::Redcarpet#rouge_formatter def rouge_formatter(lexer) - Rouge::Formatters::HTMLGitlab.new( - cssclass: "code highlight js-syntax-highlight #{lexer.tag}") + Rouge::Formatters::HTMLGitlab.new end end end diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index ad928fec970..aaef569d870 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -48,7 +48,6 @@ module Gitlab def rouge_formatter(options = {}) Rouge::Formatters::HTMLGitlab.new( - cssclass: 'code highlight', lineanchors: true, lineanchorsid: 'LC' ) diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb index 791a9523884..b9e3272e0b5 100644 --- a/lib/rouge/formatters/html_gitlab.rb +++ b/lib/rouge/formatters/html_gitlab.rb @@ -17,11 +17,9 @@ module Rouge # be changed with lineanchorsid to e.g. foo-linenumber # (default: 'L'). def initialize( - cssclass: 'highlight', lineanchors: false, lineanchorsid: 'L' ) - @cssclass = cssclass @lineanchors = lineanchors @lineanchorsid = lineanchorsid end From 34a3d2a340b5d235da3958176bca6e0de6679a0f Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Wed, 15 Jun 2016 12:15:47 -0700 Subject: [PATCH 252/335] without line anchors, this is just the plain HTML formatter --- lib/banzai/filter/syntax_highlight_filter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb index 7f838ef4c08..144d8c175dc 100644 --- a/lib/banzai/filter/syntax_highlight_filter.rb +++ b/lib/banzai/filter/syntax_highlight_filter.rb @@ -44,7 +44,7 @@ module Banzai # Override Rouge::Plugins::Redcarpet#rouge_formatter def rouge_formatter(lexer) - Rouge::Formatters::HTMLGitlab.new + Rouge::Formatters::HTML.new end end end From e1824aa101a2181fe7e5ce080582cfa188d19da8 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Wed, 15 Jun 2016 12:32:55 -0700 Subject: [PATCH 253/335] use the new token_lines interface to format lines --- lib/gitlab/highlight.rb | 5 +- lib/rouge/formatters/html_gitlab.rb | 81 ++++------------------------- 2 files changed, 12 insertions(+), 74 deletions(-) diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index aaef569d870..ba157cc98cc 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -47,10 +47,7 @@ module Gitlab end def rouge_formatter(options = {}) - Rouge::Formatters::HTMLGitlab.new( - lineanchors: true, - lineanchorsid: 'LC' - ) + Rouge::Formatters::HTMLGitlab.new end end end diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb index b9e3272e0b5..723bac574dd 100644 --- a/lib/rouge/formatters/html_gitlab.rb +++ b/lib/rouge/formatters/html_gitlab.rb @@ -2,83 +2,24 @@ require 'cgi' module Rouge module Formatters - class HTMLGitlab < Rouge::Formatter + class HTMLGitlab < Rouge::Formatters::HTML tag 'html_gitlab' # Creates a new Rouge::Formatter::HTMLGitlab instance. # - # [+cssclass+] CSS class for the wrapping
    tag - # (default: 'highlight'). - # [+lineanchors+] If set to true the formatter will wrap each output - # line in an anchor tag with a name of L-linenumber. - # This allows easy linking to certain lines - # (default: false). - # [+lineanchorsid+] If lineanchors is true the name of the anchors can - # be changed with lineanchorsid to e.g. foo-linenumber - # (default: 'L'). - def initialize( - lineanchors: false, - lineanchorsid: 'L' - ) - @lineanchors = lineanchors - @lineanchorsid = lineanchorsid + # [+linenostart+] The line number for the first line (default: 1). + def initialize(linenostart: 1) + @linenostart = linenostart + @line_number = linenostart end - def render(tokens) - data = process_tokens(tokens) + def stream(tokens, &b) + token_lines(tokens) do |line| + yield %<> + line.each { |token, value| yield span(token, value) } + yield %<\n> - wrap_lines(data[:code]) - end - - alias_method :format, :render - - private - - def process_tokens(tokens) - rendered = [] - current_line = '' - - tokens.each do |tok, val| - # In the case of multi-line values (e.g. comments), we need to apply - # styling to each line since span elements are inline. - val.lines.each do |line| - stripped = line.chomp - current_line << span(tok, stripped) - - if line.end_with?("\n") - rendered << current_line - current_line = '' - end - end - end - - # Add leftover text - rendered << current_line if current_line.present? - - { code: rendered } - end - - def wrap_lines(lines) - if @lineanchors - lines = lines.each_with_index.map do |line, index| - number = index + @linenostart - - "#{line}" \ - '' - end - end - - lines.join("\n") - end - - def span(tok, val) - # http://stackoverflow.com/a/1600584/2587286 - val = CGI.escapeHTML(val) - - if tok.shortname.empty? - val - else - "#{val}" + @line_number += 1 end end end From 6107933ba30a2ac6e591971d4a7581a5611c42c0 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Wed, 15 Jun 2016 14:01:47 -0700 Subject: [PATCH 254/335] inline #rouge_formatter --- lib/gitlab/highlight.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index ba157cc98cc..84bd616d608 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -13,8 +13,8 @@ module Gitlab highlight(file_name, blob.data, repository: repository).lines.map!(&:html_safe) end - def initialize(blob_name, blob_content, repository: nil) - @formatter = rouge_formatter + def initialize(blob_name, blob_content) + @formatter = Rouge::Formatters::HTMLGitlab.new @repository = repository @lexer = custom_language || begin Rouge::Lexer.guess(filename: blob_name, source: blob_content).new @@ -45,9 +45,5 @@ module Gitlab Rouge::Lexer.find_fancy(language_name) end - - def rouge_formatter(options = {}) - Rouge::Formatters::HTMLGitlab.new - end end end From 4365144f5cfa1ab8ada3a75447e9d494f406980e Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Wed, 15 Jun 2016 14:01:57 -0700 Subject: [PATCH 255/335] no longer need cgi --- lib/rouge/formatters/html_gitlab.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb index 723bac574dd..31533fc3b8c 100644 --- a/lib/rouge/formatters/html_gitlab.rb +++ b/lib/rouge/formatters/html_gitlab.rb @@ -1,5 +1,3 @@ -require 'cgi' - module Rouge module Formatters class HTMLGitlab < Rouge::Formatters::HTML From ff7e679bca6a0303dcb3cb07dbe26aa32f6fb649 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Wed, 15 Jun 2016 15:02:13 -0700 Subject: [PATCH 256/335] we no longer encode double-quotes --- spec/lib/gitlab/diff/highlight_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb index fb5d50a5c68..4408d5bcdb4 100644 --- a/spec/lib/gitlab/diff/highlight_spec.rb +++ b/spec/lib/gitlab/diff/highlight_spec.rb @@ -28,13 +28,13 @@ describe Gitlab::Diff::Highlight, lib: true do end it 'highlights and marks removed lines' do - code = %Q{- raise "System commands must be given as an array of strings"\n} + code = %Q{- raise "System commands must be given as an array of strings"\n} expect(subject[4].text).to eq(code) end it 'highlights and marks added lines' do - code = %Q{+ raise RuntimeError, "System commands must be given as an array of strings"\n} + code = %Q{+ raise RuntimeError, "System commands must be given as an array of strings"\n} expect(subject[5].text).to eq(code) end @@ -67,7 +67,7 @@ describe Gitlab::Diff::Highlight, lib: true do end it 'marks added lines' do - code = %Q{+ raise RuntimeError, "System commands must be given as an array of strings"} + code = %Q{+ raise RuntimeError, "System commands must be given as an array of strings"} expect(subject[5].text).to eq(code) expect(subject[5].text).to be_html_safe From f82287e2cc3a57a21be74263be81716c5b3787b7 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Thu, 16 Jun 2016 15:15:18 -0700 Subject: [PATCH 257/335] use the local lexer variable to respect plain: ... --- lib/gitlab/highlight.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index 84bd616d608..fbed65a055b 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -31,7 +31,7 @@ module Gitlab continue = false end - @formatter.format(@lexer.lex(text, continue: continue)).html_safe + @formatter.format(lexer.lex(text, continue: continue)).html_safe rescue @formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe end From e9f191907cb9c9d03b5ad0b67bd3e114f2111a18 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Thu, 16 Jun 2016 15:15:34 -0700 Subject: [PATCH 258/335] apparently this gets encoded now? --- spec/lib/gitlab/diff/highlight_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb index 4408d5bcdb4..88e4115c453 100644 --- a/spec/lib/gitlab/diff/highlight_spec.rb +++ b/spec/lib/gitlab/diff/highlight_spec.rb @@ -67,7 +67,7 @@ describe Gitlab::Diff::Highlight, lib: true do end it 'marks added lines' do - code = %Q{+ raise RuntimeError, "System commands must be given as an array of strings"} + code = %Q{+ raise RuntimeError, "System commands must be given as an array of strings"} expect(subject[5].text).to eq(code) expect(subject[5].text).to be_html_safe From 362d7fde084d0e9eeeeea0c78c2f455c6e86a35b Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Thu, 16 Jun 2016 16:05:53 -0700 Subject: [PATCH 259/335] bugfix: don't error in css_classes --- lib/banzai/filter/syntax_highlight_filter.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb index 144d8c175dc..17f9164bcb7 100644 --- a/lib/banzai/filter/syntax_highlight_filter.rb +++ b/lib/banzai/filter/syntax_highlight_filter.rb @@ -19,8 +19,15 @@ module Banzai language = node.attr('class') code = node.text + lexer = Rouge::Lexer.find_fancy(language) + formatter = Rouge::Formatters::HTML.new + css_classes = "code highlight js-syntax-highlight #{lexer.tag}" + begin - highlighted = %<
    #{block_code(code, language)}
    > + highlighted = '' + highlighted << %<
    >
    +          highlighted << formatter.format(lexer.lex(code))
    +          highlighted << %<
    > rescue # Gracefully handle syntax highlighter bugs/errors to ensure # users can still access an issue/comment/etc. @@ -31,10 +38,6 @@ module Banzai replace_parent_pre_element(node, highlighted) end - def css_classes - "code highlight js-syntax-highlight #{lexer.tag}" - end - private def replace_parent_pre_element(node, highlighted) From 001b1ff312df04e014a82fdb831a77cfaf66fd62 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Tue, 21 Jun 2016 10:52:11 -0700 Subject: [PATCH 260/335] rm spec for a deleted method --- spec/helpers/blob_helper_spec.rb | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb index 6d1c02db297..b6e18c6a753 100644 --- a/spec/helpers/blob_helper_spec.rb +++ b/spec/helpers/blob_helper_spec.rb @@ -54,20 +54,6 @@ describe BlobHelper do end end - describe "#highlighter" do - it 'should highlight continued blocks' do - # Both lines have LC1 as ID since formatter doesn't support continue at the moment - expected = [ - '(make-pathname :defaults name', - ':type "assem"))' - ] - - highlighter = helper.highlighter(blob_name, blob_content, nowrap: true) - result = split_content.map{ |content| highlighter.highlight(content) } - expect(result).to eq(expected) - end - end - describe "#sanitize_svg" do let(:input_svg_path) { File.join(Rails.root, 'spec', 'fixtures', 'unsanitized.svg') } let(:data) { open(input_svg_path).read } From d625f652916c7039797190351d1dc04c6152ce78 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Tue, 21 Jun 2016 11:23:10 -0700 Subject: [PATCH 261/335] eliminate the final newline in
     blocks
    
    ---
     lib/rouge/formatters/html_gitlab.rb | 6 +++++-
     1 file changed, 5 insertions(+), 1 deletion(-)
    
    diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb
    index 31533fc3b8c..b76cf14a536 100644
    --- a/lib/rouge/formatters/html_gitlab.rb
    +++ b/lib/rouge/formatters/html_gitlab.rb
    @@ -12,10 +12,14 @@ module Rouge
           end
     
           def stream(tokens, &b)
    +        is_first = true
             token_lines(tokens) do |line|
    +          yield "\n" unless is_first
    +          is_first = false
    +
               yield %<>
               line.each { |token, value| yield span(token, value) }
    -          yield %<\n>
    +          yield %<>
     
               @line_number += 1
             end
    
    From e0ee9dacd1bf6acab6774a2add992ae14fa0e2fc Mon Sep 17 00:00:00 2001
    From: "http://jneen.net/" 
    Date: Tue, 21 Jun 2016 11:24:12 -0700
    Subject: [PATCH 262/335] remove uses of the nowrap: feature
    
    ---
     spec/helpers/blob_helper_spec.rb | 18 +++++++++---------
     1 file changed, 9 insertions(+), 9 deletions(-)
    
    diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb
    index b6e18c6a753..e5dfa61fa6a 100644
    --- a/spec/helpers/blob_helper_spec.rb
    +++ b/spec/helpers/blob_helper_spec.rb
    @@ -16,19 +16,19 @@ describe BlobHelper do
     
       describe '#highlight' do
         it 'should return plaintext for unknown lexer context' do
    -      result = helper.highlight(blob_name, no_context_content, nowrap: true)
    -      expect(result).to eq(':type "assem"))')
    +      result = helper.highlight(blob_name, no_context_content)
    +      expect(result).to eq(%<
    :type "assem"))
    >) end it 'should highlight single block' do - expected = %Q[(make-pathname :defaults name -:type "assem"))] + expected = %Q[
    (make-pathname :defaults name
    +:type "assem"))
    ] - expect(helper.highlight(blob_name, blob_content, nowrap: true)).to eq(expected) + expect(helper.highlight(blob_name, blob_content)).to eq(expected) end it 'should highlight multi-line comments' do - result = helper.highlight(blob_name, multiline_content, nowrap: true) + result = helper.highlight(blob_name, multiline_content) html = Nokogiri::HTML(result) lines = html.search('.s') expect(lines.count).to eq(3) @@ -41,14 +41,14 @@ describe BlobHelper do let(:blob_name) { 'test.diff' } let(:blob_content) { "+aaa\n+bbb\n- ccc\n ddd\n"} let(:expected) do - %q(+aaa + %q(
    +aaa
     +bbb
     - ccc
    - ddd)
    + ddd
    ) end it 'should highlight each line properly' do - result = helper.highlight(blob_name, blob_content, nowrap: true) + result = helper.highlight(blob_name, blob_content) expect(result).to eq(expected) end end From 4e3db22fe0a469a8429f50b99a7edde8f5f28312 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Tue, 21 Jun 2016 11:48:39 -0700 Subject: [PATCH 263/335] don't expect " encoding anymore --- spec/fixtures/parallel_diff_result.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/fixtures/parallel_diff_result.yml b/spec/fixtures/parallel_diff_result.yml index 333eda1191a..37066c8e930 100644 --- a/spec/fixtures/parallel_diff_result.yml +++ b/spec/fixtures/parallel_diff_result.yml @@ -121,7 +121,7 @@ :type: old :number: 9 :text: | - - raise "System commands must be given as an array of strings" + - raise "System commands must be given as an array of strings" :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9 :position: !ruby/object:Gitlab::Diff::Position attributes: @@ -136,7 +136,7 @@ :type: new :number: 9 :text: | - + raise RuntimeError, "System commands must be given as an array of strings" + + raise RuntimeError, "System commands must be given as an array of strings" :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9 :position: !ruby/object:Gitlab::Diff::Position attributes: @@ -241,7 +241,7 @@ :type: old :number: 13 :text: | - - vars = { "PWD" => path } + - vars = { "PWD" => path } :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_13_13 :position: !ruby/object:Gitlab::Diff::Position attributes: @@ -315,7 +315,7 @@ :type: new :number: 15 :text: | - + "PWD" => path + + "PWD" => path :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15 :position: !ruby/object:Gitlab::Diff::Position attributes: @@ -623,7 +623,7 @@ :type: :number: 20 :text: |2 - @cmd_output = "" + @cmd_output = "" :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26 :position: !ruby/object:Gitlab::Diff::Position attributes: @@ -638,7 +638,7 @@ :type: :number: 26 :text: |2 - @cmd_output = "" + @cmd_output = "" :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26 :position: !ruby/object:Gitlab::Diff::Position attributes: From ca32a542d7a36c1d27fc8851534a0c15048a79dd Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Tue, 21 Jun 2016 11:51:29 -0700 Subject: [PATCH 264/335] don't expect a random newline at the end of the thing? --- spec/lib/banzai/filter/syntax_highlight_filter_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb index 407617f3307..50be175c1c3 100644 --- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb +++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb @@ -5,7 +5,7 @@ describe Banzai::Filter::SyntaxHighlightFilter, lib: true do it 'highlights valid code blocks' do result = filter('
    def fun end')
    -    expect(result.to_html).to eq("
    def fun end
    \n") + expect(result.to_html).to eq("
    def fun end
    ") end it 'passes through invalid code blocks' do From 2f0b29227d15bc30b2f13ee415ba83d052fd7f68 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Tue, 21 Jun 2016 13:08:24 -0700 Subject: [PATCH 265/335] stub out errors from the formatter since we've eliminated #block_code --- spec/lib/banzai/filter/syntax_highlight_filter_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb index 50be175c1c3..48ebc81cf82 100644 --- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb +++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb @@ -9,7 +9,7 @@ describe Banzai::Filter::SyntaxHighlightFilter, lib: true do end it 'passes through invalid code blocks' do - allow_any_instance_of(described_class).to receive(:block_code).and_raise(StandardError) + allow_any_instance_of(Rouge::Formatter).to receive(:format).and_raise(StandardError) result = filter('
    This is a test
    ') expect(result.to_html).to eq('
    This is a test
    ') From 734ed9c59a486651820907051fbee149898f01e4 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Tue, 21 Jun 2016 13:12:21 -0700 Subject: [PATCH 266/335] expect final newlines from the banzai filter --- spec/helpers/events_helper_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb index c0d2be98e85..6b5e3d93d48 100644 --- a/spec/helpers/events_helper_spec.rb +++ b/spec/helpers/events_helper_spec.rb @@ -57,7 +57,7 @@ describe EventsHelper do expected = '
    ' \
             "def test\n" \
             "  \'hello world\'\n" \
    -        "end" \
    +        "end\n" \
             '
    ' expect(helper.event_note(input)).to eq(expected) end From 7ceb9913aa87f1691411d725417e1fd1aadacb9b Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Mon, 27 Jun 2016 13:19:11 -0700 Subject: [PATCH 267/335] update to rouge 2.0.2 --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1514bde61ab..d87decc324e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -578,7 +578,7 @@ GEM railties (>= 4.2.0, < 5.1) rinku (2.0.0) rotp (2.1.2) - rouge (2.0.1) + rouge (2.0.2) rqrcode (0.7.0) chunky_png rqrcode-rails3 (0.1.7) From 9694b9925f75075b96e2ff719a7e01e55e10c39f Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Thu, 14 Jul 2016 12:31:38 -0500 Subject: [PATCH 268/335] Add margin between buttons if both retry and cancel are present --- app/assets/stylesheets/pages/pipelines.scss | 6 ++++++ app/views/projects/ci/pipelines/_pipeline.html.haml | 13 +++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 1dc96e440b8..08da4e290dc 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -128,6 +128,12 @@ color: $table-text-gray; } + .cancel-retry-btns { + .btn:not(:first-child) { + margin-left: 8px; + } + } + .dropdown-toggle, .dropdown-menu { color: $table-text-gray; diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index 4ef72ff5d2a..b53a8633937 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -80,9 +80,10 @@ %span Download '#{build.name}' artifacts - if can?(current_user, :update_pipeline, @project) - - if pipeline.retryable? - = link_to retry_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn has-tooltip', title: "Retry", method: :post do - = icon("repeat") - - if pipeline.cancelable? - = link_to cancel_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do - = icon("remove") + .cancel-retry-btns + - if pipeline.retryable? + = link_to retry_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn has-tooltip', title: "Retry", method: :post do + = icon("repeat") + - if pipeline.cancelable? + = link_to cancel_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do + = icon("remove") From d54a281e3d1c543f4cbd550c62f62d225f595bbb Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 12 Jul 2016 16:40:05 -0300 Subject: [PATCH 269/335] Fix creating group with space in group path --- app/views/layouts/_search.html.haml | 2 +- spec/features/groups_spec.rb | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml index 245b9c3b4d4..f7580f00159 100644 --- a/app/views/layouts/_search.html.haml +++ b/app/views/layouts/_search.html.haml @@ -44,7 +44,7 @@ name: "#{j(@project.name)}" }; - - if @group and @group.path + - if @group && @group.persisted? && @group.path :javascript gl.groupOptions = gl.groupOptions || {}; gl.groupOptions["#{j(@group.path)}"] = { diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index 891df65216d..2d8b59472e8 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -1,14 +1,26 @@ require 'spec_helper' feature 'Group', feature: true do + before do + login_as(:admin) + end + + describe 'creating a group with space in group path' do + it 'renders new group form with validation errors' do + visit new_group_path + fill_in 'Group path', with: 'space group' + + click_button 'Create group' + + expect(current_path).to eq(groups_path) + expect(page).to have_content("Path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-' or end in '.'.") + end + end + describe 'description' do let(:group) { create(:group) } let(:path) { group_path(group) } - before do - login_as(:admin) - end - it 'parses Markdown' do group.update_attribute(:description, 'This is **my** group') visit path From e367bbff164cef36fcb4d5f819714347ed9a2ebd Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 12 Jul 2016 16:40:37 -0300 Subject: [PATCH 270/335] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 6b24b2c5b32..7e784bd641d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -91,6 +91,7 @@ v 8.10.0 (unreleased) - Redesign Builds and Pipelines pages - Change status color and icon for running builds - Fix markdown rendering for: consecutive labels references, label references that begin with a digit or contains `.` + - Fix creating group with space in group path v 8.9.6 - Fix importing of events under notes for GitLab projects. !5154 From 822304b19f81386a36eb7175f7384e2a8c5fd5e1 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Thu, 14 Jul 2016 11:40:55 -0700 Subject: [PATCH 271/335] fix Gitlab::Highlight#initializer bugs from rebase --- lib/gitlab/highlight.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index fbed65a055b..57b7fc139f8 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -13,9 +13,10 @@ module Gitlab highlight(file_name, blob.data, repository: repository).lines.map!(&:html_safe) end - def initialize(blob_name, blob_content) + def initialize(blob_name, blob_content, repository: nil) @formatter = Rouge::Formatters::HTMLGitlab.new @repository = repository + @blob_name = blob_name @lexer = custom_language || begin Rouge::Lexer.guess(filename: blob_name, source: blob_content).new rescue Rouge::Lexer::AmbiguousGuess => e From b468672d7634b13b2a2bea5685a5e1cbc9d82c23 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Thu, 14 Jul 2016 11:44:59 -0700 Subject: [PATCH 272/335] style: factor out `@lexer` into a method --- lib/gitlab/highlight.rb | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index 57b7fc139f8..a9e429a29f4 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -17,26 +17,30 @@ module Gitlab @formatter = Rouge::Formatters::HTMLGitlab.new @repository = repository @blob_name = blob_name - @lexer = custom_language || begin + @blob_content = blob_content + end + + def highlight(text, continue: true, plain: false) + if plain + hl_lexer = Rouge::Lexers::PlainText + continue = false + else + hl_lexer = self.lexer + end + + @formatter.format(hl_lexer.lex(text, continue: continue)).html_safe + rescue + @formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe + end + + def lexer + @lexer ||= custom_language || begin Rouge::Lexer.guess(filename: blob_name, source: blob_content).new rescue Rouge::Lexer::AmbiguousGuess => e e.alternatives.sort_by(&:tag).first end end - def highlight(text, continue: true, plain: false) - lexer = @lexer - - if plain - lexer = Rouge::Lexers::PlainText - continue = false - end - - @formatter.format(lexer.lex(text, continue: continue)).html_safe - rescue - @formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe - end - private def custom_language From f7f082f46c919e5c8c730a2c2ab0a7baf086b01b Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Thu, 14 Jul 2016 12:19:39 -0700 Subject: [PATCH 273/335] bump rouge to 2.0.3 --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index d87decc324e..eab04ec3a25 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -578,7 +578,7 @@ GEM railties (>= 4.2.0, < 5.1) rinku (2.0.0) rotp (2.1.2) - rouge (2.0.2) + rouge (2.0.3) rqrcode (0.7.0) chunky_png rqrcode-rails3 (0.1.7) From c763c7e402599a2789e260ecf61c11c68381aaa5 Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Thu, 14 Jul 2016 12:21:22 -0700 Subject: [PATCH 274/335] use the proper variable names o_O --- lib/gitlab/highlight.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index a9e429a29f4..9360afedfcb 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -35,8 +35,8 @@ module Gitlab def lexer @lexer ||= custom_language || begin - Rouge::Lexer.guess(filename: blob_name, source: blob_content).new - rescue Rouge::Lexer::AmbiguousGuess => e + Rouge::Lexer.guess(filename: @blob_name, source: @blob_content).new + rescue Rouge::Guesser::Ambiguous => e e.alternatives.sort_by(&:tag).first end end From 42a1dc50414909fd1907b5bef57219ea9361c6b4 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 11 Jul 2016 12:58:32 -0500 Subject: [PATCH 275/335] Remove unnecesary CSS class --- app/views/admin/projects/index.html.haml | 2 +- app/views/admin/users/_user.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 7fbce25b2c4..1e755785d90 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -66,7 +66,7 @@ %ul.projects-list.content-list - @projects.each_with_index do |project| %li.project-row - .controls.pull-right + .controls - if project.archived %span.label.label-warning archived %span.label.label-gray diff --git a/app/views/admin/users/_user.html.haml b/app/views/admin/users/_user.html.haml index d3519f616f6..4bf1c9cde3c 100644 --- a/app/views/admin/users/_user.html.haml +++ b/app/views/admin/users/_user.html.haml @@ -14,7 +14,7 @@ %span It's you! .user-email = mail_to user.email, user.email - .controls.pull-right + .controls = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: 'btn' - unless user == current_user .dropdown.inline From 2ed52071522f3cafd12ee8d9cd15d53db4171e1b Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 11 Jul 2016 12:59:01 -0500 Subject: [PATCH 276/335] Rename .group-controls to .controls --- app/assets/stylesheets/pages/groups.scss | 4 ++-- app/views/admin/groups/_group.html.haml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index 701b9388454..a0b8bd2e28d 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -44,7 +44,7 @@ display: -ms-flexbox; display: flex; - .group-avatar, .group-details, .group-controls { + .group-avatar, .group-details, .controls { display: -webkit-flex; display: -ms-flexbox; display: flex; @@ -56,7 +56,7 @@ min-width: 0; } - .group-controls { + .controls { align-items: center; a { diff --git a/app/views/admin/groups/_group.html.haml b/app/views/admin/groups/_group.html.haml index 59fd6c3fea0..02b943141e4 100644 --- a/app/views/admin/groups/_group.html.haml +++ b/app/views/admin/groups/_group.html.haml @@ -15,6 +15,6 @@ - if group.description.present? .description = markdown(group.description, pipeline: :description) - .group-controls.hidden-xs + .controls.hidden-xs = link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: 'btn' = link_to 'Delete', [:admin, group], data: { confirm: "Are you sure you want to remove #{group.name}?" }, method: :delete, class: 'btn btn-remove' From 75528e19302dfc86254eb4e9f5d2878f64bc80b1 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 11 Jul 2016 12:59:23 -0500 Subject: [PATCH 277/335] Make CSS consistent again --- app/assets/stylesheets/pages/admin.scss | 8 +------- app/assets/stylesheets/pages/groups.scss | 4 ---- app/assets/stylesheets/pages/projects.scss | 4 ++++ 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/app/assets/stylesheets/pages/admin.scss b/app/assets/stylesheets/pages/admin.scss index 1d34a7f79ae..5607239d92d 100644 --- a/app/assets/stylesheets/pages/admin.scss +++ b/app/assets/stylesheets/pages/admin.scss @@ -88,13 +88,7 @@ .user-name { display: inline-block; - font-weight: bold; - } - - .controls { - > .btn, > .dropdown { - margin-left: 5px; - } + font-weight: 600; } .dropdown { diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index a0b8bd2e28d..3682b886cb3 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -58,10 +58,6 @@ .controls { align-items: center; - - a { - margin-left: 5px; - } } } diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 5be911dc562..fa4af0f9c8b 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -482,6 +482,10 @@ pre.light-well { a:hover { text-decoration: none; } + + > span { + margin-left: 10px; + } } } From 079d9c04404b37d7b15ff5da6a313d08ca599315 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 11 Jul 2016 15:02:52 -0500 Subject: [PATCH 278/335] Fix New Group button spacing on mobile --- app/assets/stylesheets/pages/search.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss index 9e9b18fdbb8..c9d436d72ba 100644 --- a/app/assets/stylesheets/pages/search.scss +++ b/app/assets/stylesheets/pages/search.scss @@ -185,7 +185,7 @@ padding-right: $gl-padding + 15px; } - .btn-search { + .btn-search, .btn-new { width: 100%; margin-top: 5px; From 01ff8ae5df7e00db16aa64f056098626b8ae795b Mon Sep 17 00:00:00 2001 From: winniehell Date: Thu, 14 Jul 2016 23:43:27 +0200 Subject: [PATCH 279/335] Display tooltip for mentioned users and groups (!5261) --- CHANGELOG | 1 + lib/banzai/filter/user_reference_filter.rb | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6b24b2c5b32..eeb2d377bf6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -22,6 +22,7 @@ v 8.10.0 (unreleased) - Add Sidekiq queue duration to transaction metrics. - Add a new column `artifacts_size` to table `ci_builds` !4964 - Let Workhorse serve format-patch diffs + - Display tooltip for mentioned users and groups !5261 (winniehell) - Added day name to contribution calendar tooltips - Make images fit to the size of the viewport !4810 - Fix check for New Branch button on Issue page !4630 (winniehell) diff --git a/lib/banzai/filter/user_reference_filter.rb b/lib/banzai/filter/user_reference_filter.rb index 5b0a6d8541b..e1ca7f4d24b 100644 --- a/lib/banzai/filter/user_reference_filter.rb +++ b/lib/banzai/filter/user_reference_filter.rb @@ -112,7 +112,7 @@ module Banzai data = data_attribute(project: project.id, author: author.try(:id)) text = link_text || User.reference_prefix + 'all' - link_tag(url, data, text) + link_tag(url, data, text, 'All Project and Group Members') end def link_to_namespace(namespace, link_text: nil) @@ -128,7 +128,7 @@ module Banzai data = data_attribute(group: namespace.id) text = link_text || Group.reference_prefix + group - link_tag(url, data, text) + link_tag(url, data, text, namespace.name) end def link_to_user(user, namespace, link_text: nil) @@ -136,11 +136,11 @@ module Banzai data = data_attribute(user: namespace.owner_id) text = link_text || User.reference_prefix + user - link_tag(url, data, text) + link_tag(url, data, text, namespace.owner_name) end - def link_tag(url, data, text) - %(#{escape_once(text)}) + def link_tag(url, data, text, title) + %(#{escape_once(text)}) end end end From 5fc690df6ec2350c81f02098edba271a1eba5e0b Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Thu, 14 Jul 2016 17:13:38 -0500 Subject: [PATCH 280/335] Make admin/groups view consistent with dashboard/groups --- app/views/admin/groups/_group.html.haml | 37 +++++++++++++------------ 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/app/views/admin/groups/_group.html.haml b/app/views/admin/groups/_group.html.haml index 02b943141e4..f6c76302da5 100644 --- a/app/views/admin/groups/_group.html.haml +++ b/app/views/admin/groups/_group.html.haml @@ -1,20 +1,23 @@ -- css_class = '' unless local_assigns[:css_class] +- css_class = 'no-description' if group.description.blank? -%li.group-row.group-admin{ class: css_class } - .group-avatar - = image_tag group_icon(group), class: 'avatar hidden-xs' - .group-details - .title - = link_to [:admin, group], class: 'group-name' do - = group.name - .group-stats - %span>= pluralize(number_with_delimiter(group.projects.count), 'project') - , - %span= pluralize(number_with_delimiter(group.users.count), 'member') - - - if group.description.present? - .description - = markdown(group.description, pipeline: :description) - .controls.hidden-xs +%li.group-row{ class: css_class } + .controls = link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: 'btn' = link_to 'Delete', [:admin, group], data: { confirm: "Are you sure you want to remove #{group.name}?" }, method: :delete, class: 'btn btn-remove' + .stats + %span + = icon('bookmark') + = number_with_delimiter(group.projects.count) + + %span + = icon('users') + = number_with_delimiter(group.users.count) + + = image_tag group_icon(group), class: "avatar s40 hidden-xs" + .title + = link_to [:admin, group], class: 'group-name' do + = group.name + + - if group.description.present? + .description + = markdown(group.description, pipeline: :description) From 7ab4f2ad3cc5b9bb394d578e3f6069cdff06f1ee Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Thu, 14 Jul 2016 17:14:01 -0500 Subject: [PATCH 281/335] Remove previously introduced CSS that will not be used anymore --- app/assets/stylesheets/pages/groups.scss | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index 3682b886cb3..2a3acc3eb4c 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -38,29 +38,6 @@ margin-right: 15px; } } - - &.group-admin { - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - - .group-avatar, .group-details, .controls { - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - } - - .group-details { - flex: 1 1 auto; - flex-direction: column; - min-width: 0; - } - - .controls { - align-items: center; - } - } - } .ldap-group-links { From 2231116ed72eb5c6ce6bc1c838724ed0ee199831 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Thu, 14 Jul 2016 18:02:50 -0500 Subject: [PATCH 282/335] Add visibility icon --- app/views/admin/groups/_group.html.haml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/views/admin/groups/_group.html.haml b/app/views/admin/groups/_group.html.haml index f6c76302da5..77a11e49e20 100644 --- a/app/views/admin/groups/_group.html.haml +++ b/app/views/admin/groups/_group.html.haml @@ -13,6 +13,9 @@ = icon('users') = number_with_delimiter(group.users.count) + %span.visibility-icon.has-tooltip{data: { container: 'body', placement: 'left' }, title: visibility_icon_description(group)} + = visibility_level_icon(group.visibility_level, fw: false) + = image_tag group_icon(group), class: "avatar s40 hidden-xs" .title = link_to [:admin, group], class: 'group-name' do From e5c7e11840871e3138ad32693d86de8d7cd7c670 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 14 Jul 2016 18:39:08 -0700 Subject: [PATCH 283/335] Disable PostgreSQL statement timeout during migrations Long-running migrations may take more than the timeout allowed by the database. Disable the session's statement timeout to ensure migrations don't get killed prematurely. --- CHANGELOG | 1 + lib/gitlab/database/migration_helpers.rb | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 19286abd74f..23f8bfa5d34 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.10.0 (unreleased) - Expose {should,force}_remove_source_branch (Ben Boeckel) + - Disable PostgreSQL statement timeout during migrations - Fix projects dropdown loading performance with a simplified api cal. !5113 (tiagonbotelho) - Fix commit builds API, return all builds for all pipelines for given commit. !4849 - Replace Haml with Hamlit to make view rendering faster. !3666 diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb index dec20d8659b..593ee5d9568 100644 --- a/lib/gitlab/database/migration_helpers.rb +++ b/lib/gitlab/database/migration_helpers.rb @@ -25,6 +25,13 @@ module Gitlab add_index(table_name, column_name, options) end + # Long-running migrations may take more than the timeout allowed by + # the database. Disable the session's statement timeout to ensure + # migrations don't get killed prematurely. (PostgreSQL only) + def disable_statement_timeout + ActiveRecord::Base.connection.execute('SET statement_timeout TO 0') if Database.postgresql? + end + # Updates the value of a column in batches. # # This method updates the table in batches of 5% of the total row count. @@ -134,6 +141,7 @@ module Gitlab end transaction do + disable_statement_timeout add_column(table, column, type, default: nil) # Changing the default before the update ensures any newly inserted From f700f3ec5d524afd1575a27da76b39b08947b7ea Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 14 Jul 2016 18:50:46 -0700 Subject: [PATCH 284/335] Disable statement timeout outside of transaction and during adding concurrent index --- lib/gitlab/database/migration_helpers.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb index 593ee5d9568..927f9dad20b 100644 --- a/lib/gitlab/database/migration_helpers.rb +++ b/lib/gitlab/database/migration_helpers.rb @@ -20,6 +20,7 @@ module Gitlab if Database.postgresql? options = options.merge({ algorithm: :concurrently }) + disable_statement_timeout end add_index(table_name, column_name, options) @@ -140,8 +141,9 @@ module Gitlab 'in the body of your migration class' end + disable_statement_timeout + transaction do - disable_statement_timeout add_column(table, column, type, default: nil) # Changing the default before the update ensures any newly inserted From 3fd304c1a5063ad9fd53b851de79322f49c68997 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 14 Jul 2016 20:55:33 -0700 Subject: [PATCH 285/335] Fix spec Don't attempt to disable statement timeout on a MySQL DB --- spec/lib/gitlab/database/migration_helpers_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index 9096ad101b0..4ec3f19e03f 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -13,6 +13,10 @@ describe Gitlab::Database::MigrationHelpers, lib: true do context 'outside a transaction' do before do expect(model).to receive(:transaction_open?).and_return(false) + + unless Gitlab::Database.postgresql? + allow_any_instance_of(Gitlab::Database::MigrationHelpers).to receive(:disable_statement_timeout) + end end context 'using PostgreSQL' do From c4ea394736f98aebd6b370d75a5b3556206ce09d Mon Sep 17 00:00:00 2001 From: "http://jneen.net/" Date: Thu, 14 Jul 2016 22:43:49 -0700 Subject: [PATCH 286/335] use %(...) and %[...] in favor of %<...> --- app/helpers/blob_helper.rb | 2 +- lib/banzai/filter/syntax_highlight_filter.rb | 4 ++-- lib/rouge/formatters/html_gitlab.rb | 4 ++-- spec/helpers/blob_helper_spec.rb | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 39f9f935d31..abe115d8c68 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -1,7 +1,7 @@ module BlobHelper def highlight(blob_name, blob_content, repository: nil, plain: false) highlighted = Gitlab::Highlight.highlight(blob_name, blob_content, plain: plain, repository: repository) - raw %<
    #{highlighted}
    > + raw %(
    #{highlighted}
    ) end def no_highlight_files diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb index 17f9164bcb7..028edef704b 100644 --- a/lib/banzai/filter/syntax_highlight_filter.rb +++ b/lib/banzai/filter/syntax_highlight_filter.rb @@ -25,9 +25,9 @@ module Banzai begin highlighted = '' - highlighted << %<
    >
    +          highlighted << %(
    )
               highlighted << formatter.format(lexer.lex(code))
    -          highlighted << %<
    > + highlighted << %(
    ) rescue # Gracefully handle syntax highlighter bugs/errors to ensure # users can still access an issue/comment/etc. diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb index b76cf14a536..f818dc78d34 100644 --- a/lib/rouge/formatters/html_gitlab.rb +++ b/lib/rouge/formatters/html_gitlab.rb @@ -17,9 +17,9 @@ module Rouge yield "\n" unless is_first is_first = false - yield %<> + yield %() line.each { |token, value| yield span(token, value) } - yield %<> + yield %() @line_number += 1 end diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb index e5dfa61fa6a..bd0108f9938 100644 --- a/spec/helpers/blob_helper_spec.rb +++ b/spec/helpers/blob_helper_spec.rb @@ -17,7 +17,7 @@ describe BlobHelper do describe '#highlight' do it 'should return plaintext for unknown lexer context' do result = helper.highlight(blob_name, no_context_content) - expect(result).to eq(%<
    :type "assem"))
    >) + expect(result).to eq(%[
    :type "assem"))
    ]) end it 'should highlight single block' do From f435eb6f35ab755dae1fd45d9aa577f6896eae7b Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Fri, 15 Jul 2016 16:53:22 +0800 Subject: [PATCH 287/335] navbar_icon was renamed to custom_icon in: https://gitlab.com/gitlab-org/gitlab-ce/commit/c57471ddb456c9640f6d77128e1fc56c7a5b35b2 navbar_icon was used in: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4909 --- .../dashboard/projects/_zero_authorized_projects.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/dashboard/projects/_zero_authorized_projects.html.haml b/app/views/dashboard/projects/_zero_authorized_projects.html.haml index 40c70fa3025..fdea834ff45 100644 --- a/app/views/dashboard/projects/_zero_authorized_projects.html.haml +++ b/app/views/dashboard/projects/_zero_authorized_projects.html.haml @@ -6,7 +6,7 @@ Code, test, and deploy together .blank-state .blank-state-icon - = navbar_icon("project", size: 50) + = custom_icon("project", size: 50) %h3.blank-state-title You don't have access to any projects right now %p.blank-state-text @@ -24,7 +24,7 @@ - if current_user.can_create_group? .blank-state .blank-state-icon - = navbar_icon("group", size: 50) + = custom_icon("group", size: 50) %h3.blank-state-title You can create a group for several dependent projects. %p.blank-state-text From 65549a5866da6ceaf7ee4052736077879b5e641d Mon Sep 17 00:00:00 2001 From: James Lopez Date: Fri, 15 Jul 2016 12:47:06 +0200 Subject: [PATCH 288/335] add project name and namespace to filename on project export added changelog --- CHANGELOG | 1 + .../projects/import_export/export_service.rb | 2 +- lib/gitlab/import_export.rb | 7 +++++++ lib/gitlab/import_export/saver.rb | 5 +++-- .../import_export/import_export_spec.rb | 21 +++++++++++++++++++ 5 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 spec/lib/gitlab/import_export/import_export_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 51f1db07e8b..49792d2950f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -93,6 +93,7 @@ v 8.10.0 (unreleased) - Redesign Builds and Pipelines pages - Change status color and icon for running builds - Fix markdown rendering for: consecutive labels references, label references that begin with a digit or contains `.` + - Project export filename now includes the project and namespace path v 8.9.6 - Fix importing of events under notes for GitLab projects. !5154 diff --git a/app/services/projects/import_export/export_service.rb b/app/services/projects/import_export/export_service.rb index 6afc048576d..998789d64d2 100644 --- a/app/services/projects/import_export/export_service.rb +++ b/app/services/projects/import_export/export_service.rb @@ -10,7 +10,7 @@ module Projects def save_all if [version_saver, project_tree_saver, uploads_saver, repo_saver, wiki_repo_saver].all?(&:save) - Gitlab::ImportExport::Saver.save(shared: @shared) + Gitlab::ImportExport::Saver.save(project: project, shared: @shared) notify_success else cleanup_and_notify diff --git a/lib/gitlab/import_export.rb b/lib/gitlab/import_export.rb index 588647e5adb..bab2ea73c4f 100644 --- a/lib/gitlab/import_export.rb +++ b/lib/gitlab/import_export.rb @@ -3,6 +3,7 @@ module Gitlab extend self VERSION = '0.1.1' + FILENAME_LIMIT = 50 def export_path(relative_path:) File.join(storage_path, relative_path) @@ -28,6 +29,12 @@ module Gitlab 'VERSION' end + def export_filename(project:) + basename = "#{Time.now.strftime('%Y-%m-%d_%H-%M-%3N')}_#{project.namespace.path}_#{project.path}" + + "#{basename[0..FILENAME_LIMIT]}_export.tar.gz" + end + def version VERSION end diff --git a/lib/gitlab/import_export/saver.rb b/lib/gitlab/import_export/saver.rb index 6a60b65071f..6130c124dd1 100644 --- a/lib/gitlab/import_export/saver.rb +++ b/lib/gitlab/import_export/saver.rb @@ -7,7 +7,8 @@ module Gitlab new(*args).save end - def initialize(shared:) + def initialize(project:, shared:) + @project = project @shared = shared end @@ -36,7 +37,7 @@ module Gitlab end def archive_file - @archive_file ||= File.join(@shared.export_path, '..', "#{Time.now.strftime('%Y-%m-%d_%H-%M-%3N')}_project_export.tar.gz") + @archive_file ||= File.join(@shared.export_path, '..', Gitlab::ImportExport.export_filename(project: @project)) end end end diff --git a/spec/lib/gitlab/import_export/import_export_spec.rb b/spec/lib/gitlab/import_export/import_export_spec.rb new file mode 100644 index 00000000000..d6409a29550 --- /dev/null +++ b/spec/lib/gitlab/import_export/import_export_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe Gitlab::ImportExport, services: true do + describe 'export filename' do + let(:project) { create(:project, :public, path: 'project-path') } + + it 'contains the project path' do + expect(described_class.export_filename(project: project)).to include(project.path) + end + + it 'contains the namespace path' do + expect(described_class.export_filename(project: project)).to include(project.namespace.path) + end + + it 'does not go over a certain length' do + project.path = 'a' * 100 + + expect(described_class.export_filename(project: project).length).to be < 70 + end + end +end From 86f39fece2273319e2c960d96b131924a9fbdc3c Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 15 Jul 2016 14:01:34 +0200 Subject: [PATCH 289/335] Refactor LFS specs to use requests instead of LfsRouter --- spec/lib/gitlab/lfs/lfs_router_spec.rb | 730 ----------------------- spec/requests/lfs_http_spec.rb | 763 +++++++++++++++++++++++++ 2 files changed, 763 insertions(+), 730 deletions(-) delete mode 100644 spec/lib/gitlab/lfs/lfs_router_spec.rb create mode 100644 spec/requests/lfs_http_spec.rb diff --git a/spec/lib/gitlab/lfs/lfs_router_spec.rb b/spec/lib/gitlab/lfs/lfs_router_spec.rb deleted file mode 100644 index 659facd6c19..00000000000 --- a/spec/lib/gitlab/lfs/lfs_router_spec.rb +++ /dev/null @@ -1,730 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Lfs::Router, lib: true do - let(:project) { create(:project) } - let(:public_project) { create(:project, :public) } - let(:forked_project) { fork_project(public_project, user) } - - let(:user) { create(:user) } - let(:user_two) { create(:user) } - let!(:lfs_object) { create(:lfs_object, :with_file) } - - let(:request) { Rack::Request.new(env) } - let(:env) do - { - 'rack.input' => '', - 'REQUEST_METHOD' => 'GET', - } - end - - let(:lfs_router_auth) { new_lfs_router(project, user: user) } - let(:lfs_router_ci_auth) { new_lfs_router(project, ci: true) } - let(:lfs_router_noauth) { new_lfs_router(project) } - let(:lfs_router_public_auth) { new_lfs_router(public_project, user: user) } - let(:lfs_router_public_ci_auth) { new_lfs_router(public_project, ci: true) } - let(:lfs_router_public_noauth) { new_lfs_router(public_project) } - let(:lfs_router_forked_noauth) { new_lfs_router(forked_project) } - let(:lfs_router_forked_auth) { new_lfs_router(forked_project, user: user_two) } - let(:lfs_router_forked_ci_auth) { new_lfs_router(forked_project, ci: true) } - - let(:sample_oid) { "b68143e6463773b1b6c6fd009a76c32aeec041faff32ba2ed42fd7f708a17f80" } - let(:sample_size) { 499013 } - let(:respond_with_deprecated) {[ 501, { "Content-Type" => "application/json; charset=utf-8" }, ["{\"message\":\"Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.\",\"documentation_url\":\"#{Gitlab.config.gitlab.url}/help\"}"]]} - let(:respond_with_disabled) {[ 501, { "Content-Type" => "application/json; charset=utf-8" }, ["{\"message\":\"Git LFS is not enabled on this GitLab server, contact your admin.\",\"documentation_url\":\"#{Gitlab.config.gitlab.url}/help\"}"]]} - - describe 'when lfs is disabled' do - before do - allow(Gitlab.config.lfs).to receive(:enabled).and_return(false) - env['REQUEST_METHOD'] = 'POST' - body = { - 'objects' => [ - { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', - 'size' => 1575078 - }, - { 'oid' => sample_oid, - 'size' => sample_size - } - ], - 'operation' => 'upload' - }.to_json - env['rack.input'] = StringIO.new(body) - env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/batch" - end - - it 'responds with 501' do - expect(lfs_router_auth.try_call).to match_array(respond_with_disabled) - end - end - - describe 'when fetching lfs object using deprecated API' do - before do - enable_lfs - env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/#{sample_oid}" - end - - it 'responds with 501' do - expect(lfs_router_auth.try_call).to match_array(respond_with_deprecated) - end - end - - describe 'when fetching lfs object' do - before do - enable_lfs - env['HTTP_ACCEPT'] = "application/vnd.git-lfs+json; charset=utf-8" - env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}" - end - - describe 'and request comes from gitlab-workhorse' do - context 'without user being authorized' do - it "responds with status 401" do - expect(lfs_router_noauth.try_call.first).to eq(401) - end - end - - context 'with required headers' do - before do - project.lfs_objects << lfs_object - env['HTTP_X_SENDFILE_TYPE'] = "X-Sendfile" - end - - context 'when user does not have project access' do - it "responds with status 403" do - expect(lfs_router_auth.try_call.first).to eq(403) - end - end - - context 'when user has project access' do - before do - project.team << [user, :master] - end - - it "responds with status 200" do - expect(lfs_router_auth.try_call.first).to eq(200) - end - - it "responds with the file location" do - expect(lfs_router_auth.try_call[1]['Content-Type']).to eq("application/octet-stream") - expect(lfs_router_auth.try_call[1]['X-Sendfile']).to eq(lfs_object.file.path) - end - end - - context 'when CI is authorized' do - it "responds with status 200" do - expect(lfs_router_ci_auth.try_call.first).to eq(200) - end - - it "responds with the file location" do - expect(lfs_router_ci_auth.try_call[1]['Content-Type']).to eq("application/octet-stream") - expect(lfs_router_ci_auth.try_call[1]['X-Sendfile']).to eq(lfs_object.file.path) - end - end - end - - context 'without required headers' do - it "responds with status 403" do - expect(lfs_router_auth.try_call.first).to eq(403) - end - end - end - end - - describe 'when handling lfs request using deprecated API' do - before do - enable_lfs - env['REQUEST_METHOD'] = 'POST' - env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects" - end - - it 'responds with 501' do - expect(lfs_router_auth.try_call).to match_array(respond_with_deprecated) - end - end - - describe 'when handling lfs batch request' do - before do - enable_lfs - env['REQUEST_METHOD'] = 'POST' - env['PATH_INFO'] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/batch" - end - - describe 'download' do - before do - body = { 'operation' => 'download', - 'objects' => [ - { 'oid' => sample_oid, - 'size' => sample_size - }] - }.to_json - env['rack.input'] = StringIO.new(body) - end - - shared_examples 'an authorized requests' do - context 'when downloading an lfs object that is assigned to our project' do - before do - project.lfs_objects << lfs_object - end - - it 'responds with status 200 and href to download' do - response = router.try_call - expect(response.first).to eq(200) - response_body = ActiveSupport::JSON.decode(response.last.first) - - expect(response_body).to eq('objects' => [ - { 'oid' => sample_oid, - 'size' => sample_size, - 'actions' => { - 'download' => { - 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}", - 'header' => { 'Authorization' => auth } - } - } - }]) - end - end - - context 'when downloading an lfs object that is assigned to other project' do - before do - public_project.lfs_objects << lfs_object - end - - it 'responds with status 200 and error message' do - response = router.try_call - expect(response.first).to eq(200) - response_body = ActiveSupport::JSON.decode(response.last.first) - - expect(response_body).to eq('objects' => [ - { 'oid' => sample_oid, - 'size' => sample_size, - 'error' => { - 'code' => 404, - 'message' => "Object does not exist on the server or you don't have permissions to access it", - } - }]) - end - end - - context 'when downloading a lfs object that does not exist' do - before do - body = { 'operation' => 'download', - 'objects' => [ - { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', - 'size' => 1575078 - }] - }.to_json - env['rack.input'] = StringIO.new(body) - end - - it "responds with status 200 and error message" do - response = router.try_call - expect(response.first).to eq(200) - response_body = ActiveSupport::JSON.decode(response.last.first) - - expect(response_body).to eq('objects' => [ - { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', - 'size' => 1575078, - 'error' => { - 'code' => 404, - 'message' => "Object does not exist on the server or you don't have permissions to access it", - } - }]) - end - end - - context 'when downloading one new and one existing lfs object' do - before do - body = { 'operation' => 'download', - 'objects' => [ - { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', - 'size' => 1575078 - }, - { 'oid' => sample_oid, - 'size' => sample_size - } - ] - }.to_json - env['rack.input'] = StringIO.new(body) - project.lfs_objects << lfs_object - end - - it "responds with status 200 with upload hypermedia link for the new object" do - response = router.try_call - expect(response.first).to eq(200) - response_body = ActiveSupport::JSON.decode(response.last.first) - - expect(response_body).to eq('objects' => [ - { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', - 'size' => 1575078, - 'error' => { - 'code' => 404, - 'message' => "Object does not exist on the server or you don't have permissions to access it", - } - }, - { 'oid' => sample_oid, - 'size' => sample_size, - 'actions' => { - 'download' => { - 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}", - 'header' => { 'Authorization' => auth } - } - } - }]) - end - end - end - - context 'when user is authenticated' do - let(:auth) { authorize(user) } - - before do - env["HTTP_AUTHORIZATION"] = auth - project.team << [user, role] - end - - it_behaves_like 'an authorized requests' do - let(:role) { :reporter } - let(:router) { lfs_router_auth } - end - - context 'when user does is not member of the project' do - let(:role) { :guest } - - it 'responds with 403' do - expect(lfs_router_auth.try_call.first).to eq(403) - end - end - - context 'when user does not have download access' do - let(:role) { :guest } - - it 'responds with 403' do - expect(lfs_router_auth.try_call.first).to eq(403) - end - end - end - - context 'when CI is authorized' do - let(:auth) { 'gitlab-ci-token:password' } - - before do - env["HTTP_AUTHORIZATION"] = auth - end - - it_behaves_like 'an authorized requests' do - let(:router) { lfs_router_ci_auth } - end - end - - context 'when user is not authenticated' do - describe 'is accessing public project' do - before do - public_project.lfs_objects << lfs_object - end - - it 'responds with status 200 and href to download' do - response = lfs_router_public_noauth.try_call - expect(response.first).to eq(200) - response_body = ActiveSupport::JSON.decode(response.last.first) - - expect(response_body).to eq('objects' => [ - { 'oid' => sample_oid, - 'size' => sample_size, - 'actions' => { - 'download' => { - 'href' => "#{public_project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}", - 'header' => {} - } - } - }]) - end - end - - describe 'is accessing non-public project' do - before do - project.lfs_objects << lfs_object - end - - it 'responds with authorization required' do - expect(lfs_router_noauth.try_call.first).to eq(401) - end - end - end - end - - describe 'upload' do - before do - body = { 'operation' => 'upload', - 'objects' => [ - { 'oid' => sample_oid, - 'size' => sample_size - }] - }.to_json - env['rack.input'] = StringIO.new(body) - end - - describe 'when request is authenticated' do - describe 'when user has project push access' do - before do - @auth = authorize(user) - env["HTTP_AUTHORIZATION"] = @auth - project.team << [user, :developer] - end - - context 'when pushing an lfs object that already exists' do - before do - public_project.lfs_objects << lfs_object - end - - it "responds with status 200 and links the object to the project" do - response_body = lfs_router_auth.try_call.last - response = ActiveSupport::JSON.decode(response_body.first) - - expect(response['objects']).to be_kind_of(Array) - expect(response['objects'].first['oid']).to eq(sample_oid) - expect(response['objects'].first['size']).to eq(sample_size) - expect(lfs_object.projects.pluck(:id)).not_to include(project.id) - expect(lfs_object.projects.pluck(:id)).to include(public_project.id) - expect(response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}") - expect(response['objects'].first['actions']['upload']['header']).to eq('Authorization' => @auth) - end - end - - context 'when pushing a lfs object that does not exist' do - before do - body = { 'operation' => 'upload', - 'objects' => [ - { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', - 'size' => 1575078 - }] - }.to_json - env['rack.input'] = StringIO.new(body) - end - - it "responds with status 200 and upload hypermedia link" do - response = lfs_router_auth.try_call - expect(response.first).to eq(200) - - response_body = ActiveSupport::JSON.decode(response.last.first) - expect(response_body['objects']).to be_kind_of(Array) - expect(response_body['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897") - expect(response_body['objects'].first['size']).to eq(1575078) - expect(lfs_object.projects.pluck(:id)).not_to include(project.id) - expect(response_body['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078") - expect(response_body['objects'].first['actions']['upload']['header']).to eq('Authorization' => @auth) - end - end - - context 'when pushing one new and one existing lfs object' do - before do - body = { 'operation' => 'upload', - 'objects' => [ - { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', - 'size' => 1575078 - }, - { 'oid' => sample_oid, - 'size' => sample_size - } - ] - }.to_json - env['rack.input'] = StringIO.new(body) - project.lfs_objects << lfs_object - end - - it "responds with status 200 with upload hypermedia link for the new object" do - response = lfs_router_auth.try_call - expect(response.first).to eq(200) - - response_body = ActiveSupport::JSON.decode(response.last.first) - expect(response_body['objects']).to be_kind_of(Array) - - expect(response_body['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897") - expect(response_body['objects'].first['size']).to eq(1575078) - expect(response_body['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078") - expect(response_body['objects'].first['actions']['upload']['header']).to eq("Authorization" => @auth) - - expect(response_body['objects'].last['oid']).to eq(sample_oid) - expect(response_body['objects'].last['size']).to eq(sample_size) - expect(response_body['objects'].last).not_to have_key('actions') - end - end - end - - context 'when user does not have push access' do - it 'responds with 403' do - expect(lfs_router_auth.try_call.first).to eq(403) - end - end - - context 'when CI is authorized' do - it 'responds with 401' do - expect(lfs_router_ci_auth.try_call.first).to eq(401) - end - end - end - - context 'when user is not authenticated' do - context 'when user has push access' do - before do - project.team << [user, :master] - end - - it "responds with status 401" do - expect(lfs_router_public_noauth.try_call.first).to eq(401) - end - end - - context 'when user does not have push access' do - it "responds with status 401" do - expect(lfs_router_public_noauth.try_call.first).to eq(401) - end - end - end - - context 'when CI is authorized' do - let(:auth) { 'gitlab-ci-token:password' } - - before do - env["HTTP_AUTHORIZATION"] = auth - end - - it "responds with status 403" do - expect(lfs_router_public_ci_auth.try_call.first).to eq(401) - end - end - end - - describe 'unsupported' do - before do - body = { 'operation' => 'other', - 'objects' => [ - { 'oid' => sample_oid, - 'size' => sample_size - }] - }.to_json - env['rack.input'] = StringIO.new(body) - end - - it 'responds with status 404' do - expect(lfs_router_public_noauth.try_call.first).to eq(404) - end - end - end - - describe 'when pushing a lfs object' do - before do - enable_lfs - env['REQUEST_METHOD'] = 'PUT' - end - - shared_examples 'unauthorized' do - context 'and request is sent by gitlab-workhorse to authorize the request' do - before do - header_for_upload_authorize(router.project) - end - - it 'responds with status 401' do - expect(router.try_call.first).to eq(401) - end - end - - context 'and request is sent by gitlab-workhorse to finalize the upload' do - before do - headers_for_upload_finalize(router.project) - end - - it 'responds with status 401' do - expect(router.try_call.first).to eq(401) - end - end - - context 'and request is sent with a malformed headers' do - before do - env["PATH_INFO"] = "#{router.project.repository.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}" - env["HTTP_X_GITLAB_LFS_TMP"] = "cat /etc/passwd" - end - - it 'does not recognize it as a valid lfs command' do - expect(router.try_call).to eq(nil) - end - end - end - - shared_examples 'forbidden' do - context 'and request is sent by gitlab-workhorse to authorize the request' do - before do - header_for_upload_authorize(router.project) - end - - it 'responds with 403' do - expect(router.try_call.first).to eq(403) - end - end - - context 'and request is sent by gitlab-workhorse to finalize the upload' do - before do - headers_for_upload_finalize(router.project) - end - - it 'responds with 403' do - expect(router.try_call.first).to eq(403) - end - end - end - - describe 'to one project' do - describe 'when user is authenticated' do - describe 'when user has push access to the project' do - before do - project.team << [user, :developer] - end - - context 'and request is sent by gitlab-workhorse to authorize the request' do - before do - header_for_upload_authorize(project) - end - - it 'responds with status 200, location of lfs store and object details' do - json_response = ActiveSupport::JSON.decode(lfs_router_auth.try_call.last.first) - - expect(lfs_router_auth.try_call.first).to eq(200) - expect(json_response['StoreLFSPath']).to eq("#{Gitlab.config.shared.path}/lfs-objects/tmp/upload") - expect(json_response['LfsOid']).to eq(sample_oid) - expect(json_response['LfsSize']).to eq(sample_size) - end - end - - context 'and request is sent by gitlab-workhorse to finalize the upload' do - before do - headers_for_upload_finalize(project) - end - - it 'responds with status 200 and lfs object is linked to the project' do - expect(lfs_router_auth.try_call.first).to eq(200) - expect(lfs_object.projects.pluck(:id)).to include(project.id) - end - end - end - - describe 'and user does not have push access' do - let(:router) { lfs_router_auth } - - it_behaves_like 'forbidden' - end - end - - context 'when CI is authenticated' do - let(:router) { lfs_router_ci_auth } - - it_behaves_like 'unauthorized' - end - - context 'for unauthenticated' do - let(:router) { new_lfs_router(project) } - - it_behaves_like 'unauthorized' - end - end - - describe 'to a forked project' do - let(:forked_project) { fork_project(public_project, user) } - - describe 'when user is authenticated' do - describe 'when user has push access to the project' do - before do - forked_project.team << [user_two, :developer] - end - - context 'and request is sent by gitlab-workhorse to authorize the request' do - before do - header_for_upload_authorize(forked_project) - end - - it 'responds with status 200, location of lfs store and object details' do - json_response = ActiveSupport::JSON.decode(lfs_router_forked_auth.try_call.last.first) - - expect(lfs_router_forked_auth.try_call.first).to eq(200) - expect(json_response['StoreLFSPath']).to eq("#{Gitlab.config.shared.path}/lfs-objects/tmp/upload") - expect(json_response['LfsOid']).to eq(sample_oid) - expect(json_response['LfsSize']).to eq(sample_size) - end - end - - context 'and request is sent by gitlab-workhorse to finalize the upload' do - before do - headers_for_upload_finalize(forked_project) - end - - it 'responds with status 200 and lfs object is linked to the source project' do - expect(lfs_router_forked_auth.try_call.first).to eq(200) - expect(lfs_object.projects.pluck(:id)).to include(public_project.id) - end - end - end - - describe 'and user does not have push access' do - let(:router) { lfs_router_forked_auth } - - it_behaves_like 'forbidden' - end - end - - context 'when CI is authenticated' do - let(:router) { lfs_router_forked_ci_auth } - - it_behaves_like 'unauthorized' - end - - context 'for unauthenticated' do - let(:router) { lfs_router_forked_noauth } - - it_behaves_like 'unauthorized' - end - - describe 'and second project not related to fork or a source project' do - let(:second_project) { create(:project) } - let(:lfs_router_second_project) { new_lfs_router(second_project, user: user) } - - before do - public_project.lfs_objects << lfs_object - headers_for_upload_finalize(second_project) - end - - context 'when pushing the same lfs object to the second project' do - before do - second_project.team << [user, :master] - end - - it 'responds with 200 and links the lfs object to the project' do - expect(lfs_router_second_project.try_call.first).to eq(200) - expect(lfs_object.projects.pluck(:id)).to include(second_project.id, public_project.id) - end - end - end - end - end - - def enable_lfs - allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) - end - - def authorize(user) - ActionController::HttpAuthentication::Basic.encode_credentials(user.username, user.password) - end - - def new_lfs_router(project, user: nil, ci: false) - Gitlab::Lfs::Router.new(project, user, ci, request) - end - - def header_for_upload_authorize(project) - env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}/authorize" - end - - def headers_for_upload_finalize(project) - env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}" - env["HTTP_X_GITLAB_LFS_TMP"] = "#{sample_oid}6e561c9d4" - end - - def fork_project(project, user, object = nil) - allow(RepositoryForkWorker).to receive(:perform_async).and_return(true) - Projects::ForkService.new(project, user, {}).execute - end -end diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb new file mode 100644 index 00000000000..d862cb5b0b4 --- /dev/null +++ b/spec/requests/lfs_http_spec.rb @@ -0,0 +1,763 @@ +require 'spec_helper' + +describe Gitlab::Lfs::Router do + let(:user) { create(:user) } + let!(:lfs_object) { create(:lfs_object, :with_file) } + + let(:headers) do + { + 'Authorization' => authorization, + 'X-Sendfile-Type' => sendfile + }.compact + end + let(:authorization) { } + let(:sendfile) { } + + let(:sample_oid) { lfs_object.oid } + let(:sample_size) { lfs_object.size } + + describe 'when lfs is disabled' do + let(:project) { create(:empty_project) } + let(:body) do + { + 'objects' => [ + { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', + 'size' => 1575078 + }, + { 'oid' => sample_oid, + 'size' => sample_size + } + ], + 'operation' => 'upload' + } + end + + before do + allow(Gitlab.config.lfs).to receive(:enabled).and_return(false) + post_json "#{project.http_url_to_repo}/info/lfs/objects/batch", body, headers + end + + it 'responds with 501' do + expect(response).to have_http_status(501) + expect(json_response).to include('message' => 'Git LFS is not enabled on this GitLab server, contact your admin.') + end + end + + describe 'deprecated API' do + let(:project) { create(:empty_project) } + + before do + enable_lfs + end + + shared_examples 'a deprecated' do + it 'responds with 501' do + expect(response).to have_http_status(501) + end + + it 'returns deprecated message' do + expect(json_response).to include('message' => 'Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.') + end + end + + context 'when fetching lfs object using deprecated API' do + let(:authorization) { authorize_user } + + before do + get "#{project.http_url_to_repo}/info/lfs/objects/#{sample_oid}", nil, headers + end + + it_behaves_like 'a deprecated' + end + + context 'when handling lfs request using deprecated API' do + before do + post_json "#{project.http_url_to_repo}/info/lfs/objects", nil, headers + end + + it_behaves_like 'a deprecated' + end + end + + describe 'when fetching lfs object' do + let(:project) { create(:empty_project) } + let(:update_permissions) { } + + before do + enable_lfs + update_permissions + get "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}", nil, headers + end + + context 'and request comes from gitlab-workhorse' do + context 'without user being authorized' do + it 'responds with status 401' do + expect(response).to have_http_status(401) + end + end + + context 'with required headers' do + shared_examples 'responds with a file' do + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'responds with the file location' do + expect(response.headers['Content-Type']).to eq('application/octet-stream') + expect(response.headers['X-Sendfile']).to eq(lfs_object.file.path) + end + end + + context 'with user is authorized' do + let(:authorization) { authorize_user } + let(:sendfile) { 'X-Sendfile' } + + context 'and does not have project access' do + let(:update_permissions) do + project.lfs_objects << lfs_object + end + + it 'responds with status 403' do + expect(response).to have_http_status(403) + end + end + + context 'and does have project access' do + let(:update_permissions) do + project.team << [user, :master] + project.lfs_objects << lfs_object + end + + it_behaves_like 'responds with a file' + end + end + + context 'when CI is authorized' do + let(:authorization) { authorize_ci_project } + + it_behaves_like 'responds with a file' + end + end + + context 'without required headers' do + let(:authorization) { authorize_user } + + it 'responds with status 403' do + expect(response).to have_http_status(403) + end + end + end + end + + describe 'when handling lfs batch request' do + let(:update_lfs_permissions) { } + let(:update_user_permissions) { } + + before do + enable_lfs + update_lfs_permissions + update_user_permissions + post_json "#{project.http_url_to_repo}/info/lfs/objects/batch", body, headers + end + + describe 'download' do + let(:project) { create(:empty_project) } + let(:body) do + { 'operation' => 'download', + 'objects' => [ + { 'oid' => sample_oid, + 'size' => sample_size + }] + } + end + + shared_examples 'an authorized requests' do + context 'when downloading an lfs object that is assigned to our project' do + let(:update_lfs_permissions) do + project.lfs_objects << lfs_object + end + + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'with href to download' do + expect(json_response).to eq('objects' => [ + { 'oid' => sample_oid, + 'size' => sample_size, + 'actions' => { + 'download' => { + 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}", + 'header' => { 'Authorization' => authorization } + } + } + }]) + end + end + + context 'when downloading an lfs object that is assigned to other project' do + let(:other_project) { create(:empty_project) } + let(:update_lfs_permissions) do + other_project.lfs_objects << lfs_object + end + + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'with href to download' do + expect(json_response).to eq('objects' => [ + { 'oid' => sample_oid, + 'size' => sample_size, + 'error' => { + 'code' => 404, + 'message' => "Object does not exist on the server or you don't have permissions to access it", + } + }]) + end + end + + context 'when downloading a lfs object that does not exist' do + let(:body) do + { 'operation' => 'download', + 'objects' => [ + { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', + 'size' => 1575078 + }] + } + end + + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'with an 404 for specific object' do + expect(json_response).to eq('objects' => [ + { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', + 'size' => 1575078, + 'error' => { + 'code' => 404, + 'message' => "Object does not exist on the server or you don't have permissions to access it", + } + }]) + end + end + + context 'when downloading one new and one existing lfs object' do + let(:body) do + { 'operation' => 'download', + 'objects' => [ + { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', + 'size' => 1575078 + }, + { 'oid' => sample_oid, + 'size' => sample_size + } + ] + } + end + + let(:update_lfs_permissions) do + project.lfs_objects << lfs_object + end + + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'responds with upload hypermedia link for the new object' do + expect(json_response).to eq('objects' => [ + { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', + 'size' => 1575078, + 'error' => { + 'code' => 404, + 'message' => "Object does not exist on the server or you don't have permissions to access it", + } + }, + { 'oid' => sample_oid, + 'size' => sample_size, + 'actions' => { + 'download' => { + 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}", + 'header' => { 'Authorization' => authorization } + } + } + }]) + end + end + end + + context 'when user is authenticated' do + let(:authorization) { authorize_user } + + let(:update_user_permissions) do + project.team << [user, role] + end + + it_behaves_like 'an authorized requests' do + let(:role) { :reporter } + end + + context 'when user does is not member of the project' do + let(:role) { :guest } + + it 'responds with 403' do + expect(response).to have_http_status(403) + end + end + + context 'when user does not have download access' do + let(:role) { :guest } + + it 'responds with 403' do + expect(response).to have_http_status(403) + end + end + end + + context 'when CI is authorized' do + let(:authorization) { authorize_ci_project } + + it_behaves_like 'an authorized requests' + end + + context 'when user is not authenticated' do + describe 'is accessing public project' do + let(:project) { create(:project, :public) } + + let(:update_lfs_permissions) do + project.lfs_objects << lfs_object + end + + it 'responds with status 200 and href to download' do + expect(response).to have_http_status(200) + end + + it 'responds with status 200 and href to download' do + expect(json_response).to eq('objects' => [ + { 'oid' => sample_oid, + 'size' => sample_size, + 'actions' => { + 'download' => { + 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}", + 'header' => {} + } + } + }]) + end + end + + describe 'is accessing non-public project' do + let(:update_lfs_permissions) do + project.lfs_objects << lfs_object + end + + it 'responds with authorization required' do + expect(response).to have_http_status(401) + end + end + end + end + + describe 'upload' do + let(:project) { create(:project, :public) } + let(:body) do + { 'operation' => 'upload', + 'objects' => [ + { 'oid' => sample_oid, + 'size' => sample_size + }] + } + end + + describe 'when request is authenticated' do + describe 'when user has project push access' do + let(:authorization) { authorize_user } + + let(:update_user_permissions) do + project.team << [user, :developer] + end + + context 'when pushing an lfs object that already exists' do + let(:other_project) { create(:empty_project) } + let(:update_lfs_permissions) do + other_project.lfs_objects << lfs_object + end + + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'responds with links the object to the project' do + expect(json_response['objects']).to be_kind_of(Array) + expect(json_response['objects'].first['oid']).to eq(sample_oid) + expect(json_response['objects'].first['size']).to eq(sample_size) + expect(lfs_object.projects.pluck(:id)).not_to include(project.id) + expect(lfs_object.projects.pluck(:id)).to include(other_project.id) + expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}/#{sample_size}") + expect(json_response['objects'].first['actions']['upload']['header']).to eq('Authorization' => authorization) + end + end + + context 'when pushing a lfs object that does not exist' do + let(:body) do + { 'operation' => 'upload', + 'objects' => [ + { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', + 'size' => 1575078 + }] + } + end + + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'responds with upload hypermedia link' do + expect(json_response['objects']).to be_kind_of(Array) + expect(json_response['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897") + expect(json_response['objects'].first['size']).to eq(1575078) + expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078") + expect(json_response['objects'].first['actions']['upload']['header']).to eq('Authorization' => authorization) + end + end + + context 'when pushing one new and one existing lfs object' do + let(:body) do + { 'operation' => 'upload', + 'objects' => [ + { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', + 'size' => 1575078 + }, + { 'oid' => sample_oid, + 'size' => sample_size + } + ] + } + end + + let(:update_lfs_permissions) do + project.lfs_objects << lfs_object + end + + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'responds with upload hypermedia link for the new object' do + expect(json_response['objects']).to be_kind_of(Array) + + expect(json_response['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897") + expect(json_response['objects'].first['size']).to eq(1575078) + expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{project.http_url_to_repo}/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078") + expect(json_response['objects'].first['actions']['upload']['header']).to eq("Authorization" => authorization) + + expect(json_response['objects'].last['oid']).to eq(sample_oid) + expect(json_response['objects'].last['size']).to eq(sample_size) + expect(json_response['objects'].last).not_to have_key('actions') + end + end + end + + context 'when user does not have push access' do + let(:authorization) { authorize_user } + + it 'responds with 403' do + expect(response).to have_http_status(403) + end + end + + context 'when CI is authorized' do + let(:authorization) { authorize_ci_project } + + it 'responds with 401' do + expect(response).to have_http_status(401) + end + end + end + + context 'when user is not authenticated' do + context 'when user has push access' do + let(:update_user_permissions) do + project.team << [user, :master] + end + + it 'responds with status 401' do + expect(response).to have_http_status(401) + end + end + + context 'when user does not have push access' do + it 'responds with status 401' do + expect(response).to have_http_status(401) + end + end + end + + context 'when CI is authorized' do + let(:authorization) { authorize_ci_project } + + it 'responds with status 403' do + expect(response).to have_http_status(401) + end + end + end + + describe 'unsupported' do + let(:project) { create(:empty_project) } + let(:body) do + { 'operation' => 'other', + 'objects' => [ + { 'oid' => sample_oid, + 'size' => sample_size + }] + } + end + + it 'responds with status 404' do + expect(response).to have_http_status(404) + end + end + end + + describe 'when pushing a lfs object' do + before do + enable_lfs + end + + shared_examples 'unauthorized' do + context 'and request is sent by gitlab-workhorse to authorize the request' do + before do + put_authorize + end + + it 'responds with status 401' do + expect(response).to have_http_status(401) + end + end + + context 'and request is sent by gitlab-workhorse to finalize the upload' do + before do + put_finalize + end + + it 'responds with status 401' do + expect(response).to have_http_status(401) + end + end + + context 'and request is sent with a malformed headers' do + before do + put_finalize('cat /etc/passwd') + end + + it 'does not recognize it as a valid lfs command' do + expect(response).to have_http_status(401) + end + end + end + + shared_examples 'forbidden' do + context 'and request is sent by gitlab-workhorse to authorize the request' do + before do + put_authorize + end + + it 'responds with 403' do + expect(response).to have_http_status(403) + end + end + + context 'and request is sent by gitlab-workhorse to finalize the upload' do + before do + put_finalize + end + + it 'responds with 403' do + expect(response).to have_http_status(403) + end + end + end + + describe 'to one project' do + let(:project) { create(:empty_project) } + + describe 'when user is authenticated' do + let(:authorization) { authorize_user } + + describe 'when user has push access to the project' do + before do + project.team << [user, :developer] + end + + context 'and request is sent by gitlab-workhorse to authorize the request' do + before do + put_authorize + end + + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'responds with status 200, location of lfs store and object details' do + expect(json_response['StoreLFSPath']).to eq("#{Gitlab.config.shared.path}/lfs-objects/tmp/upload") + expect(json_response['LfsOid']).to eq(sample_oid) + expect(json_response['LfsSize']).to eq(sample_size) + end + end + + context 'and request is sent by gitlab-workhorse to finalize the upload' do + before do + put_finalize + end + + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'lfs object is linked to the project' do + expect(lfs_object.projects.pluck(:id)).to include(project.id) + end + end + end + + describe 'and user does not have push access' do + it_behaves_like 'forbidden' + end + end + + context 'when CI is authenticated' do + let(:authorization) { authorize_ci_project } + + it_behaves_like 'unauthorized' + end + + context 'for unauthenticated' do + it_behaves_like 'unauthorized' + end + end + + describe 'to a forked project' do + let(:upstream_project) { create(:project, :public) } + let(:project_owner) { create(:user) } + let(:project) { fork_project(upstream_project, project_owner) } + + describe 'when user is authenticated' do + let(:authorization) { authorize_user } + + describe 'when user has push access to the project' do + before do + project.team << [user, :developer] + end + + context 'and request is sent by gitlab-workhorse to authorize the request' do + before do + put_authorize + end + + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'with location of lfs store and object details' do + expect(json_response['StoreLFSPath']).to eq("#{Gitlab.config.shared.path}/lfs-objects/tmp/upload") + expect(json_response['LfsOid']).to eq(sample_oid) + expect(json_response['LfsSize']).to eq(sample_size) + end + end + + context 'and request is sent by gitlab-workhorse to finalize the upload' do + before do + put_finalize + end + + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'lfs object is linked to the source project' do + expect(lfs_object.projects.pluck(:id)).to include(upstream_project.id) + end + end + end + + describe 'and user does not have push access' do + it_behaves_like 'forbidden' + end + end + + context 'when CI is authenticated' do + let(:authorization) { authorize_ci_project } + + it_behaves_like 'unauthorized' + end + + context 'for unauthenticated' do + it_behaves_like 'unauthorized' + end + + describe 'and second project not related to fork or a source project' do + let(:second_project) { create(:empty_project) } + let(:authorization) { authorize_user } + + before do + second_project.team << [user, :master] + upstream_project.lfs_objects << lfs_object + end + + context 'when pushing the same lfs object to the second project' do + before do + put "#{second_project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}/#{sample_size}", nil, + headers.merge('X-Gitlab-Lfs-Tmp' => lfs_tmp_file).compact + end + + it 'responds with status 200' do + expect(response).to have_http_status(200) + end + + it 'links the lfs object to the project' do + expect(lfs_object.projects.pluck(:id)).to include(second_project.id, upstream_project.id) + end + end + end + end + + def put_authorize + put "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}/#{sample_size}/authorize", nil, headers + end + + def put_finalize(lfs_tmp = lfs_tmp_file) + put "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}/#{sample_size}", nil, + headers.merge('X-Gitlab-Lfs-Tmp' => lfs_tmp).compact + end + + def lfs_tmp_file + "#{sample_oid}012345678" + end + end + + def enable_lfs + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + end + + def authorize_ci_project + ActionController::HttpAuthentication::Basic.encode_credentials('gitlab-ci-token', project.runners_token) + end + + def authorize_user + ActionController::HttpAuthentication::Basic.encode_credentials(user.username, user.password) + end + + def fork_project(project, user, object = nil) + allow(RepositoryForkWorker).to receive(:perform_async).and_return(true) + Projects::ForkService.new(project, user, {}).execute + end + + def post_json(url, body = nil, headers = nil) + post(url, body.try(:to_json), (headers || {}).merge('Content-Type' => 'application/json')) + end + + def json_response + @json_response ||= JSON.parse(response.body) + end +end From bb9f827ddc51eba73c78be83b977a07e10638936 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 15 Jul 2016 14:23:26 +0200 Subject: [PATCH 290/335] Fix fetching LFS objects for private CI projects --- CHANGELOG | 1 + lib/gitlab/backend/grack_auth.rb | 2 +- spec/requests/lfs_http_spec.rb | 7 ++++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a977fc3fdbf..671a7c2e4a9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,7 @@ v 8.10.0 (unreleased) - Fix MR-auto-close text added to description. !4836 - Fix issue, preventing users w/o push access to sort tags !5105 (redetection) - Add Spring EmojiOne updates. + - Fix fetching LFS objects for private CI projects - Add syntax for multiline blockquote using `>>>` fence !3954 - Fix viewing notification settings when a project is pending deletion - Fix pagination when sorting by columns with lots of ties (like priority) diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index 478f145bfed..ab94abeda77 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -63,7 +63,7 @@ module Grack def ci_request?(login, password) matched_login = /(?^[a-zA-Z]*-ci)-token$/.match(login) - if project && matched_login.present? && git_cmd == 'git-upload-pack' + if project && matched_login.present? underscored_service = matched_login['s'].underscore if underscored_service == 'gitlab_ci' diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index d862cb5b0b4..aaad1e3a6ec 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -98,6 +98,8 @@ describe Gitlab::Lfs::Router do context 'with required headers' do shared_examples 'responds with a file' do + let(:sendfile) { 'X-Sendfile' } + it 'responds with status 200' do expect(response).to have_http_status(200) end @@ -110,7 +112,6 @@ describe Gitlab::Lfs::Router do context 'with user is authorized' do let(:authorization) { authorize_user } - let(:sendfile) { 'X-Sendfile' } context 'and does not have project access' do let(:update_permissions) do @@ -135,6 +136,10 @@ describe Gitlab::Lfs::Router do context 'when CI is authorized' do let(:authorization) { authorize_ci_project } + let(:update_permissions) do + project.lfs_objects << lfs_object + end + it_behaves_like 'responds with a file' end end From e300dac29302015cbba5b917ad5ea3657de62f0d Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 15 Jul 2016 15:06:19 +0200 Subject: [PATCH 291/335] Fix LFS specs --- lib/gitlab/lfs/response.rb | 2 ++ lib/gitlab/lfs/router.rb | 2 -- spec/requests/lfs_http_spec.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/gitlab/lfs/response.rb b/lib/gitlab/lfs/response.rb index 811363405a8..a1ee1aa81ff 100644 --- a/lib/gitlab/lfs/response.rb +++ b/lib/gitlab/lfs/response.rb @@ -47,6 +47,8 @@ module Gitlab end def render_storage_upload_store_response(oid, size, tmp_file_name) + return render_forbidden unless tmp_file_name + render_response_to_push do render_lfs_upload_ok(oid, size, tmp_file_name) end diff --git a/lib/gitlab/lfs/router.rb b/lib/gitlab/lfs/router.rb index 69bd5e62305..f2a76a56b8f 100644 --- a/lib/gitlab/lfs/router.rb +++ b/lib/gitlab/lfs/router.rb @@ -74,8 +74,6 @@ module Gitlab lfs.render_storage_upload_authorize_response(oid, size) else tmp_file_name = sanitize_tmp_filename(@request.env['HTTP_X_GITLAB_LFS_TMP']) - return nil unless tmp_file_name - lfs.render_storage_upload_store_response(oid, size, tmp_file_name) end end diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index aaad1e3a6ec..93d2bc160cc 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -557,7 +557,7 @@ describe Gitlab::Lfs::Router do end it 'does not recognize it as a valid lfs command' do - expect(response).to have_http_status(401) + expect(response).to have_http_status(403) end end end From 3a3d999601ded922acca5a8f7a5f374f9690c1e0 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 15 Jul 2016 16:35:48 +0200 Subject: [PATCH 292/335] Fix stage status shown for pipelines --- CHANGELOG | 1 + .../projects/ci/pipelines/_pipeline.html.haml | 2 +- spec/models/commit_status_spec.rb | 24 +++++++++++++++---- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 040926d270d..67d7b43fef2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -58,6 +58,7 @@ v 8.10.0 (unreleased) - Collapse large diffs by default (!4990) - Check for conflicts with existing Project's wiki path when creating a new project. - Show last push widget in upstream after push to fork + - Fix stage status shown for pipelines - Cache todos pending/done dashboard query counts. - Don't instantiate a git tree on Projects show default view - Bump Rinku to 2.0.0 diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index b53a8633937..0a103e58db3 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -32,7 +32,7 @@ Cant find HEAD commit for this branch - - stages_status = pipeline.statuses.stages_status + - stages_status = pipeline.statuses.latest.stages_status - stages.each do |stage| %td - status = stages_status[stage] diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb index 05f22c7a9eb..ff6371ad685 100644 --- a/spec/models/commit_status_spec.rb +++ b/spec/models/commit_status_spec.rb @@ -177,10 +177,10 @@ describe CommitStatus, models: true do describe '#stages' do before do - FactoryGirl.create :commit_status, pipeline: pipeline, stage: 'build', stage_idx: 0, status: 'success' - FactoryGirl.create :commit_status, pipeline: pipeline, stage: 'build', stage_idx: 0, status: 'failed' - FactoryGirl.create :commit_status, pipeline: pipeline, stage: 'deploy', stage_idx: 2, status: 'running' - FactoryGirl.create :commit_status, pipeline: pipeline, stage: 'test', stage_idx: 1, status: 'success' + create :commit_status, pipeline: pipeline, stage: 'build', name: 'linux', stage_idx: 0, status: 'success' + create :commit_status, pipeline: pipeline, stage: 'build', name: 'mac', stage_idx: 0, status: 'failed' + create :commit_status, pipeline: pipeline, stage: 'deploy', name: 'staging', stage_idx: 2, status: 'running' + create :commit_status, pipeline: pipeline, stage: 'test', name: 'rspec', stage_idx: 1, status: 'success' end context 'stages list' do @@ -192,7 +192,7 @@ describe CommitStatus, models: true do end context 'stages with statuses' do - subject { CommitStatus.where(pipeline: pipeline).stages_status } + subject { CommitStatus.where(pipeline: pipeline).latest.stages_status } it 'return list of stages with statuses' do is_expected.to eq({ @@ -201,6 +201,20 @@ describe CommitStatus, models: true do 'deploy' => 'running' }) end + + context 'when build is retried' do + before do + create :commit_status, pipeline: pipeline, stage: 'build', name: 'mac', stage_idx: 0, status: 'success' + end + + it 'ignores a previous state' do + is_expected.to eq({ + 'build' => 'success', + 'test' => 'success', + 'deploy' => 'running' + }) + end + end end end From 1744c742f28afb1a89432fa2854fad93e1557fd8 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 15 Jul 2016 17:05:41 +0200 Subject: [PATCH 293/335] Allow to access Container Registry for Public and Internal projects --- CHANGELOG | 1 + app/models/ability.rb | 3 +- .../security/project/internal_access_spec.rb | 19 +++ .../security/project/private_access_spec.rb | 19 +++ .../security/project/public_access_spec.rb | 19 +++ ...er_registry_authentication_service_spec.rb | 110 +++++++++++++----- 6 files changed, 142 insertions(+), 29 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 040926d270d..bb58672f7bf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -79,6 +79,7 @@ v 8.10.0 (unreleased) - Don't garbage collect commits that have related DB records like comments - More descriptive message for git hooks and file locks - Handle custom Git hook result in GitLab UI + - Allow to access Container Registry for Public and Internal projects - Allow '?', or '&' for label names - Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests - Add date when user joined the team on the member page diff --git a/app/models/ability.rb b/app/models/ability.rb index eeb0ceba081..6fd18f2ee24 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -204,7 +204,8 @@ class Ability :download_code, :fork_project, :read_commit_status, - :read_pipeline + :read_pipeline, + :read_container_image ] end diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index 13d980a326f..b6acc509342 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -426,4 +426,23 @@ describe "Internal Project Access", feature: true do it { is_expected.to be_denied_for :external } it { is_expected.to be_denied_for :visitor } end + + describe "GET /:project_path/container_registry" do + before do + stub_container_registry_tags('latest') + stub_container_registry_config(enabled: true) + end + + subject { namespace_project_container_registry_index_path(project.namespace, project) } + + it { is_expected.to be_allowed_for :admin } + it { is_expected.to be_allowed_for owner } + it { is_expected.to be_allowed_for master } + it { is_expected.to be_allowed_for developer } + it { is_expected.to be_allowed_for reporter } + it { is_expected.to be_allowed_for guest } + it { is_expected.to be_allowed_for :user } + it { is_expected.to be_denied_for :external } + it { is_expected.to be_denied_for :visitor } + end end diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index ac9690cc127..ccb5c06dab0 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -362,4 +362,23 @@ describe "Private Project Access", feature: true do it { is_expected.to be_denied_for :external } it { is_expected.to be_denied_for :visitor } end + + describe "GET /:project_path/container_registry" do + before do + stub_container_registry_tags('latest') + stub_container_registry_config(enabled: true) + end + + subject { namespace_project_container_registry_index_path(project.namespace, project) } + + it { is_expected.to be_allowed_for :admin } + it { is_expected.to be_allowed_for owner } + it { is_expected.to be_allowed_for master } + it { is_expected.to be_allowed_for developer } + it { is_expected.to be_allowed_for reporter } + it { is_expected.to be_denied_for guest } + it { is_expected.to be_denied_for :user } + it { is_expected.to be_denied_for :external } + it { is_expected.to be_denied_for :visitor } + end end diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index 737897de52b..985663e7c98 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -426,4 +426,23 @@ describe "Public Project Access", feature: true do it { is_expected.to be_denied_for :external } it { is_expected.to be_denied_for :visitor } end + + describe "GET /:project_path/container_registry" do + before do + stub_container_registry_tags('latest') + stub_container_registry_config(enabled: true) + end + + subject { namespace_project_container_registry_index_path(project.namespace, project) } + + it { is_expected.to be_allowed_for :admin } + it { is_expected.to be_allowed_for owner } + it { is_expected.to be_allowed_for master } + it { is_expected.to be_allowed_for developer } + it { is_expected.to be_allowed_for reporter } + it { is_expected.to be_allowed_for guest } + it { is_expected.to be_allowed_for :user } + it { is_expected.to be_allowed_for :external } + it { is_expected.to be_allowed_for :visitor } + end end diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb index 67777ad48bc..7cc71f706ce 100644 --- a/spec/services/auth/container_registry_authentication_service_spec.rb +++ b/spec/services/auth/container_registry_authentication_service_spec.rb @@ -87,51 +87,105 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do end context 'user authorization' do - let(:project) { create(:project) } let(:current_user) { create(:user) } - context 'allow to use scope-less authentication' do - it_behaves_like 'a valid token' - end + context 'for private project' do + let(:project) { create(:empty_project) } - context 'allow developer to push images' do - before { project.team << [current_user, :developer] } - - let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push" } + context 'allow to use scope-less authentication' do + it_behaves_like 'a valid token' end - it_behaves_like 'a pushable' - end + context 'allow developer to push images' do + before { project.team << [current_user, :developer] } - context 'allow reporter to pull images' do - before { project.team << [current_user, :reporter] } + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:push" } + end - let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + it_behaves_like 'a pushable' end - it_behaves_like 'a pullable' - end + context 'allow reporter to pull images' do + before { project.team << [current_user, :reporter] } - context 'return a least of privileges' do - before { project.team << [current_user, :reporter] } + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:pull" } + end - let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push,pull" } + it_behaves_like 'a pullable' end - it_behaves_like 'a pullable' - end + context 'return a least of privileges' do + before { project.team << [current_user, :reporter] } - context 'disallow guest to pull or push images' do - before { project.team << [current_user, :guest] } + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:push,pull" } + end - let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull,push" } + it_behaves_like 'a pullable' end - it_behaves_like 'an inaccessible' + context 'disallow guest to pull or push images' do + before { project.team << [current_user, :guest] } + + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:pull,push" } + end + + it_behaves_like 'an inaccessible' + end + end + + context 'for public project' do + let(:project) { create(:empty_project, :public) } + + context 'allow anyone to pull images' do + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:pull" } + end + + it_behaves_like 'a pullable' + end + + context 'disallow anyone to push images' do + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:push" } + end + + it_behaves_like 'an inaccessible' + end + end + + context 'for internal project' do + let(:project) { create(:empty_project, :internal) } + + context 'for internal user' do + context 'allow anyone to pull images' do + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:pull" } + end + + it_behaves_like 'a pullable' + end + + context 'disallow anyone to push images' do + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:push" } + end + + it_behaves_like 'an inaccessible' + end + end + + context 'for external user' do + let(:current_user) { create(:user, external: true) } + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:pull,push" } + end + + it_behaves_like 'an inaccessible' + end end end From fbdf9008c2f6f2fbf75338ab6582b65072972f08 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 15 Jun 2016 16:08:45 +0200 Subject: [PATCH 294/335] Make docker registry work with location redirects when external storage is used --- CHANGELOG | 1 + lib/container_registry/tag.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 5ab16db31ce..8a4b8f4dfbc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -281,6 +281,7 @@ v 8.9.0 - TeamCity Service: Fix URL handling when base URL contains a path - Todos will display target state if issuable target is 'Closed' or 'Merged' - Validate only and except regexp + - Make docker registry work with location redirects when external storage is used - Fix bug when sorting issues by milestone due date and filtering by two or more labels - POST to API /projects/:id/runners/:runner_id would give 409 if the runner was already enabled for this project - Add support for using Yubikeys (U2F) for two-factor authentication diff --git a/lib/container_registry/tag.rb b/lib/container_registry/tag.rb index 708d01b95a1..59040199920 100644 --- a/lib/container_registry/tag.rb +++ b/lib/container_registry/tag.rb @@ -53,7 +53,7 @@ module ContainerRegistry def config return unless config_blob - @config ||= ContainerRegistry::Config.new(self, config_blob) + @config ||= ContainerRegistry::Config.new(self, config_blob) if config_blob.data end def created_at From a3d8a7e6be2511ba9457a5045581de2b3ce80ab0 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 29 Jun 2016 14:18:55 +0200 Subject: [PATCH 295/335] Allow blob to be redirected --- lib/container_registry/client.rb | 37 +++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb index 42232b7129d..50ddf79601d 100644 --- a/lib/container_registry/client.rb +++ b/lib/container_registry/client.rb @@ -7,6 +7,13 @@ module ContainerRegistry MANIFEST_VERSION = 'application/vnd.docker.distribution.manifest.v2+json' + # Taken from: FaradayMiddleware::FollowRedirects + REDIRECT_CODES = Set.new [301, 302, 303, 307] + + # Regex that matches characters that need to be escaped in URLs, sans + # the "%" character which we assume already represents an escaped sequence. + URI_UNSAFE = /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]%]/ + def initialize(base_uri, options = {}) @base_uri = base_uri @faraday = Faraday.new(@base_uri) do |conn| @@ -34,7 +41,7 @@ module ContainerRegistry def blob(name, digest, type = nil) headers = {} headers['Accept'] = type if type - response_body @faraday.get("/v2/#{name}/blobs/#{digest}", nil, headers) + response_body @faraday.get("/v2/#{name}/blobs/#{digest}", nil, headers), allow_redirect: true end def delete_blob(name, digest) @@ -61,8 +68,32 @@ module ContainerRegistry conn.adapter :net_http end - def response_body(response) - response.body if response.success? + def response_body(response, allow_redirect: false) + if allow_redirect && REDIRECT_CODES.include?(response.status) + response = redirect_response(response.env['url'], response.headers['location']) + end + + response.body if response && response.success? + end + + def redirect_response(url, location) + return unless location + + url += safe_escape(location) + + # We use HTTParty due to fact that @faraday contains internal authorization token + HTTParty.get(url) + end + + # Taken from: FaradayMiddleware::FollowRedirects + # Internal: escapes unsafe characters from an URL which might be a path + # component only or a fully qualified URI so that it can be joined onto an + # URI:HTTP using the `+` operator. Doesn't escape "%" characters so to not + # risk double-escaping. + def safe_escape(uri) + uri.to_s.gsub(URI_UNSAFE) { |match| + '%' + match.unpack('H2' * match.bytesize).join('%').upcase + } end end end From 3e4dc164a7a99f19c24accc64b15fb33c0bee1aa Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 30 Jun 2016 14:49:58 +0200 Subject: [PATCH 296/335] Explicitly remove authorization token and make sure that invalid addresses are properly handled --- lib/container_registry/client.rb | 74 ++++++++++++------------ spec/lib/container_registry/blob_spec.rb | 52 ++++++++++++++++- spec/lib/container_registry/tag_spec.rb | 47 +++++++++++---- 3 files changed, 122 insertions(+), 51 deletions(-) diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb index 50ddf79601d..3dda60f607c 100644 --- a/lib/container_registry/client.rb +++ b/lib/container_registry/client.rb @@ -10,54 +10,41 @@ module ContainerRegistry # Taken from: FaradayMiddleware::FollowRedirects REDIRECT_CODES = Set.new [301, 302, 303, 307] - # Regex that matches characters that need to be escaped in URLs, sans - # the "%" character which we assume already represents an escaped sequence. - URI_UNSAFE = /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]%]/ - def initialize(base_uri, options = {}) @base_uri = base_uri - @faraday = Faraday.new(@base_uri) do |conn| - initialize_connection(conn, options) - end + @options = options end def repository_tags(name) - response_body @faraday.get("/v2/#{name}/tags/list") + response_body faraday.get("/v2/#{name}/tags/list") end def repository_manifest(name, reference) - response_body @faraday.get("/v2/#{name}/manifests/#{reference}") + response_body faraday.get("/v2/#{name}/manifests/#{reference}") end def repository_tag_digest(name, reference) - response = @faraday.head("/v2/#{name}/manifests/#{reference}") + response = faraday.head("/v2/#{name}/manifests/#{reference}") response.headers['docker-content-digest'] if response.success? end def delete_repository_tag(name, reference) - @faraday.delete("/v2/#{name}/manifests/#{reference}").success? + faraday.delete("/v2/#{name}/manifests/#{reference}").success? end def blob(name, digest, type = nil) - headers = {} - headers['Accept'] = type if type - response_body @faraday.get("/v2/#{name}/blobs/#{digest}", nil, headers), allow_redirect: true + type ||= 'application/octet-stream' + response_body faraday_blob.get("/v2/#{name}/blobs/#{digest}", nil, 'Accept' => type), allow_redirect: true end def delete_blob(name, digest) - @faraday.delete("/v2/#{name}/blobs/#{digest}").success? + faraday.delete("/v2/#{name}/blobs/#{digest}").success? end - + private - + def initialize_connection(conn, options) conn.request :json - conn.headers['Accept'] = MANIFEST_VERSION - - conn.response :json, content_type: 'application/json' - conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v1+prettyjws' - conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v1+json' - conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v2+json' if options[:user] && options[:password] conn.request(:basic_auth, options[:user].to_s, options[:password].to_s) @@ -68,32 +55,43 @@ module ContainerRegistry conn.adapter :net_http end + def accept_manifest(conn) + conn.headers['Accept'] = MANIFEST_VERSION + + conn.response :json, content_type: 'application/json' + conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v1+prettyjws' + conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v1+json' + conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v2+json' + end + def response_body(response, allow_redirect: false) if allow_redirect && REDIRECT_CODES.include?(response.status) - response = redirect_response(response.env['url'], response.headers['location']) + response = redirect_response(response.headers['location']) end response.body if response && response.success? end - def redirect_response(url, location) + def redirect_response(location) return unless location - url += safe_escape(location) - - # We use HTTParty due to fact that @faraday contains internal authorization token - HTTParty.get(url) + # We explicitly remove authorization token + faraday_blob.get(location) do |req| + req['Authorization'] = '' + end end - # Taken from: FaradayMiddleware::FollowRedirects - # Internal: escapes unsafe characters from an URL which might be a path - # component only or a fully qualified URI so that it can be joined onto an - # URI:HTTP using the `+` operator. Doesn't escape "%" characters so to not - # risk double-escaping. - def safe_escape(uri) - uri.to_s.gsub(URI_UNSAFE) { |match| - '%' + match.unpack('H2' * match.bytesize).join('%').upcase - } + def faraday + @faraday ||= Faraday.new(@base_uri) do |conn| + initialize_connection(conn, @options) + accept_manifest(conn) + end + end + + def faraday_blob + @faraday_blob ||= Faraday.new(@base_uri) do |conn| + initialize_connection(conn, @options) + end end end end diff --git a/spec/lib/container_registry/blob_spec.rb b/spec/lib/container_registry/blob_spec.rb index 4d8cb787dde..bbacdc67ebd 100644 --- a/spec/lib/container_registry/blob_spec.rb +++ b/spec/lib/container_registry/blob_spec.rb @@ -9,8 +9,9 @@ describe ContainerRegistry::Blob do 'size' => 1000 } end + let(:token) { 'authorization-token' } - let(:registry) { ContainerRegistry::Registry.new('http://example.com') } + let(:registry) { ContainerRegistry::Registry.new('http://example.com', token: token) } let(:repository) { registry.repository('group/test') } let(:blob) { repository.blob(config) } @@ -58,4 +59,53 @@ describe ContainerRegistry::Blob do it { is_expected.to be_truthy } end + + context '#data' do + let(:data) { '{"key":"value"}' } + + subject { blob.data } + + context 'when locally stored' do + before do + stub_request(:get, 'http://example.com/v2/group/test/blobs/sha256:0123456789012345'). + to_return( + status: 200, + headers: { 'Content-Type' => 'application/json' }, + body: data) + end + + it { is_expected.to eq(data) } + end + + context 'when externally stored' do + before do + stub_request(:get, 'http://example.com/v2/group/test/blobs/sha256:0123456789012345'). + with(headers: { 'Authorization' => "bearer #{token}" }). + to_return( + status: 307, + headers: { 'Location' => location }) + end + + context 'for a valid address' do + let(:location) { 'http://external.com/blob/file' } + + before do + stub_request(:get, location). + with(headers: { 'Authorization' => nil }). + to_return( + status: 200, + headers: { 'Content-Type' => 'application/json' }, + body: data) + end + + it { is_expected.to eq(data) } + end + + context 'for invalid file' do + let(:location) { 'file:///etc/passwd' } + + it { expect{ subject }.to raise_error(ArgumentError, 'invalid address') } + end + end + end end diff --git a/spec/lib/container_registry/tag_spec.rb b/spec/lib/container_registry/tag_spec.rb index c7324c2bf77..c5e31ae82b6 100644 --- a/spec/lib/container_registry/tag_spec.rb +++ b/spec/lib/container_registry/tag_spec.rb @@ -77,24 +77,47 @@ describe ContainerRegistry::Tag do end context 'config processing' do - before do - stub_request(:get, 'http://example.com/v2/group/test/blobs/sha256:d7a513a663c1a6dcdba9ed832ca53c02ac2af0c333322cd6ca92936d1d9917ac'). - with(headers: { 'Accept' => 'application/octet-stream' }). - to_return( - status: 200, - body: File.read(Rails.root + 'spec/fixtures/container_registry/config_blob.json')) + shared_examples 'a processable' do + context '#config' do + subject { tag.config } + + it { is_expected.not_to be_nil } + end + + context '#created_at' do + subject { tag.created_at } + + it { is_expected.not_to be_nil } + end end - context '#config' do - subject { tag.config } + context 'when locally stored' do + before do + stub_request(:get, 'http://example.com/v2/group/test/blobs/sha256:d7a513a663c1a6dcdba9ed832ca53c02ac2af0c333322cd6ca92936d1d9917ac'). + with(headers: { 'Accept' => 'application/octet-stream' }). + to_return( + status: 200, + body: File.read(Rails.root + 'spec/fixtures/container_registry/config_blob.json')) + end - it { is_expected.not_to be_nil } + it_behaves_like 'a processable' end - context '#created_at' do - subject { tag.created_at } + context 'when externally stored' do + before do + stub_request(:get, 'http://example.com/v2/group/test/blobs/sha256:d7a513a663c1a6dcdba9ed832ca53c02ac2af0c333322cd6ca92936d1d9917ac'). + with(headers: { 'Accept' => 'application/octet-stream' }). + to_return( + status: 307, + headers: { 'Location' => 'http://external.com/blob/file' }) - it { is_expected.not_to be_nil } + stub_request(:get, 'http://external.com/blob/file'). + to_return( + status: 200, + body: File.read(Rails.root + 'spec/fixtures/container_registry/config_blob.json')) + end + + it_behaves_like 'a processable' end end end From 2630111e5141fcc211e76c7512aec47614a8bd3b Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 15 Jul 2016 17:36:00 +0200 Subject: [PATCH 297/335] Add CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 8a4b8f4dfbc..141a323ab99 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -81,6 +81,7 @@ v 8.10.0 (unreleased) - More descriptive message for git hooks and file locks - Handle custom Git hook result in GitLab UI - Allow '?', or '&' for label names + - Support redirected blobs for Container Registry integration - Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests - Add date when user joined the team on the member page - Fix 404 redirect after validation fails importing a GitLab project From 1556d4848d4753b7bddd8430cf223b91e6f47b0f Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 15 Jul 2016 15:42:29 +0200 Subject: [PATCH 298/335] Track a user who created a pipeline --- CHANGELOG | 1 + app/models/ci/pipeline.rb | 2 ++ app/models/project.rb | 4 ++-- app/models/user.rb | 1 + app/services/ci/create_pipeline_service.rb | 1 + app/services/create_commit_builds_service.rb | 8 +++++++- db/migrate/20160715132507_add_user_id_to_pipeline.rb | 7 +++++++ db/schema.rb | 3 ++- lib/api/commit_statuses.rb | 2 +- spec/models/ci/pipeline_spec.rb | 3 +++ spec/models/user_spec.rb | 2 ++ spec/services/create_commit_builds_service_spec.rb | 3 ++- 12 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20160715132507_add_user_id_to_pipeline.rb diff --git a/CHANGELOG b/CHANGELOG index 5ab16db31ce..044bdb476cc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -53,6 +53,7 @@ v 8.10.0 (unreleased) - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - Only show New Snippet button to users that can create snippets. - PipelinesFinder uses git cache data + - Track a user who created a pipeline - Actually render old and new sections of parallel diff next to each other - Throttle the update of `project.pushes_since_gc` to 1 minute. - Allow expanding and collapsing files in diff view (!4990) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index fa4071e2482..cb284ba1e1c 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -6,6 +6,8 @@ module Ci self.table_name = 'ci_commits' belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id + belongs_to :user + has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id has_many :builds, class_name: 'Ci::Build', foreign_key: :commit_id has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest', foreign_key: :commit_id diff --git a/app/models/project.rb b/app/models/project.rb index e7b9835692d..dba3b3413ef 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1038,8 +1038,8 @@ class Project < ActiveRecord::Base pipelines.order(id: :desc).find_by(sha: sha, ref: ref) end - def ensure_pipeline(sha, ref) - pipeline(sha, ref) || pipelines.create(sha: sha, ref: ref) + def ensure_pipeline(sha, ref, current_user = nil) + pipeline(sha, ref) || pipelines.create(sha: sha, ref: ref, user: current_user) end def enable_ci diff --git a/app/models/user.rb b/app/models/user.rb index 7a72c202150..3d0a033785c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -85,6 +85,7 @@ class User < ActiveRecord::Base has_one :abuse_report, dependent: :destroy has_many :spam_logs, dependent: :destroy has_many :builds, dependent: :nullify, class_name: 'Ci::Build' + has_many :pipelines, dependent: :nullify, class_name: 'Ci::Pipeline' has_many :todos, dependent: :destroy has_many :notification_settings, dependent: :destroy has_many :award_emoji, dependent: :destroy diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index b1ee6874190..be91bf0db85 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -2,6 +2,7 @@ module Ci class CreatePipelineService < BaseService def execute pipeline = project.pipelines.new(params) + pipeline.user = current_user unless ref_names.include?(params[:ref]) pipeline.errors.add(:base, 'Reference not found') diff --git a/app/services/create_commit_builds_service.rb b/app/services/create_commit_builds_service.rb index f947e8f452e..0b66b854dea 100644 --- a/app/services/create_commit_builds_service.rb +++ b/app/services/create_commit_builds_service.rb @@ -14,7 +14,13 @@ class CreateCommitBuildsService return false end - @pipeline = Ci::Pipeline.new(project: project, sha: sha, ref: ref, before_sha: before_sha, tag: tag) + @pipeline = Ci::Pipeline.new( + project: project, + sha: sha, + ref: ref, + before_sha: before_sha, + tag: tag, + user: user) ## # Skip creating pipeline if no gitlab-ci.yml is found diff --git a/db/migrate/20160715132507_add_user_id_to_pipeline.rb b/db/migrate/20160715132507_add_user_id_to_pipeline.rb new file mode 100644 index 00000000000..af0461c4daf --- /dev/null +++ b/db/migrate/20160715132507_add_user_id_to_pipeline.rb @@ -0,0 +1,7 @@ +class AddUserIdToPipeline < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + def change + add_column :ci_commits, :user_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index f24e47b85b2..6ab5a1eaded 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160712171823) do +ActiveRecord::Schema.define(version: 20160715132507) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -199,6 +199,7 @@ ActiveRecord::Schema.define(version: 20160712171823) do t.datetime "started_at" t.datetime "finished_at" t.integer "duration" + t.integer "user_id" end add_index "ci_commits", ["gl_project_id", "sha"], name: "index_ci_commits_on_gl_project_id_and_sha", using: :btree diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb index 323a7086890..acb4812b5cf 100644 --- a/lib/api/commit_statuses.rb +++ b/lib/api/commit_statuses.rb @@ -64,7 +64,7 @@ module API ref = branches.first end - pipeline = @project.ensure_pipeline(commit.sha, ref) + pipeline = @project.ensure_pipeline(commit.sha, ref, current_user) name = params[:name] || params[:context] status = GenericCommitStatus.running_or_pending.find_by(pipeline: pipeline, name: name, ref: params[:ref]) diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 4e5481f9154..10db79bd15f 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -5,9 +5,12 @@ describe Ci::Pipeline, models: true do let(:pipeline) { FactoryGirl.create :ci_pipeline, project: project } it { is_expected.to belong_to(:project) } + it { is_expected.to belong_to(:user) } + it { is_expected.to have_many(:statuses) } it { is_expected.to have_many(:trigger_requests) } it { is_expected.to have_many(:builds) } + it { is_expected.to validate_presence_of :sha } it { is_expected.to validate_presence_of :status } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index ff39f187759..fc74488ac0e 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -31,6 +31,8 @@ describe User, models: true do it { is_expected.to have_many(:spam_logs).dependent(:destroy) } it { is_expected.to have_many(:todos).dependent(:destroy) } it { is_expected.to have_many(:award_emoji).dependent(:destroy) } + it { is_expected.to have_many(:builds).dependent(:nullify) } + it { is_expected.to have_many(:pipelines).dependent(:nullify) } describe '#group_members' do it 'does not include group memberships for which user is a requester' do diff --git a/spec/services/create_commit_builds_service_spec.rb b/spec/services/create_commit_builds_service_spec.rb index 4d09bc5fb12..7caf69bc870 100644 --- a/spec/services/create_commit_builds_service_spec.rb +++ b/spec/services/create_commit_builds_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe CreateCommitBuildsService, services: true do let(:service) { CreateCommitBuildsService.new } let(:project) { FactoryGirl.create(:empty_project) } - let(:user) { nil } + let(:user) { create(:user) } before do stub_ci_pipeline_to_return_yaml_file @@ -24,6 +24,7 @@ describe CreateCommitBuildsService, services: true do it { expect(pipeline).to be_valid } it { expect(pipeline).to be_persisted } it { expect(pipeline).to eq(project.pipelines.last) } + it { expect(pipeline).to have_attributes(:user => user) } it { expect(pipeline.builds.first).to be_kind_of(Ci::Build) } end From 7993fc1b89f6a8903fea0aa9586b1ed1d8a3b29e Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 15 Jul 2016 15:46:49 +0200 Subject: [PATCH 299/335] Add index for user_id of pipeline --- .../20160715134306_add_index_for_pipeline_user_id.rb | 7 +++++++ db/schema.rb | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20160715134306_add_index_for_pipeline_user_id.rb diff --git a/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb b/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb new file mode 100644 index 00000000000..ac5d2bec681 --- /dev/null +++ b/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb @@ -0,0 +1,7 @@ +class AddIndexForPipelineUserId < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + def change + add_index :ci_commits, :user_id + end +end diff --git a/db/schema.rb b/db/schema.rb index 6ab5a1eaded..c96baef6a8b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160715132507) do +ActiveRecord::Schema.define(version: 20160715134306) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -211,6 +211,7 @@ ActiveRecord::Schema.define(version: 20160715132507) do add_index "ci_commits", ["project_id"], name: "index_ci_commits_on_project_id", using: :btree add_index "ci_commits", ["sha"], name: "index_ci_commits_on_sha", using: :btree add_index "ci_commits", ["status"], name: "index_ci_commits_on_status", using: :btree + add_index "ci_commits", ["user_id"], name: "index_ci_commits_on_user_id", using: :btree create_table "ci_events", force: :cascade do |t| t.integer "project_id" From 9d72d902cf21c786b871eced12609a793596cf29 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 15 Jul 2016 18:01:43 +0200 Subject: [PATCH 300/335] Make rubocop happy --- db/migrate/20160715134306_add_index_for_pipeline_user_id.rb | 2 +- spec/services/create_commit_builds_service_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb b/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb index ac5d2bec681..e09caa0e6d7 100644 --- a/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb +++ b/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb @@ -2,6 +2,6 @@ class AddIndexForPipelineUserId < ActiveRecord::Migration include Gitlab::Database::MigrationHelpers def change - add_index :ci_commits, :user_id + add_concurrent_index :ci_commits, :user_id end end diff --git a/spec/services/create_commit_builds_service_spec.rb b/spec/services/create_commit_builds_service_spec.rb index 7caf69bc870..d4c5e584421 100644 --- a/spec/services/create_commit_builds_service_spec.rb +++ b/spec/services/create_commit_builds_service_spec.rb @@ -24,7 +24,7 @@ describe CreateCommitBuildsService, services: true do it { expect(pipeline).to be_valid } it { expect(pipeline).to be_persisted } it { expect(pipeline).to eq(project.pipelines.last) } - it { expect(pipeline).to have_attributes(:user => user) } + it { expect(pipeline).to have_attributes(user: user) } it { expect(pipeline.builds.first).to be_kind_of(Ci::Build) } end From 52af77d8f8e45caff9b7a496768fa47256e74c71 Mon Sep 17 00:00:00 2001 From: "Jacob Vosmaer (GitLab)" Date: Fri, 15 Jul 2016 16:04:45 +0000 Subject: [PATCH 301/335] Don't ask Heather to review documentation MR's --- doc/development/doc_styleguide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/development/doc_styleguide.md b/doc/development/doc_styleguide.md index 975bb82c37d..fac35ec964d 100644 --- a/doc/development/doc_styleguide.md +++ b/doc/development/doc_styleguide.md @@ -44,7 +44,7 @@ it organized and easy to find. - When introducing a new document, be careful for the headings to be grammatically and syntactically correct. It is advised to mention one or all of the following GitLab members for a review: `@axil`, `@rspeicher`, - `@dblessing`, `@ashleys`, `@nearlythere`. This is to ensure that no document + `@dblessing`, `@ashleys`. This is to ensure that no document with wrong heading is going live without an audit, thus preventing dead links and redirection issues when corrected - Leave exactly one newline after a heading From 2462a473c2048dc0bc2b4e8e2aa2c802566d687c Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 15 Jul 2016 18:05:39 +0200 Subject: [PATCH 302/335] Make rubocop happy --- lib/container_registry/client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb index 3dda60f607c..2edddb84fc3 100644 --- a/lib/container_registry/client.rb +++ b/lib/container_registry/client.rb @@ -8,7 +8,7 @@ module ContainerRegistry MANIFEST_VERSION = 'application/vnd.docker.distribution.manifest.v2+json' # Taken from: FaradayMiddleware::FollowRedirects - REDIRECT_CODES = Set.new [301, 302, 303, 307] + REDIRECT_CODES = Set.new [301, 302, 303, 307] def initialize(base_uri, options = {}) @base_uri = base_uri From 66c4ed6165d5e895ee802d9745205a05dfca9986 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 13 Jul 2016 21:00:46 -0300 Subject: [PATCH 303/335] Fix mentioned users list on diff notes --- app/models/concerns/note_on_diff.rb | 3 +++ spec/services/todo_service_spec.rb | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/app/models/concerns/note_on_diff.rb b/app/models/concerns/note_on_diff.rb index 2785fbb21c9..7b6a28ccf3c 100644 --- a/app/models/concerns/note_on_diff.rb +++ b/app/models/concerns/note_on_diff.rb @@ -4,6 +4,9 @@ module NoteOnDiff NUMBER_OF_TRUNCATED_DIFF_LINES = 16 included do + attr_mentionable :note, pipeline: :note + participant :author + delegate :blob, :highlighted_diff_lines, to: :diff_file, allow_nil: true end diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index b4522536724..83c18a35472 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -435,6 +435,24 @@ describe TodoService, services: true do should_create_todo(user: author, target: mr_unassigned, action: Todo::MARKED) end end + + describe '#new_note' do + let(:mention) { john_doe.to_reference } + let(:diff_note_on_merge_request) { create(:diff_note_on_merge_request, project: project, noteable: mr_unassigned, author: author, note: "Hey #{mention}") } + let(:legacy_diff_note_on_merge_request) { create(:legacy_diff_note_on_merge_request, project: project, noteable: mr_unassigned, author: author, note: "Hey #{mention}") } + + it 'creates a todo for mentioned user on new diff note' do + service.new_note(diff_note_on_merge_request, author) + + should_create_todo(user: john_doe, target: mr_unassigned, author: author, action: Todo::MENTIONED, note: diff_note_on_merge_request) + end + + it 'creates a todo for mentioned user on legacy diff note' do + service.new_note(legacy_diff_note_on_merge_request, author) + + should_create_todo(user: john_doe, target: mr_unassigned, author: author, action: Todo::MENTIONED, note: legacy_diff_note_on_merge_request) + end + end end it 'updates cached counts when a todo is created' do From 16c9abf1ee95551d130e8b8eb454c440ca4c2eb2 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 14 Jul 2016 00:28:58 -0300 Subject: [PATCH 304/335] Use cattr_accessor instead duplicating code on NoteOnDiff concern --- app/models/concerns/mentionable.rb | 10 +++++----- app/models/concerns/note_on_diff.rb | 3 --- app/models/concerns/participable.rb | 7 +++++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb index 8cac47246db..ec9e0f1b1d0 100644 --- a/app/models/concerns/mentionable.rb +++ b/app/models/concerns/mentionable.rb @@ -14,14 +14,14 @@ module Mentionable attr = attr.to_s mentionable_attrs << [attr, options] end - - # Accessor for attributes marked mentionable. - def mentionable_attrs - @mentionable_attrs ||= [] - end end included do + # Accessor for attributes marked mentionable. + cattr_accessor :mentionable_attrs, instance_accessor: false do + [] + end + if self < Participable participant -> (user, ext) { all_references(user, extractor: ext) } end diff --git a/app/models/concerns/note_on_diff.rb b/app/models/concerns/note_on_diff.rb index 7b6a28ccf3c..2785fbb21c9 100644 --- a/app/models/concerns/note_on_diff.rb +++ b/app/models/concerns/note_on_diff.rb @@ -4,9 +4,6 @@ module NoteOnDiff NUMBER_OF_TRUNCATED_DIFF_LINES = 16 included do - attr_mentionable :note, pipeline: :note - participant :author - delegate :blob, :highlighted_diff_lines, to: :diff_file, allow_nil: true end diff --git a/app/models/concerns/participable.rb b/app/models/concerns/participable.rb index 9822844357d..70740c76e43 100644 --- a/app/models/concerns/participable.rb +++ b/app/models/concerns/participable.rb @@ -41,9 +41,12 @@ module Participable def participant(attr) participant_attrs << attr end + end - def participant_attrs - @participant_attrs ||= [] + included do + # Accessor for participant attributes. + cattr_accessor :participant_attrs, instance_accessor: false do + [] end end From efe18f0507e08c7fd0f90a99e0c241c3c4ce107a Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 13 Jul 2016 21:01:15 -0300 Subject: [PATCH 305/335] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 5ab16db31ce..424f8956a51 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -57,6 +57,7 @@ v 8.10.0 (unreleased) - Throttle the update of `project.pushes_since_gc` to 1 minute. - Allow expanding and collapsing files in diff view (!4990) - Collapse large diffs by default (!4990) + - Fix mentioned users list on diff notes - Check for conflicts with existing Project's wiki path when creating a new project. - Show last push widget in upstream after push to fork - Cache todos pending/done dashboard query counts. From 566e01a5b1488dfa6bd19fd0818e2c0e8ea71762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Fri, 15 Jul 2016 19:14:52 +0000 Subject: [PATCH 306/335] Update CHANGELOG --- CHANGELOG | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 141a323ab99..80c85213842 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -282,7 +282,6 @@ v 8.9.0 - TeamCity Service: Fix URL handling when base URL contains a path - Todos will display target state if issuable target is 'Closed' or 'Merged' - Validate only and except regexp - - Make docker registry work with location redirects when external storage is used - Fix bug when sorting issues by milestone due date and filtering by two or more labels - POST to API /projects/:id/runners/:runner_id would give 409 if the runner was already enabled for this project - Add support for using Yubikeys (U2F) for two-factor authentication From c5555c8a84f10dd4a3f3f213bcf8b088e2a79718 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 15 Jul 2016 17:32:49 -0500 Subject: [PATCH 307/335] Don't fail when a LegacyDiffNote didn't store the right diff --- app/models/legacy_diff_note.rb | 4 ++-- app/views/notify/note_merge_request_email.html.haml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/legacy_diff_note.rb b/app/models/legacy_diff_note.rb index 790dfd4d480..04a651d50ab 100644 --- a/app/models/legacy_diff_note.rb +++ b/app/models/legacy_diff_note.rb @@ -38,7 +38,7 @@ class LegacyDiffNote < Note end def diff_line - @diff_line ||= diff_file.line_for_line_code(self.line_code) + @diff_line ||= diff_file.line_for_line_code(self.line_code) if diff_file end def for_line?(line) @@ -55,7 +55,7 @@ class LegacyDiffNote < Note def active? return @active if defined?(@active) return true if for_commit? - return true unless self.diff + return true unless diff_line return false unless noteable noteable_diff = find_noteable_diff diff --git a/app/views/notify/note_merge_request_email.html.haml b/app/views/notify/note_merge_request_email.html.haml index 35c4b862bb7..ea7e3d199fd 100644 --- a/app/views/notify/note_merge_request_email.html.haml +++ b/app/views/notify/note_merge_request_email.html.haml @@ -1,4 +1,4 @@ -- if @note.diff_note? +- if @note.diff_note? && @note.diff_file %p.details New comment on diff for = link_to @note.diff_file.file_path, @target_url From 979f1182ae7f036e5b647cdab6c80ca73ede968a Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 15 Jul 2016 17:33:30 -0500 Subject: [PATCH 308/335] Don't fail when Ci::Pipeline doesn't have a project --- app/models/ci/pipeline.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index fa4071e2482..7d743ce99f0 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -215,6 +215,8 @@ module Ci end def keep_around_commits + return unless project + project.repository.keep_around(self.sha) project.repository.keep_around(self.before_sha) end From 34653c1e8be0be230943c39713da424a9e22d15b Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 15 Jul 2016 18:17:15 -0500 Subject: [PATCH 309/335] Update tests --- spec/models/legacy_diff_note_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/models/legacy_diff_note_spec.rb b/spec/models/legacy_diff_note_spec.rb index d64d89edbd3..d23fc06c3ad 100644 --- a/spec/models/legacy_diff_note_spec.rb +++ b/spec/models/legacy_diff_note_spec.rb @@ -16,10 +16,10 @@ describe LegacyDiffNote, models: true do end describe '#active?' do - it 'is always true when the note has no associated diff' do + it 'is always true when the note has no associated diff line' do note = build(:legacy_diff_note_on_merge_request) - expect(note).to receive(:diff).and_return(nil) + expect(note).to receive(:diff_line).and_return(nil) expect(note).to be_active end @@ -27,7 +27,7 @@ describe LegacyDiffNote, models: true do it 'is never true when the note has no noteable associated' do note = build(:legacy_diff_note_on_merge_request) - expect(note).to receive(:diff).and_return(double) + expect(note).to receive(:diff_line).and_return(double) expect(note).to receive(:noteable).and_return(nil) expect(note).not_to be_active @@ -47,7 +47,7 @@ describe LegacyDiffNote, models: true do merge = build_stubbed(:merge_request, :simple) note = build(:legacy_diff_note_on_merge_request, noteable: merge) - allow(note).to receive(:diff).and_return(double) + allow(note).to receive(:diff_line).and_return(double) expect(note).to receive(:find_noteable_diff).and_return(nil) expect(note).not_to be_active From 2735e5f1c2859ad496bc4f7bd820a7be33f97527 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 15 Jul 2016 23:46:29 +0000 Subject: [PATCH 310/335] Revert "Merge branch 'gl-dropdown-issuable-form' into 'master'" This reverts merge request !4970 --- app/assets/javascripts/dispatcher.js.coffee | 2 -- .../javascripts/labels_select.js.coffee | 31 ++++++---------- .../javascripts/milestone_select.js.coffee | 2 +- app/assets/javascripts/users_select.js.coffee | 9 ++--- .../stylesheets/framework/dropdowns.scss | 2 +- .../stylesheets/pages/merge_requests.scss | 4 --- app/helpers/issuables_helper.rb | 2 +- app/views/shared/issuable/_filter.html.haml | 4 +-- app/views/shared/issuable/_form.html.haml | 36 +++++++++++++------ .../shared/issuable/_label_dropdown.html.haml | 14 ++++---- .../issuable/_milestone_dropdown.html.haml | 8 ++--- features/project/issues/issues.feature | 1 - .../steps/project/forked_merge_requests.rb | 12 ++++--- features/steps/project/issues/issues.rb | 3 +- spec/features/issues/move_spec.rb | 2 +- spec/features/issues_spec.rb | 5 +-- 16 files changed, 65 insertions(+), 72 deletions(-) diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index b5da15e9e49..afaa6407b05 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -39,8 +39,6 @@ class Dispatcher shortcut_handler = new ShortcutsNavigation() new GLForm($('.issue-form')) new IssuableForm($('.issue-form')) - new LabelsSelect() - new MilestoneSelect() when 'projects:merge_requests:new', 'projects:merge_requests:edit' new Diff() shortcut_handler = new ShortcutsNavigation() diff --git a/app/assets/javascripts/labels_select.js.coffee b/app/assets/javascripts/labels_select.js.coffee index 1a802b81452..7688609b301 100644 --- a/app/assets/javascripts/labels_select.js.coffee +++ b/app/assets/javascripts/labels_select.js.coffee @@ -184,22 +184,20 @@ class @LabelsSelect .value() if $dropdown.hasClass 'js-extra-options' - extraData = [] - if showAny - extraData.push( - isAny: true - title: 'Any Label' - ) - if showNo - extraData.push( + data.unshift( id: 0 title: 'No Label' ) - if extraData.length - extraData.push 'divider' - data = extraData.concat(data) + if showAny + data.unshift( + isAny: true + title: 'Any Label' + ) + + if data.length > 2 + data.splice 2, 0, 'divider' callback data @@ -289,12 +287,6 @@ class @LabelsSelect defaultLabel fieldName: $dropdown.data('field-name') id: (label) -> - if $dropdown.hasClass('js-issuable-form-dropdown') - if label.id is 0 - return - else - return label.id - if $dropdown.hasClass("js-filter-submit") and not label.isAny? label.title else @@ -308,9 +300,6 @@ class @LabelsSelect $selectbox.hide() # display:block overrides the hide-collapse rule $value.removeAttr('style') - - return if $dropdown.hasClass('js-issuable-form-dropdown') - if $dropdown.hasClass 'js-multiselect' if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex) selectedLabels = $dropdown @@ -332,7 +321,7 @@ class @LabelsSelect clicked: (label) -> _this.enableBulkLabelDropdown() - if $dropdown.hasClass('js-filter-bulk-update') or $dropdown.hasClass('js-issuable-form-dropdown') + if $dropdown.hasClass('js-filter-bulk-update') return page = $('body').data 'page' diff --git a/app/assets/javascripts/milestone_select.js.coffee b/app/assets/javascripts/milestone_select.js.coffee index 3a036569317..8ab03ed93ee 100644 --- a/app/assets/javascripts/milestone_select.js.coffee +++ b/app/assets/javascripts/milestone_select.js.coffee @@ -62,7 +62,7 @@ class @MilestoneSelect title: 'Upcoming' ) - if extraOptions.length > 0 + if extraOptions.length > 2 extraOptions.push 'divider' callback(extraOptions.concat(data)) diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index e061f042ca9..344be811e0d 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -155,13 +155,11 @@ class @UsersSelect # display:block overrides the hide-collapse rule $value.css('display', '') - clicked: (user, $el, e) -> + clicked: (user) -> page = $('body').data 'page' isIssueIndex = page is 'projects:issues:index' isMRIndex = page is page is 'projects:merge_requests:index' - if $dropdown.hasClass('js-filter-bulk-update') or $dropdown.hasClass('js-issuable-form-dropdown') - e.preventDefault() - selectedId = user.id + if $dropdown.hasClass('js-filter-bulk-update') return if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex) @@ -174,8 +172,7 @@ class @UsersSelect .closest('.selectbox') .find("input[name='#{$dropdown.data('field-name')}']").val() assignTo(selected) - id: (user) -> - user.id + renderRow: (user) -> username = if user.username then "@#{user.username}" else "" avatar = if user.avatar_url then user.avatar_url else false diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index 3fd0e12568d..d4e900f80ef 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -56,7 +56,7 @@ position: absolute; top: 50%; right: 6px; - margin-top: -6px; + margin-top: -4px; color: $dropdown-toggle-icon-color; font-size: 10px; } diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index dba9a7ab3ee..15c6c9f231a 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -324,10 +324,6 @@ .issuable-form-select-holder { display: inline-block; width: 250px; - - .dropdown-menu-toggle { - width: 100%; - } } .table-holder { diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index a3a8c7d5ff9..47d174361db 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -9,7 +9,7 @@ module IssuablesHelper def multi_label_name(current_labels, default_label) # current_labels may be a string from before - if current_labels.is_a?(Array) && current_labels.any? + if current_labels.is_a?(Array) if current_labels.count > 1 "#{current_labels[0]} +#{current_labels.count - 1} more" else diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index d5199bd86dd..094d6636c66 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -21,10 +21,10 @@ placeholder: "Search assignee", data: { any_user: "Any Assignee", first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: params[:assignee_id], field_name: "assignee_id", default_label: "Assignee" } }) .filter-item.inline.milestone-filter - = render "shared/issuable/milestone_dropdown", selected: params[:milestone_title], name: :milestone_title, show_any: true, show_upcoming: true + = render "shared/issuable/milestone_dropdown" .filter-item.inline.labels-filter - = render "shared/issuable/label_dropdown", selected: params[:label_name], data_options: { field_name: "label_name[]" } + = render "shared/issuable/label_dropdown" .pull-right = render 'shared/sort_dropdown' diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index a8a8426df52..c30bdb0ae91 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -52,24 +52,38 @@ = f.label :assignee_id, "Assignee", class: "control-label #{"col-lg-4" if has_due_date}" .col-sm-10{ class: ("col-lg-8" if has_due_date) } .issuable-form-select-holder - - project = @target_project || @project - - if issuable.assignee_id - = hidden_field_tag("#{issuable.class.model_name.param_key}[assignee_id]", issuable.assignee_id) - = dropdown_tag(user_dropdown_label(issuable.assignee_id, "Assignee"), options: { toggle_class: "js-user-search js-issuable-form-dropdown js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit", - placeholder: "Search assignee", data: { first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (project.id if project), selected: issuable.assignee_id, field_name: "#{issuable.class.model_name.param_key}[assignee_id]", default_label: "Assignee" } }) + = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]", + placeholder: 'Select assignee', class: 'custom-form-control', null_user: true, + selected: issuable.assignee_id, project: @target_project || @project, + first_user: true, current_user: true, include_blank: true) + %div + = link_to 'Assign to me', '#', class: 'assign-to-me-link prepend-top-5 inline' .form-group.issue-milestone = f.label :milestone_id, "Milestone", class: "control-label #{"col-lg-4" if has_due_date}" .col-sm-10{ class: ("col-lg-8" if has_due_date) } - .issuable-form-select-holder - = render "shared/issuable/milestone_dropdown", selected: issuable.milestone_id, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false + - if milestone_options(issuable).present? + .issuable-form-select-holder + = f.select(:milestone_id, milestone_options(issuable), + { include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } }) + - else + .prepend-top-10 + %span.light No open milestones available. + - if can? current_user, :admin_milestone, issuable.project + %div + = link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline" .form-group - has_labels = issuable.project.labels.any? - - selected_labels = issuable.label_ids.any? ? issuable.label_ids : nil - - label_dropdown_toggle = issuable.labels.map { |label| label.title } = f.label :label_ids, "Labels", class: "control-label #{"col-lg-4" if has_due_date}" .col-sm-10{ class: "#{"col-lg-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" } - .issuable-form-select-holder - = render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: selected_labels, selected_toggle: label_dropdown_toggle, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: "false" } + - if has_labels + .issuable-form-select-holder + = f.collection_select :label_ids, issuable.project.labels.all, :id, :name, + { selected: issuable.label_ids }, multiple: true, class: 'select2', data: { placeholder: "Select labels" } + - else + %span.light No labels yet. + - if can? current_user, :admin_label, issuable.project + %div + = link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline" - if has_due_date .col-lg-6 .form-group diff --git a/app/views/shared/issuable/_label_dropdown.html.haml b/app/views/shared/issuable/_label_dropdown.html.haml index bcbe133ce62..d34d28f6736 100644 --- a/app/views/shared/issuable/_label_dropdown.html.haml +++ b/app/views/shared/issuable/_label_dropdown.html.haml @@ -4,21 +4,19 @@ - show_footer = local_assigns.fetch(:show_footer, true) - data_options = local_assigns.fetch(:data_options, {}) - classes = local_assigns.fetch(:classes, []) -- selected = local_assigns.fetch(:selected, nil) -- selected_toggle = local_assigns.fetch(:selected_toggle, nil) -- dropdown_data = {toggle: 'dropdown', field_name: "label_name[]", show_no: "true", show_any: "true", selected: selected, project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"} +- dropdown_data = {toggle: 'dropdown', field_name: 'label_name[]', show_no: "true", show_any: "true", selected: params[:label_name], project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"} - dropdown_data.merge!(data_options) - classes << 'js-extra-options' if extra_options - classes << 'js-filter-submit' if filter_submit -- if selected.present? - - if selected.respond_to?('any?') - - selected.each do |label| - = hidden_field_tag data_options[:field_name], label, id: nil +- if params[:label_name].present? + - if params[:label_name].respond_to?('any?') + - params[:label_name].each do |label| + = hidden_field_tag "label_name[]", label, id: nil .dropdown %button.dropdown-menu-toggle.js-label-select.js-multiselect{class: classes.join(' '), type: "button", data: dropdown_data} %span.dropdown-toggle-text - = h(multi_label_name(selected_toggle || selected, "Label")) + = h(multi_label_name(params[:label_name], "Label")) = icon('chevron-down') .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable = render partial: "shared/issuable/label_page_default", locals: { title: "Filter by label", show_footer: show_footer, show_create: show_create } diff --git a/app/views/shared/issuable/_milestone_dropdown.html.haml b/app/views/shared/issuable/_milestone_dropdown.html.haml index 9188ef72d52..2fcf40ece99 100644 --- a/app/views/shared/issuable/_milestone_dropdown.html.haml +++ b/app/views/shared/issuable/_milestone_dropdown.html.haml @@ -1,7 +1,7 @@ -- if selected.present? - = hidden_field_tag(name, selected) -= dropdown_tag(milestone_dropdown_label(selected), options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable", - placeholder: "Search milestones", footer_content: @project.present?, data: { show_no: true, show_any: show_any, show_upcoming: show_upcoming, field_name: name, selected: selected, project_id: @project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do +- if params[:milestone_title].present? + = hidden_field_tag(:milestone_title, params[:milestone_title]) += dropdown_tag(milestone_dropdown_label(params[:milestone_title]), options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable", + placeholder: "Search milestones", footer_content: @project.present?, data: { show_no: true, show_any: true, show_upcoming: true, field_name: "milestone_title", selected: params[:milestone_title], project_id: @project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do - if @project %ul.dropdown-footer-list - if can? current_user, :admin_milestone, @project diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature index 80670063ea0..358e622b736 100644 --- a/features/project/issues/issues.feature +++ b/features/project/issues/issues.feature @@ -37,7 +37,6 @@ Feature: Project Issues And I submit new issue "500 error on profile" Then I should see issue "500 error on profile" - @javascript Scenario: I submit new unassigned issue with labels Given project "Shop" has labels: "bug", "feature", "enhancement" And I click link "New Issue" diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb index 8f71dfdd899..6b56a77b832 100644 --- a/features/steps/project/forked_merge_requests.rb +++ b/features/steps/project/forked_merge_requests.rb @@ -135,17 +135,19 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps end step 'I click "Assign to" dropdown"' do - click_button 'Assignee' + first('.ajax-users-select').click end step 'I should see the target project ID in the input selector' do - expect(find('.js-assignee-search')["data-project-id"]).to eq "#{@project.id}" + expect(page).to have_selector("input[data-project-id=\"#{@project.id}\"]") end step 'I should see the users from the target project ID' do - expect(page).to have_content 'Unassigned' - expect(page).to have_content current_user.name - expect(page).to have_content @project.users.first.name + expect(page).to have_selector('.user-result', visible: true, count: 3) + users = page.all('.user-name') + expect(users[0].text).to eq 'Unassigned' + expect(users[1].text).to eq current_user.name + expect(users[2].text).to eq @project.users.first.name end # Verify a link is generated against the correct project diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb index b785e15f70e..35f166c7c08 100644 --- a/features/steps/project/issues/issues.rb +++ b/features/steps/project/issues/issues.rb @@ -82,8 +82,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps step 'I submit new issue "500 error on profile" with label \'bug\'' do fill_in "issue_title", with: "500 error on profile" - click_button "Label" - click_link "bug" + select 'bug', from: "Labels" click_button "Submit issue" end diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb index 055210399a7..7773c486b4e 100644 --- a/spec/features/issues/move_spec.rb +++ b/spec/features/issues/move_spec.rb @@ -55,7 +55,7 @@ feature 'issue move to another project' do first('.select2-choice').click end - fill_in('s2id_autogen1_search', with: new_project_search.name) + fill_in('s2id_autogen2_search', with: new_project_search.name) page.within '.select2-drop' do expect(page).to have_content(new_project_search.name) diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index d00cffa4e2b..d51c9abea19 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -50,8 +50,9 @@ describe 'Issues', feature: true do expect(page).to have_content "Assignee #{@user.name}" - first('.js-user-search').click - click_link 'Unassigned' + first('#s2id_issue_assignee_id').click + sleep 2 # wait for ajax stuff to complete + first('.user-result').click click_button 'Save changes' From 82959349dd97450a166d42547083f8dfd3d1491e Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 15 Jul 2016 20:22:35 -0500 Subject: [PATCH 311/335] Don't fail to highlight when Rouge doesn't have a lexer --- lib/banzai/filter/syntax_highlight_filter.rb | 15 ++++---- .../filter/syntax_highlight_filter_spec.rb | 34 +++++++++++++++---- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb index 028edef704b..91f0159f9a1 100644 --- a/lib/banzai/filter/syntax_highlight_filter.rb +++ b/lib/banzai/filter/syntax_highlight_filter.rb @@ -19,21 +19,22 @@ module Banzai language = node.attr('class') code = node.text - lexer = Rouge::Lexer.find_fancy(language) + css_classes = "code highlight" + + lexer = Rouge::Lexer.find_fancy(language) || Rouge::Lexers::PlainText formatter = Rouge::Formatters::HTML.new - css_classes = "code highlight js-syntax-highlight #{lexer.tag}" begin - highlighted = '' - highlighted << %(
    )
    -          highlighted << formatter.format(lexer.lex(code))
    -          highlighted << %(
    ) + code = formatter.format(lexer.lex(code)) + + css_classes << " js-syntax-highlight #{lexer.tag}" rescue # Gracefully handle syntax highlighter bugs/errors to ensure # users can still access an issue/comment/etc. - highlighted = "
    #{code}
    " end + highlighted = %(
    #{code}
    ) + # Extracted to a method to measure it replace_parent_pre_element(node, highlighted) end diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb index 48ebc81cf82..b1370bca833 100644 --- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb +++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb @@ -3,15 +3,35 @@ require 'spec_helper' describe Banzai::Filter::SyntaxHighlightFilter, lib: true do include FilterSpecHelper - it 'highlights valid code blocks' do - result = filter('
    def fun end')
    -    expect(result.to_html).to eq("
    def fun end
    ") + context "when no language is specified" do + it "highlights as plaintext" do + result = filter('
    def fun end
    ') + expect(result.to_html).to eq('
    def fun end
    ') + end end - it 'passes through invalid code blocks' do - allow_any_instance_of(Rouge::Formatter).to receive(:format).and_raise(StandardError) + context "when a valid language is specified" do + it "highlights as that language" do + result = filter('
    def fun end
    ') + expect(result.to_html).to eq('
    def fun end
    ') + end + end - result = filter('
    This is a test
    ') - expect(result.to_html).to eq('
    This is a test
    ') + context "when an invalid language is specified" do + it "highlights as plaintext" do + result = filter('
    This is a test
    ') + expect(result.to_html).to eq('
    This is a test
    ') + end + end + + context "when Rouge formatting fails" do + before do + allow_any_instance_of(Rouge::Formatter).to receive(:format).and_raise(StandardError) + end + + it "highlights as plaintext" do + result = filter('
    This is a test
    ') + expect(result.to_html).to eq('
    This is a test
    ') + end end end From e94d3834c7d32f6e8a1d3d4c32d8be8cb1d7810c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Fri, 15 Jul 2016 21:31:26 -0400 Subject: [PATCH 312/335] Fix a bug where the project's repository path was returned instead of the wiki path --- lib/api/internal.rb | 7 ++++++- spec/requests/api/internal_spec.rb | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/api/internal.rb b/lib/api/internal.rb index d5dfba5e0cc..959b700de78 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -63,7 +63,12 @@ module API if access_status.status # Return the repository full path so that gitlab-shell has it when # handling ssh commands - response[:repository_path] = project.repository.path_to_repo + response[:repository_path] = + if wiki? + project.wiki.repository.path_to_repo + else + project.repository.path_to_repo + end end response diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index e567d36afa8..f6f85d6e95e 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -56,13 +56,21 @@ describe API::API, api: true do context "git push with project.wiki" do it 'responds with success' do - project_wiki = create(:project, name: 'my.wiki', path: 'my.wiki') - project_wiki.team << [user, :developer] - - push(key, project_wiki) + push(key, project.wiki) expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy + expect(json_response["repository_path"]).to eq(project.wiki.repository.path_to_repo) + end + end + + context "git pull with project.wiki" do + it 'responds with success' do + pull(key, project.wiki) + + expect(response).to have_http_status(200) + expect(json_response["status"]).to be_truthy + expect(json_response["repository_path"]).to eq(project.wiki.repository.path_to_repo) end end From 72818f2c1573b7664d4b41692dc51db1e5c28fbb Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 15 Jul 2016 16:17:46 +0200 Subject: [PATCH 313/335] Fix creation of deployment on build that is retried, redeployed or rollback --- CHANGELOG | 1 + app/models/ci/build.rb | 1 + spec/services/create_deployment_service_spec.rb | 16 ++++++++++++++++ 3 files changed, 18 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 5518429e1b5..0ab37eea3c6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -60,6 +60,7 @@ v 8.10.0 (unreleased) - Allow expanding and collapsing files in diff view (!4990) - Collapse large diffs by default (!4990) - Fix mentioned users list on diff notes + - Fix creation of deployment on build that is retried, redeployed or rollback - Check for conflicts with existing Project's wiki path when creating a new project. - Show last push widget in upstream after push to fork - Cache todos pending/done dashboard query counts. diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index e189dbac285..b24527247e0 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -53,6 +53,7 @@ module Ci new_build.stage_idx = build.stage_idx new_build.trigger_request = build.trigger_request new_build.user = user + new_build.environment = build.environment new_build.save MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build) new_build diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb index 654e441f3cd..8da2a2b3c1b 100644 --- a/spec/services/create_deployment_service_spec.rb +++ b/spec/services/create_deployment_service_spec.rb @@ -89,6 +89,12 @@ describe CreateDeploymentService, services: true do expect_any_instance_of(described_class).to receive(:execute) subject end + + it 'is set as deployable' do + subject + + expect(Deployment.last.deployable).to eq(deployable) + end end context 'without environment specified' do @@ -105,6 +111,8 @@ describe CreateDeploymentService, services: true do context 'when build succeeds' do it_behaves_like 'does create environment and deployment' do + let(:deployable) { build } + subject { build.success } end end @@ -114,6 +122,14 @@ describe CreateDeploymentService, services: true do subject { build.drop } end end + + context 'when build is retried' do + it_behaves_like 'does create environment and deployment' do + let(:deployable) { Ci::Build.retry(build) } + + subject { deployable.success } + end + end end end end From 9912ad261f696ef92657171396774607af7f1893 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sat, 16 Jul 2016 20:10:22 +0200 Subject: [PATCH 314/335] Store when and yaml variables in builds table --- CHANGELOG | 1 + app/models/ci/build.rb | 34 +++--------- app/services/ci/create_builds_service.rb | 4 +- ...dd_when_and_yaml_variables_to_ci_builds.rb | 22 ++++++++ db/schema.rb | 4 +- lib/ci/gitlab_ci_yaml_processor.rb | 55 +++++++++++++------ spec/factories/ci/builds.rb | 5 ++ spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 21 +++---- spec/models/build_spec.rb | 18 +----- 9 files changed, 90 insertions(+), 74 deletions(-) create mode 100644 db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb diff --git a/CHANGELOG b/CHANGELOG index 040926d270d..32f33131de1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,7 @@ v 8.10.0 (unreleased) - Align flash messages with left side of page content !4959 (winniehell) - Display tooltip for "Copy to Clipboard" button !5164 (winniehell) - Use default cursor for table header of project files !5165 (winniehell) + - Store when and yaml variables in builds table - Display last commit of deleted branch in push events !4699 (winniehell) - Escape file extension when parsing search results !5141 (winniehell) - Apply the trusted_proxies config to the rack request object for use with rack_attack diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index e189dbac285..8c18f7ceb12 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -5,6 +5,7 @@ module Ci belongs_to :erased_by, class_name: 'User' serialize :options + serialize :yaml_variables validates :coverage, numericality: true, allow_blank: true validates_presence_of :ref @@ -52,6 +53,8 @@ module Ci new_build.stage = build.stage new_build.stage_idx = build.stage_idx new_build.trigger_request = build.trigger_request + new_build.yaml_variables = build.yaml_variables + new_build.when = build.when new_build.user = user new_build.save MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build) @@ -117,7 +120,12 @@ module Ci end def variables - predefined_variables + yaml_variables + project_variables + trigger_variables + variables = [] + variables += predefined_variables + variables += yaml_variables if yaml_variables + variables += project_variables + variables += trigger_variables + variables end def merge_request @@ -394,30 +402,6 @@ module Ci self.update(erased_by: user, erased_at: Time.now, artifacts_expire_at: nil) end - def yaml_variables - global_yaml_variables + job_yaml_variables - end - - def global_yaml_variables - if pipeline.config_processor - pipeline.config_processor.global_variables.map do |key, value| - { key: key, value: value, public: true } - end - else - [] - end - end - - def job_yaml_variables - if pipeline.config_processor - pipeline.config_processor.job_variables(name).map do |key, value| - { key: key, value: value, public: true } - end - else - [] - end - end - def project_variables project.variables.map do |variable| { key: variable.key, value: variable.value, public: false } diff --git a/app/services/ci/create_builds_service.rb b/app/services/ci/create_builds_service.rb index 2dcb052d274..3b21f0acb96 100644 --- a/app/services/ci/create_builds_service.rb +++ b/app/services/ci/create_builds_service.rb @@ -36,7 +36,9 @@ module Ci :allow_failure, :stage, :stage_idx, - :environment) + :environment, + :when, + :yaml_variables) build_attrs.merge!(pipeline: @pipeline, ref: @pipeline.ref, diff --git a/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb b/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb new file mode 100644 index 00000000000..816a32aa0d3 --- /dev/null +++ b/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb @@ -0,0 +1,22 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddWhenAndYamlVariablesCiBuilds < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # When using the methods "add_concurrent_index" or "add_column_with_default" + # you must disable the use of transactions as these methods can not run in an + # existing transaction. When using "add_concurrent_index" make sure that this + # method is the _only_ method called in the migration, any other changes + # should go in a separate migration. This ensures that upon failure _only_ the + # index creation fails and can be retried or reverted easily. + # + # To disable transactions uncomment the following line and remove these + # comments: + # disable_ddl_transaction! + + def change + add_column :ci_builds, :when, :string + add_column :ci_builds, :yaml_variables, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index f24e47b85b2..4a0df65aafb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160712171823) do +ActiveRecord::Schema.define(version: 20160716115710) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -168,6 +168,8 @@ ActiveRecord::Schema.define(version: 20160712171823) do t.datetime "artifacts_expire_at" t.string "environment" t.integer "artifacts_size" + t.string "when" + t.text "yaml_variables" end add_index "ci_builds", ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 01ef13df57a..a48dc542b14 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -31,10 +31,27 @@ module Ci raise ValidationError, e.message end + def jobs_for_ref(ref, tag = false, trigger_request = nil) + @jobs.select do |_, job| + process?(job[:only], job[:except], ref, tag, trigger_request) + end + end + + def jobs_for_stage_and_ref(stage, ref, tag = false, trigger_request = nil) + jobs_for_ref(ref, tag, trigger_request).select do |_, job| + job[:stage] == stage + end + end + + def builds_for_ref(ref, tag = false, trigger_request = nil) + jobs_for_ref(ref, tag, trigger_request).map do |name, job| + build_job(name, job) + end + end + def builds_for_stage_and_ref(stage, ref, tag = false, trigger_request = nil) - builds.select do |build| - build[:stage] == stage && - process?(build[:only], build[:except], ref, tag, trigger_request) + jobs_for_stage_and_ref(stage, ref, tag, trigger_request).map do |name, job| + build_job(name, job) end end @@ -44,17 +61,6 @@ module Ci end end - def global_variables - @variables - end - - def job_variables(name) - job = @jobs[name.to_sym] - return [] unless job - - job[:variables] || [] - end - private def initial_parsing @@ -95,11 +101,10 @@ module Ci commands: [job[:before_script] || @before_script, job[:script]].flatten.compact.join("\n"), tag_list: job[:tags] || [], name: name, - only: job[:only], - except: job[:except], allow_failure: job[:allow_failure] || false, when: job[:when] || 'on_success', environment: job[:environment], + yaml_variables: yaml_variables(name), options: { image: job[:image] || @image, services: job[:services] || @services, @@ -111,6 +116,24 @@ module Ci } end + def yaml_variables(name) + variables = global_variables.merge(job_variables(name)) + variables.map do |key, value| + { key: key, value: value, public: true } + end + end + + def global_variables + @variables || {} + end + + def job_variables(name) + job = @jobs[name.to_sym] + return {} unless job + + job[:variables] || {} + end + def validate! @jobs.each do |name, job| validate_job!(name, job) diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index fe05a0cfc00..5fb671df570 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -15,6 +15,11 @@ FactoryGirl.define do services: ["postgres"] } end + yaml_variables do + [ + { key: :DB_NAME, value: 'postgres', public: true } + ] + end pipeline factory: :ci_pipeline diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index bcbf409c8b0..6b2492b61b8 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -19,15 +19,14 @@ module Ci expect(config_processor.builds_for_stage_and_ref(type, "master").first).to eq({ stage: "test", stage_idx: 1, - except: nil, name: :rspec, - only: nil, commands: "pwd\nrspec", tag_list: [], options: {}, allow_failure: false, when: "on_success", environment: nil, + yaml_variables: {} }) end @@ -432,11 +431,9 @@ module Ci expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ - except: nil, stage: "test", stage_idx: 1, name: :rspec, - only: nil, commands: "pwd\nrspec", tag_list: [], options: { @@ -446,6 +443,7 @@ module Ci allow_failure: false, when: "on_success", environment: nil, + yaml_variables: {} }) end @@ -461,11 +459,9 @@ module Ci expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ - except: nil, stage: "test", stage_idx: 1, name: :rspec, - only: nil, commands: "pwd\nrspec", tag_list: [], options: { @@ -475,6 +471,7 @@ module Ci allow_failure: false, when: "on_success", environment: nil, + yaml_variables: [] }) end end @@ -681,11 +678,9 @@ module Ci expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ - except: nil, stage: "test", stage_idx: 1, name: :rspec, - only: nil, commands: "pwd\nrspec", tag_list: [], options: { @@ -701,6 +696,7 @@ module Ci when: "on_success", allow_failure: false, environment: nil, + yaml_variables: {} }) end @@ -819,17 +815,16 @@ module Ci it "doesn't create jobs that start with dot" do expect(subject.size).to eq(1) expect(subject.first).to eq({ - except: nil, stage: "test", stage_idx: 1, name: :normal_job, - only: nil, commands: "test", tag_list: [], options: {}, when: "on_success", allow_failure: false, environment: nil, + yaml_variables: {} }) end end @@ -865,30 +860,28 @@ module Ci it "is correctly supported for jobs" do expect(subject.size).to eq(2) expect(subject.first).to eq({ - except: nil, stage: "build", stage_idx: 0, name: :job1, - only: nil, commands: "execute-script-for-job", tag_list: [], options: {}, when: "on_success", allow_failure: false, environment: nil, + yaml_variables: {} }) expect(subject.second).to eq({ - except: nil, stage: "build", stage_idx: 0, name: :job2, - only: nil, commands: "execute-script-for-job", tag_list: [], options: {}, when: "on_success", allow_failure: false, environment: nil, + yaml_variables: {} }) end end diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb index e8171788872..481416319dd 100644 --- a/spec/models/build_spec.rb +++ b/spec/models/build_spec.rb @@ -208,7 +208,7 @@ describe Ci::Build, models: true do end before do - build.update_attributes(stage: 'stage') + build.update_attributes(stage: 'stage', yaml_variables: yaml_variables) end it { is_expected.to eq(predefined_variables + yaml_variables) } @@ -260,22 +260,6 @@ describe Ci::Build, models: true do it { is_expected.to eq(predefined_variables + predefined_trigger_variable + yaml_variables + secure_variables + trigger_variables) } end - - context 'when job variables are defined' do - ## - # Job-level variables are defined in gitlab_ci.yml fixture - # - context 'when job variables are unique' do - let(:build) { create(:ci_build, name: 'staging') } - - it 'includes job variables' do - expect(subject).to include( - { key: :KEY1, value: 'value1', public: true }, - { key: :KEY2, value: 'value2', public: true } - ) - end - end - end end end end From 50b54951e84b4cfed23f5b3d57e2c785f44cb031 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sat, 16 Jul 2016 20:53:24 +0200 Subject: [PATCH 315/335] Fix gitlab_ci_yaml_processor_spec.rb --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 6b2492b61b8..1efc1e8ebdd 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -881,7 +881,7 @@ module Ci when: "on_success", allow_failure: false, environment: nil, - yaml_variables: {} + yaml_variables: [] }) end end From 75857e94bd878395a6d649580dd08207ea4c41fa Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sat, 16 Jul 2016 20:54:07 +0200 Subject: [PATCH 316/335] Fix AddWhenAndYamlVariablesToCiBuilds migration --- .../20160716115710_add_when_and_yaml_variables_to_ci_builds.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb b/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb index 816a32aa0d3..800e88f789d 100644 --- a/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb +++ b/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb @@ -1,7 +1,7 @@ # See http://doc.gitlab.com/ce/development/migration_style_guide.html # for more information on how to write migrations for GitLab. -class AddWhenAndYamlVariablesCiBuilds < ActiveRecord::Migration +class AddWhenAndYamlVariablesToCiBuilds < ActiveRecord::Migration include Gitlab::Database::MigrationHelpers # When using the methods "add_concurrent_index" or "add_column_with_default" From 0793370c1aa595e9af3f89c80923b657037b0b4f Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sat, 16 Jul 2016 22:16:38 +0200 Subject: [PATCH 317/335] Fix gitlab_ci_yaml_processor_spec.rb --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 1efc1e8ebdd..974fbcc7195 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -26,7 +26,7 @@ module Ci allow_failure: false, when: "on_success", environment: nil, - yaml_variables: {} + yaml_variables: [] }) end @@ -443,7 +443,7 @@ module Ci allow_failure: false, when: "on_success", environment: nil, - yaml_variables: {} + yaml_variables: [] }) end @@ -696,7 +696,7 @@ module Ci when: "on_success", allow_failure: false, environment: nil, - yaml_variables: {} + yaml_variables: [] }) end @@ -824,7 +824,7 @@ module Ci when: "on_success", allow_failure: false, environment: nil, - yaml_variables: {} + yaml_variables: [] }) end end @@ -869,7 +869,7 @@ module Ci when: "on_success", allow_failure: false, environment: nil, - yaml_variables: {} + yaml_variables: [] }) expect(subject.second).to eq({ stage: "build", From aafd4349862d538e57eba65154c498bc4cc4d749 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sat, 16 Jul 2016 22:56:03 +0200 Subject: [PATCH 318/335] Remove irrelevant comments --- ...710_add_when_and_yaml_variables_to_ci_builds.rb | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb b/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb index 800e88f789d..3e084023a65 100644 --- a/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb +++ b/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb @@ -1,20 +1,6 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - class AddWhenAndYamlVariablesToCiBuilds < ActiveRecord::Migration include Gitlab::Database::MigrationHelpers - # When using the methods "add_concurrent_index" or "add_column_with_default" - # you must disable the use of transactions as these methods can not run in an - # existing transaction. When using "add_concurrent_index" make sure that this - # method is the _only_ method called in the migration, any other changes - # should go in a separate migration. This ensures that upon failure _only_ the - # index creation fails and can be retried or reverted easily. - # - # To disable transactions uncomment the following line and remove these - # comments: - # disable_ddl_transaction! - def change add_column :ci_builds, :when, :string add_column :ci_builds, :yaml_variables, :text From 1395edc06f0f06e4cfe8b37b49298c739b9eda2e Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Sat, 16 Jul 2016 17:47:05 -0500 Subject: [PATCH 319/335] Remove deploy to production button --- app/views/projects/ci/pipelines/_pipeline.html.haml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index b53a8633937..ebe4204788e 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -58,16 +58,7 @@ .controls.hidden-xs.pull-right - artifacts = pipeline.builds.latest.select { |b| b.artifacts? } - if artifacts.present? - .btn-group.inline - .btn-group - %a.dropdown-toggle.btn.btn-default{type: 'button', 'data-toggle' => 'dropdown'} - = icon("play") - %b.caret - %ul.dropdown-menu.dropdown-menu-align-right - %li - = link_to '#' do - = icon("play") - %span Deploy to production + .inline .btn-group %a.dropdown-toggle.btn.btn-default.build-artifacts{type: 'button', 'data-toggle' => 'dropdown'} = icon("download") From e72fe97e42c1a97bd6fd305a61e90dbb193c9f45 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Sat, 16 Jul 2016 17:51:39 -0500 Subject: [PATCH 320/335] Align cancel and retry buttons --- app/assets/stylesheets/pages/pipelines.scss | 2 ++ app/views/projects/ci/pipelines/_pipeline.html.haml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 08da4e290dc..a0334207c68 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -129,6 +129,8 @@ } .cancel-retry-btns { + vertical-align: middle; + .btn:not(:first-child) { margin-left: 8px; } diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index ebe4204788e..631873fb0a3 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -71,7 +71,7 @@ %span Download '#{build.name}' artifacts - if can?(current_user, :update_pipeline, @project) - .cancel-retry-btns + .cancel-retry-btns.inline - if pipeline.retryable? = link_to retry_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn has-tooltip', title: "Retry", method: :post do = icon("repeat") From 63e951797102b37ef99a5651e18c45dc24e7f75c Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Sun, 17 Jul 2016 11:10:18 +0300 Subject: [PATCH 321/335] Fix CI yaml example --- doc/ci/yaml/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 16a1461a7e4..50fa263f693 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -985,11 +985,11 @@ directive defined in `.postgres_services` and `.mysql_services` respectively: - ruby test:postgres: - << *job_definition + <<: *job_definition services: *postgres_definition test:mysql: - << *job_definition + <<: *job_definition services: *mysql_definition ``` From 22c2814b09960255d9ece0c620858500719858cb Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sun, 17 Jul 2016 13:03:57 +0200 Subject: [PATCH 322/335] Refactor gitlab_ci_yaml_processor variables tests --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 130 +++++++++++-------- 1 file changed, 77 insertions(+), 53 deletions(-) diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 974fbcc7195..ad6587b4c25 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -477,96 +477,120 @@ module Ci end describe 'Variables' do - context 'when global variables are defined' do - it 'returns global variables' do - variables = { - VAR1: 'value1', - VAR2: 'value2', - } + let(:config_processor) { GitlabCiYamlProcessor.new(YAML.dump(config), path) } - config = YAML.dump({ + subject { config_processor.builds.first[:yaml_variables] } + + context 'when global variables are defined' do + let(:variables) do + { VAR1: 'value1', VAR2: 'value2' } + end + let(:config) do + { variables: variables, before_script: ['pwd'], rspec: { script: 'rspec' } - }) + } + end - config_processor = GitlabCiYamlProcessor.new(config, path) + it 'returns global variables' do + expect(subject).to contain_exactly( + { key: :VAR1, value: 'value1', public: true }, + { key: :VAR2, value: 'value2', public: true } + ) + end + end - expect(config_processor.global_variables).to eq(variables) + context 'when job and global variables are defined' do + let(:global_variables) do + { VAR1: 'global1', VAR3: 'global3' } + end + let(:job_variables) do + { VAR1: 'value1', VAR2: 'value2' } + end + let(:config) do + { + before_script: ['pwd'], + variables: global_variables, + rspec: { script: 'rspec', variables: job_variables } + } + end + + it 'returns all unique variables' do + expect(subject).to contain_exactly( + { key: :VAR3, value: 'global3', public: true }, + { key: :VAR1, value: 'value1', public: true }, + { key: :VAR2, value: 'value2', public: true } + ) end end context 'when job variables are defined' do + let(:config) do + { + before_script: ['pwd'], + rspec: { script: 'rspec', variables: variables } + } + end + + context 'when also global variables are defined' do + + end + context 'when syntax is correct' do + let(:variables) do + { VAR1: 'value1', VAR2: 'value2' } + end + it 'returns job variables' do - variables = { - KEY1: 'value1', - SOME_KEY_2: 'value2' - } - - config = YAML.dump( - { before_script: ['pwd'], - rspec: { - variables: variables, - script: 'rspec' } - }) - - config_processor = GitlabCiYamlProcessor.new(config, path) - - expect(config_processor.job_variables(:rspec)).to eq variables + expect(subject).to contain_exactly( + { key: :VAR1, value: 'value1', public: true }, + { key: :VAR2, value: 'value2', public: true } + ) end end context 'when syntax is incorrect' do context 'when variables defined but invalid' do + let(:variables) do + [ :VAR1, 'value1', :VAR2, 'value2' ] + end + it 'raises error' do - variables = [:KEY1, 'value1', :KEY2, 'value2'] - - config = YAML.dump( - { before_script: ['pwd'], - rspec: { - variables: variables, - script: 'rspec' } - }) - - expect { GitlabCiYamlProcessor.new(config, path) } + expect { subject } .to raise_error(GitlabCiYamlProcessor::ValidationError, - /job: variables should be a map/) + /job: variables should be a map/) end end context 'when variables key defined but value not specified' do + let(:variables) do + nil + end + it 'returns empty array' do - config = YAML.dump( - { before_script: ['pwd'], - rspec: { - variables: nil, - script: 'rspec' } - }) - - config_processor = GitlabCiYamlProcessor.new(config, path) - ## # When variables config is empty, we assume this is a valid # configuration, see issue #18775 # - expect(config_processor.job_variables(:rspec)) - .to be_an_instance_of(Array).and be_empty + expect(subject).to be_an_instance_of(Array) + expect(subject).to be_empty end end end end context 'when job variables are not defined' do - it 'returns empty array' do - config = YAML.dump({ + let(:config) do + { before_script: ['pwd'], rspec: { script: 'rspec' } - }) + } + end - config_processor = GitlabCiYamlProcessor.new(config, path) - - expect(config_processor.job_variables(:rspec)).to eq [] + it 'returns empty array' do + expect(subject).to be_an_instance_of(Array) + expect(subject).to be_empty end end end From 565b3a183978a7952ef92d2e1e05b429f38322fa Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 17 Jul 2016 20:12:32 -0700 Subject: [PATCH 323/335] Allow a project import URL to be blank to prevent false positives preventing settings from being saved --- app/models/project.rb | 4 ++-- spec/models/project_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index e7b9835692d..8d71e01103c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -162,7 +162,7 @@ class Project < ActiveRecord::Base validates :namespace, presence: true validates_uniqueness_of :name, scope: :namespace_id validates_uniqueness_of :path, scope: :namespace_id - validates :import_url, addressable_url: true, if: :import_url + validates :import_url, addressable_url: true, if: "import_url.present?" validates :star_count, numericality: { greater_than_or_equal_to: 0 } validate :check_limit, on: :create validate :avatar_type, @@ -482,7 +482,7 @@ class Project < ActiveRecord::Base end def create_or_update_import_data(data: nil, credentials: nil) - return unless valid_import_url? + return unless import_url.present? && valid_import_url? project_import_data = import_data || build_import_data if data diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index e842c58dd82..9dc34276f18 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -142,10 +142,10 @@ describe Project, models: true do expect(project2).to be_valid end - it 'does not allow to introduce an empty URI' do + it 'allows an empty URI' do project2 = build(:project, import_url: '') - expect(project2).not_to be_valid + expect(project2).to be_valid end it 'does not produce import data on an empty URI' do From 328da189d21673b7f8937d122363ef0c710f9ae9 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 17 Jul 2016 20:57:11 -0700 Subject: [PATCH 324/335] Fix spec to set import_url before attempting to create import_data --- spec/lib/gitlab/bitbucket_import/client_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/gitlab/bitbucket_import/client_spec.rb b/spec/lib/gitlab/bitbucket_import/client_spec.rb index 760d66a1488..7543c29bcc4 100644 --- a/spec/lib/gitlab/bitbucket_import/client_spec.rb +++ b/spec/lib/gitlab/bitbucket_import/client_spec.rb @@ -54,12 +54,12 @@ describe Gitlab::BitbucketImport::Client, lib: true do context 'project import' do it 'calls .from_project with no errors' do project = create(:empty_project) + project.import_url = "ssh://git@bitbucket.org/test/test.git" project.create_or_update_import_data(credentials: { user: "git", password: nil, bb_session: { bitbucket_access_token: "test", bitbucket_access_token_secret: "test" } }) - project.import_url = "ssh://git@bitbucket.org/test/test.git" expect { described_class.from_project(project) }.not_to raise_error end From 7a72c75a9cfeb2793e68e55ef091c1c298f27832 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 18 Jul 2016 08:54:25 +0200 Subject: [PATCH 325/335] use method in validates statement --- app/models/project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index 8d71e01103c..d3ae4a2dd0b 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -162,7 +162,7 @@ class Project < ActiveRecord::Base validates :namespace, presence: true validates_uniqueness_of :name, scope: :namespace_id validates_uniqueness_of :path, scope: :namespace_id - validates :import_url, addressable_url: true, if: "import_url.present?" + validates :import_url, addressable_url: true, if: :external_import? validates :star_count, numericality: { greater_than_or_equal_to: 0 } validate :check_limit, on: :create validate :avatar_type, From 785043841873f120e8e26da706060500b4a333a6 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Fri, 15 Jul 2016 11:34:23 +0200 Subject: [PATCH 326/335] limit project expor retry to only 3 --- app/workers/project_export_worker.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/workers/project_export_worker.rb b/app/workers/project_export_worker.rb index 39f6037e077..615311e63f5 100644 --- a/app/workers/project_export_worker.rb +++ b/app/workers/project_export_worker.rb @@ -1,7 +1,7 @@ class ProjectExportWorker include Sidekiq::Worker - sidekiq_options queue: :gitlab_shell, retry: true + sidekiq_options queue: :gitlab_shell, retry: 3 def perform(current_user_id, project_id) current_user = User.find(current_user_id) From 5ede1331d45199ff1b79d98c70bddda86837de48 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Fri, 15 Jul 2016 11:44:38 +0200 Subject: [PATCH 327/335] added changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 5518429e1b5..8b70c6bf3df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -103,6 +103,7 @@ v 8.10.0 (unreleased) - Fix issues importing projects from EE to CE - Fix creating group with space in group path - Create Todos for Issue author when assign or mention himself (Katarzyna Kobierska) + - Limit the number of retries on error to 3 for exporting projects v 8.9.6 - Fix importing of events under notes for GitLab projects. !5154 From 5813aec22dac9a896e75a23781934d555aef4269 Mon Sep 17 00:00:00 2001 From: Katarzyna Kobierska Date: Tue, 5 Jul 2016 10:10:34 +0200 Subject: [PATCH 328/335] Add Pending Tab to Admin Builds Add Pending Tab to Project Builds Update CHANGELOG --- CHANGELOG | 5 +++++ app/controllers/admin/builds_controller.rb | 4 +++- app/controllers/projects/builds_controller.rb | 4 +++- app/views/admin/builds/index.html.haml | 7 ++++++- app/views/projects/builds/index.html.haml | 7 ++++++- 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 90f006d445d..6cfb51b5d62 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -133,6 +133,11 @@ v 8.9.5 - Fixed 'use shortcuts' button on docs. !4979 - Admin should be able to turn shared runners into specific ones. !4961 - Update RedCloth to 4.3.2 for CVE-2012-6684. !4929 (Takuya Noguchi) + - Add Pending tab for Builds + +v 8.9.4 (unreleased) + - Ensure references to private repos aren't shown to logged-out users +v 8.9.5 (unreleased) - Improve the request / withdraw access button. !4860 v 8.9.4 diff --git a/app/controllers/admin/builds_controller.rb b/app/controllers/admin/builds_controller.rb index 0db91eaaf2e..88f3c0e2fd4 100644 --- a/app/controllers/admin/builds_controller.rb +++ b/app/controllers/admin/builds_controller.rb @@ -5,8 +5,10 @@ class Admin::BuildsController < Admin::ApplicationController @builds = @all_builds.order('created_at DESC') @builds = case @scope + when 'pending' + @builds.pending.reverse_order when 'running' - @builds.running_or_pending.reverse_order + @builds.running.reverse_order when 'finished' @builds.finished else diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb index ef3051d7519..d7513d75f01 100644 --- a/app/controllers/projects/builds_controller.rb +++ b/app/controllers/projects/builds_controller.rb @@ -10,8 +10,10 @@ class Projects::BuildsController < Projects::ApplicationController @builds = @all_builds.order('created_at DESC') @builds = case @scope + when 'pending' + @builds.pending.reverse_order when 'running' - @builds.running_or_pending.reverse_order + @builds.running.reverse_order when 'finished' @builds.finished else diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml index 9ea3cca0ecb..0fcff566a70 100644 --- a/app/views/admin/builds/index.html.haml +++ b/app/views/admin/builds/index.html.haml @@ -10,10 +10,15 @@ All %span.badge.js-totalbuilds-count= @all_builds.count(:id) + %li{class: ('active' if @scope == 'pending')} + = link_to admin_builds_path(scope: :pending) do + Pending + %span.badge.js-running-count= number_with_delimiter(@all_builds.pending.count(:id)) + %li{class: ('active' if @scope == 'running')} = link_to admin_builds_path(scope: :running) do Running - %span.badge.js-running-count= number_with_delimiter(@all_builds.running_or_pending.count(:id)) + %span.badge.js-running-count= number_with_delimiter(@all_builds.running.count(:id)) %li{class: ('active' if @scope == 'finished')} = link_to admin_builds_path(scope: :finished) do diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml index 85c31dfd918..41f0462e4be 100644 --- a/app/views/projects/builds/index.html.haml +++ b/app/views/projects/builds/index.html.haml @@ -11,12 +11,17 @@ %span.badge.js-totalbuilds-count = number_with_delimiter(@all_builds.count(:id)) + %li{class: ('active' if @scope == 'pending')} + = link_to project_builds_path(@project, scope: :pending) do + Pending + %span.badge.js-running-count + = number_with_delimiter(@all_builds.pending.count(:id)) %li{class: ('active' if @scope == 'running')} = link_to project_builds_path(@project, scope: :running) do Running %span.badge.js-running-count - = number_with_delimiter(@all_builds.running_or_pending.count(:id)) + = number_with_delimiter(@all_builds.running.count(:id)) %li{class: ('active' if @scope == 'finished')} = link_to project_builds_path(@project, scope: :finished) do From a3d8f89d9fd8e49017850e8e2a2c2ddcd405c7e7 Mon Sep 17 00:00:00 2001 From: Katarzyna Kobierska Date: Tue, 5 Jul 2016 14:39:55 +0200 Subject: [PATCH 329/335] Add test for new pending tab and update tests for running tab --- spec/features/admin/admin_builds_spec.rb | 36 +++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/spec/features/admin/admin_builds_spec.rb b/spec/features/admin/admin_builds_spec.rb index a6198389f04..e177059d959 100644 --- a/spec/features/admin/admin_builds_spec.rb +++ b/spec/features/admin/admin_builds_spec.rb @@ -36,12 +36,45 @@ describe 'Admin Builds' do end end + context 'Pending tab' do + context 'when have pending builds' do + it 'shows pending builds' do + build1 = create(:ci_build, pipeline: pipeline, status: :pending) + build2 = create(:ci_build, pipeline: pipeline, status: :running) + build3 = create(:ci_build, pipeline: pipeline, status: :success) + build4 = create(:ci_build, pipeline: pipeline, status: :failed) + + visit admin_builds_path(scope: :pending) + + expect(page).to have_selector('.nav-links li.active', text: 'Pending') + expect(page.find('.build-link')).to have_content(build1.id) + expect(page.find('.build-link')).not_to have_content(build2.id) + expect(page.find('.build-link')).not_to have_content(build3.id) + expect(page.find('.build-link')).not_to have_content(build4.id) + expect(page).to have_link 'Cancel all' + end + end + + context 'when have no builds pending' do + it 'shows a message' do + create(:ci_build, pipeline: pipeline, status: :success) + + visit admin_builds_path(scope: :pending) + + expect(page).to have_selector('.nav-links li.active', text: 'Pending') + expect(page).to have_content 'No builds to show' + expect(page).not_to have_link 'Cancel all' + end + end + end + context 'Running tab' do context 'when have running builds' do it 'shows running builds' do - build1 = create(:ci_build, pipeline: pipeline, status: :pending) + build1 = create(:ci_build, pipeline: pipeline, status: :running) build2 = create(:ci_build, pipeline: pipeline, status: :success) build3 = create(:ci_build, pipeline: pipeline, status: :failed) + build4 = create(:ci_build, pipeline: pipeline, status: :pending) visit admin_builds_path(scope: :running) @@ -49,6 +82,7 @@ describe 'Admin Builds' do expect(page.find('.build-link')).to have_content(build1.id) expect(page.find('.build-link')).not_to have_content(build2.id) expect(page.find('.build-link')).not_to have_content(build3.id) + expect(page.find('.build-link')).not_to have_content(build4.id) expect(page).to have_link 'Cancel all' end end From 463f1cb52b0d57f0e388a0324a06f1a90bb9ea09 Mon Sep 17 00:00:00 2001 From: Katarzyna Kobierska Date: Mon, 11 Jul 2016 10:33:04 +0200 Subject: [PATCH 330/335] Remove unused .js-running-count class --- app/views/admin/builds/index.html.haml | 6 +++--- app/views/projects/builds/index.html.haml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml index 0fcff566a70..3d77634d8fa 100644 --- a/app/views/admin/builds/index.html.haml +++ b/app/views/admin/builds/index.html.haml @@ -13,17 +13,17 @@ %li{class: ('active' if @scope == 'pending')} = link_to admin_builds_path(scope: :pending) do Pending - %span.badge.js-running-count= number_with_delimiter(@all_builds.pending.count(:id)) + %span.badge= number_with_delimiter(@all_builds.pending.count(:id)) %li{class: ('active' if @scope == 'running')} = link_to admin_builds_path(scope: :running) do Running - %span.badge.js-running-count= number_with_delimiter(@all_builds.running.count(:id)) + %span.badge= number_with_delimiter(@all_builds.running.count(:id)) %li{class: ('active' if @scope == 'finished')} = link_to admin_builds_path(scope: :finished) do Finished - %span.badge.js-running-count= number_with_delimiter(@all_builds.finished.count(:id)) + %span.badge= number_with_delimiter(@all_builds.finished.count(:id)) .nav-controls - if @all_builds.running_or_pending.any? diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml index 41f0462e4be..2af625f69cd 100644 --- a/app/views/projects/builds/index.html.haml +++ b/app/views/projects/builds/index.html.haml @@ -14,19 +14,19 @@ %li{class: ('active' if @scope == 'pending')} = link_to project_builds_path(@project, scope: :pending) do Pending - %span.badge.js-running-count + %span.badge = number_with_delimiter(@all_builds.pending.count(:id)) %li{class: ('active' if @scope == 'running')} = link_to project_builds_path(@project, scope: :running) do Running - %span.badge.js-running-count + %span.badge = number_with_delimiter(@all_builds.running.count(:id)) %li{class: ('active' if @scope == 'finished')} = link_to project_builds_path(@project, scope: :finished) do Finished - %span.badge.js-running-count + %span.badge = number_with_delimiter(@all_builds.finished.count(:id)) .nav-controls From c220f9a03717ea2274a61f3365d37b5bac5c24e7 Mon Sep 17 00:00:00 2001 From: Katarzyna Kobierska Date: Tue, 12 Jul 2016 10:31:15 +0200 Subject: [PATCH 331/335] Add tests to project builds for pending tab Fix CHANGELOG Fix build spec for pending tab --- CHANGELOG | 6 +----- spec/features/builds_spec.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6cfb51b5d62..38aee5af6c5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -113,6 +113,7 @@ v 8.9.6 - Fix broken migration in MySQL. !5005 - Overwrite Host and X-Forwarded-Host headers in NGINX !5213 - Keeps issue number when importing from Gitlab.com + - Add Pending tab for Builds (Katarzyna Kobierska, Urszula Budziszewska) v 8.9.7 (unreleased) - Fix import_data wrongly saved as a result of an invalid import_url @@ -133,11 +134,6 @@ v 8.9.5 - Fixed 'use shortcuts' button on docs. !4979 - Admin should be able to turn shared runners into specific ones. !4961 - Update RedCloth to 4.3.2 for CVE-2012-6684. !4929 (Takuya Noguchi) - - Add Pending tab for Builds - -v 8.9.4 (unreleased) - - Ensure references to private repos aren't shown to logged-out users -v 8.9.5 (unreleased) - Improve the request / withdraw access button. !4860 v 8.9.4 diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb index 16832c297ac..38c11ca9c4c 100644 --- a/spec/features/builds_spec.rb +++ b/spec/features/builds_spec.rb @@ -13,6 +13,18 @@ describe "Builds" do end describe "GET /:project/builds" do + context "Pending scope" do + before do + visit namespace_project_builds_path(@project.namespace, @project, scope: :pending) + end + + it { expect(page).to have_link 'Cancel running' } + it { expect(page).to have_selector('.nav-links li.active', text: 'Pending') } + it { expect(page).to have_content @build.short_sha } + it { expect(page).to have_content @build.ref } + it { expect(page).to have_content @build.name } + end + context "Running scope" do before do @build.run! From c958305409dbec64852a88fb91ecd55da7bd79d3 Mon Sep 17 00:00:00 2001 From: Katarzyna Kobierska Date: Mon, 18 Jul 2016 10:57:22 +0200 Subject: [PATCH 332/335] Modify test for Build tabs --- spec/features/builds_spec.rb | 44 +++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb index 38c11ca9c4c..cab3dc1d167 100644 --- a/spec/features/builds_spec.rb +++ b/spec/features/builds_spec.rb @@ -18,11 +18,13 @@ describe "Builds" do visit namespace_project_builds_path(@project.namespace, @project, scope: :pending) end - it { expect(page).to have_link 'Cancel running' } - it { expect(page).to have_selector('.nav-links li.active', text: 'Pending') } - it { expect(page).to have_content @build.short_sha } - it { expect(page).to have_content @build.ref } - it { expect(page).to have_content @build.name } + it "shows Pending tab builds" do + expect(page).to have_link 'Cancel running' + expect(page).to have_selector('.nav-links li.active', text: 'Pending') + expect(page).to have_content @build.short_sha + expect(page).to have_content @build.ref + expect(page).to have_content @build.name + end end context "Running scope" do @@ -31,11 +33,13 @@ describe "Builds" do visit namespace_project_builds_path(@project.namespace, @project, scope: :running) end - it { expect(page).to have_selector('.nav-links li.active', text: 'Running') } - it { expect(page).to have_link 'Cancel running' } - it { expect(page).to have_content @build.short_sha } - it { expect(page).to have_content @build.ref } - it { expect(page).to have_content @build.name } + it "shows Running tab builds" do + expect(page).to have_selector('.nav-links li.active', text: 'Running') + expect(page).to have_link 'Cancel running' + expect(page).to have_content @build.short_sha + expect(page).to have_content @build.ref + expect(page).to have_content @build.name + end end context "Finished scope" do @@ -44,9 +48,11 @@ describe "Builds" do visit namespace_project_builds_path(@project.namespace, @project, scope: :finished) end - it { expect(page).to have_selector('.nav-links li.active', text: 'Finished') } - it { expect(page).to have_content 'No builds to show' } - it { expect(page).to have_link 'Cancel running' } + it "shows Finished tab builds" do + expect(page).to have_selector('.nav-links li.active', text: 'Finished') + expect(page).to have_content 'No builds to show' + expect(page).to have_link 'Cancel running' + end end context "All builds" do @@ -55,11 +61,13 @@ describe "Builds" do visit namespace_project_builds_path(@project.namespace, @project) end - it { expect(page).to have_selector('.nav-links li.active', text: 'All') } - it { expect(page).to have_content @build.short_sha } - it { expect(page).to have_content @build.ref } - it { expect(page).to have_content @build.name } - it { expect(page).not_to have_link 'Cancel running' } + it "shows All tab builds" do + expect(page).to have_selector('.nav-links li.active', text: 'All') + expect(page).to have_content @build.short_sha + expect(page).to have_content @build.ref + expect(page).to have_content @build.name + expect(page).not_to have_link 'Cancel running' + end end end From 60a2b3eff2b91ae8db6eac4df95059c5fcd3eb31 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 18 Jul 2016 11:02:07 +0200 Subject: [PATCH 333/335] allow empty repos on import/export --- lib/gitlab/import_export/importer.rb | 3 +-- lib/gitlab/import_export/repo_restorer.rb | 9 ++------- lib/gitlab/import_export/repo_saver.rb | 2 +- lib/gitlab/import_export/wiki_repo_saver.rb | 1 + 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/gitlab/import_export/importer.rb b/lib/gitlab/import_export/importer.rb index 8f66f48cbfe..6b69a653f12 100644 --- a/lib/gitlab/import_export/importer.rb +++ b/lib/gitlab/import_export/importer.rb @@ -44,8 +44,7 @@ module Gitlab def wiki_restorer Gitlab::ImportExport::RepoRestorer.new(path_to_bundle: wiki_repo_path, shared: @shared, - project: ProjectWiki.new(project_tree.restored_project), - wiki: true) + project: ProjectWiki.new(project_tree.restored_project)) end def uploads_restorer diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb index 546dae4d122..f84de652a57 100644 --- a/lib/gitlab/import_export/repo_restorer.rb +++ b/lib/gitlab/import_export/repo_restorer.rb @@ -3,15 +3,14 @@ module Gitlab class RepoRestorer include Gitlab::ImportExport::CommandLineUtil - def initialize(project:, shared:, path_to_bundle:, wiki: false) + def initialize(project:, shared:, path_to_bundle:) @project = project @path_to_bundle = path_to_bundle @shared = shared - @wiki = wiki end def restore - return wiki? unless File.exist?(@path_to_bundle) + return true unless File.exist?(@path_to_bundle) FileUtils.mkdir_p(path_to_repo) @@ -30,10 +29,6 @@ module Gitlab def path_to_repo @project.repository.path_to_repo end - - def wiki? - @wiki - end end end end diff --git a/lib/gitlab/import_export/repo_saver.rb b/lib/gitlab/import_export/repo_saver.rb index cce43fe994b..331e14021e6 100644 --- a/lib/gitlab/import_export/repo_saver.rb +++ b/lib/gitlab/import_export/repo_saver.rb @@ -11,7 +11,7 @@ module Gitlab end def save - return false if @project.empty_repo? + return true if @project.empty_repo? # it's ok to have no repo @full_path = File.join(@shared.export_path, ImportExport.project_bundle_filename) bundle_to_disk diff --git a/lib/gitlab/import_export/wiki_repo_saver.rb b/lib/gitlab/import_export/wiki_repo_saver.rb index 1eedae39f8a..6107420e4dd 100644 --- a/lib/gitlab/import_export/wiki_repo_saver.rb +++ b/lib/gitlab/import_export/wiki_repo_saver.rb @@ -4,6 +4,7 @@ module Gitlab def save @wiki = ProjectWiki.new(@project) return true unless wiki_repository_exists? # it's okay to have no Wiki + bundle_to_disk(File.join(@shared.export_path, project_filename)) end From c157305373593d49aaa2536f3220a6b475d74914 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 18 Jul 2016 11:07:42 +0200 Subject: [PATCH 334/335] added changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 94f212324f7..52e47ba9c95 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -111,6 +111,7 @@ v 8.10.0 (unreleased) - Fix creating group with space in group path - Create Todos for Issue author when assign or mention himself (Katarzyna Kobierska) - Limit the number of retries on error to 3 for exporting projects + - Allow empty repositories on project import/export v 8.9.6 - Fix importing of events under notes for GitLab projects. !5154 From a0260bb57777ae66353bbcd079405702cc6800d7 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 18 Jul 2016 14:01:57 +0200 Subject: [PATCH 335/335] Disable transaction when adding index for Ci::Pipeline --- db/migrate/20160715134306_add_index_for_pipeline_user_id.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb b/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb index e09caa0e6d7..7c991c6d998 100644 --- a/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb +++ b/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb @@ -1,6 +1,8 @@ class AddIndexForPipelineUserId < ActiveRecord::Migration include Gitlab::Database::MigrationHelpers + disable_ddl_transaction! + def change add_concurrent_index :ci_commits, :user_id end