From ea19bd6d9c26e3be5ba924504dc638569a034b98 Mon Sep 17 00:00:00 2001 From: Eirik Lygre Date: Sun, 17 Jan 2016 21:30:27 +0000 Subject: Add usage example for the Office 365 GetPersonaPhoto-service. --- doc/customization/libravatar.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/customization/libravatar.md b/doc/customization/libravatar.md index bd2c242afc2..c46ce2ee203 100644 --- a/doc/customization/libravatar.md +++ b/doc/customization/libravatar.md @@ -67,3 +67,16 @@ Run `sudo gitlab-ctl reconfigure` for changes to take effect. In order to use a different set other than `identicon`, replace `&d=identicon` portion of the URL with another supported set. For example, you can use `retro` set in which case the URL would look like: `plain_url: "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=retro"` + + +## Usage examples + +#### For Microsoft Office 365 + +If your users are Office 365-users, the "GetPersonaPhoto" service can be used. Note that this service requires login, so this use case is +most useful in a corporate installation, where all users have access to Office 365. + +```ruby +gitlab_rails['gravatar_plain_url'] = 'http://outlook.office365.com/owa/service.svc/s/GetPersonaPhoto?email=%{email}&size=HR120x120' +gitlab_rails['gravatar_ssl_url'] = 'https://outlook.office365.com/owa/service.svc/s/GetPersonaPhoto?email=%{email}&size=HR120x120' +``` -- cgit v1.2.1 From d7d644a42814e46915f8517f4fdbc8d10e52cfa5 Mon Sep 17 00:00:00 2001 From: Kelvin Date: Fri, 4 Mar 2016 12:58:05 +0300 Subject: Prepend letter v to GitLab Workhorse version numbers --- doc/update/patch_versions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md index a10e62877ba..9bb007d4f4e 100644 --- a/doc/update/patch_versions.md +++ b/doc/update/patch_versions.md @@ -47,7 +47,7 @@ sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION` -b v`ca ```bash cd /home/git/gitlab-workhorse sudo -u git -H git fetch -sudo -u git -H git checkout `cat /home/git/gitlab/GITLAB_WORKHORSE_VERSION` -b `cat /home/git/gitlab/GITLAB_WORKHORSE_VERSION` +sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_WORKHORSE_VERSION` -b v`cat /home/git/gitlab/GITLAB_WORKHORSE_VERSION` sudo -u git -H make ``` -- cgit v1.2.1 From de95ab6257fcb38f109d9d1aea03618ae9981738 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Sat, 16 Apr 2016 18:03:20 -0600 Subject: Enable the UrlFormat and UrlQuotes SCSS Linters. --- .scss-lint.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.scss-lint.yml b/.scss-lint.yml index 835a4a88c44..bddb48eb090 100644 --- a/.scss-lint.yml +++ b/.scss-lint.yml @@ -244,11 +244,11 @@ linters: # URLs should be valid and not contain protocols or domain names. UrlFormat: - enabled: false + enabled: true # URLs should always be enclosed within quotes. UrlQuotes: - enabled: false + enabled: true # Properties, like color and font, are easier to read and maintain # when defined using variables rather than literals. -- cgit v1.2.1 From a6ba8647f919cca5f37f663502186d8b6b7642ec Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 19 Apr 2016 16:00:45 -0400 Subject: Improve uniqueness of field names on the signup form Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/15075 --- app/controllers/registrations_controller.rb | 7 +++++++ app/views/devise/shared/_signup_box.html.haml | 4 ++-- spec/features/signup_spec.rb | 24 ++++++++++++------------ spec/features/users_spec.rb | 16 ++++++++-------- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index c48175a4c5a..b441b34d0be 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -8,6 +8,13 @@ class RegistrationsController < Devise::RegistrationsController def create if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha + # To avoid duplicate form fields on the login page, the registration form + # names fields using `new_user`, but Devise still wants the params in + # `user`. + if params["new_#{resource_name}"].present? && params[resource_name].blank? + params[resource_name] = params.delete(:"new_#{resource_name}") + end + super else flash[:alert] = "There was an error with the reCAPTCHA code below. Please re-enter the code." diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml index e5607dacd0d..510215bb8cd 100644 --- a/app/views/devise/shared/_signup_box.html.haml +++ b/app/views/devise/shared/_signup_box.html.haml @@ -6,7 +6,7 @@ .login-heading %h3 Create an account .login-body - = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| + = form_for(resource, as: "new_#{resource_name}", url: registration_path(resource_name)) do |f| .devise-errors = devise_error_messages! %div @@ -16,7 +16,7 @@ %div = f.email_field :email, class: "form-control middle", placeholder: "Email", required: true .form-group.append-bottom-20#password-strength - = f.password_field :password, class: "form-control bottom", id: "user_password_sign_up", placeholder: "Password", required: true + = f.password_field :password, class: "form-control bottom", placeholder: "Password", required: true %div - if current_application_settings.recaptcha_enabled = recaptcha_tags diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb index 01472743b2a..a9b81733897 100644 --- a/spec/features/signup_spec.rb +++ b/spec/features/signup_spec.rb @@ -7,10 +7,10 @@ feature 'Signup', feature: true do visit root_path - fill_in 'user_name', with: user.name - fill_in 'user_username', with: user.username - fill_in 'user_email', with: user.email - fill_in 'user_password_sign_up', with: user.password + fill_in 'new_user_name', with: user.name + fill_in 'new_user_username', with: user.username + fill_in 'new_user_email', with: user.email + fill_in 'new_user_password', with: user.password click_button "Sign up" expect(current_path).to eq user_session_path @@ -25,10 +25,10 @@ feature 'Signup', feature: true do visit root_path - fill_in 'user_name', with: user.name - fill_in 'user_username', with: user.username - fill_in 'user_email', with: existing_user.email - fill_in 'user_password_sign_up', with: user.password + fill_in 'new_user_name', with: user.name + fill_in 'new_user_username', with: user.username + fill_in 'new_user_email', with: existing_user.email + fill_in 'new_user_password', with: user.password click_button "Sign up" expect(current_path).to eq user_registration_path @@ -42,10 +42,10 @@ feature 'Signup', feature: true do visit root_path - fill_in 'user_name', with: user.name - fill_in 'user_username', with: user.username - fill_in 'user_email', with: existing_user.email - fill_in 'user_password_sign_up', with: user.password + fill_in 'new_user_name', with: user.name + fill_in 'new_user_username', with: user.username + fill_in 'new_user_email', with: existing_user.email + fill_in 'new_user_password', with: user.password click_button "Sign up" expect(current_path).to eq user_registration_path diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb index c1248162031..cf116040394 100644 --- a/spec/features/users_spec.rb +++ b/spec/features/users_spec.rb @@ -5,10 +5,10 @@ feature 'Users', feature: true do scenario 'GET /users/sign_in creates a new user account' do visit new_user_session_path - fill_in 'user_name', with: 'Name Surname' - fill_in 'user_username', with: 'Great' - fill_in 'user_email', with: 'name@mail.com' - fill_in 'user_password_sign_up', with: 'password1234' + fill_in 'new_user_name', with: 'Name Surname' + fill_in 'new_user_username', with: 'Great' + fill_in 'new_user_email', with: 'name@mail.com' + fill_in 'new_user_password', with: 'password1234' expect { click_button 'Sign up' }.to change { User.count }.by(1) end @@ -31,10 +31,10 @@ feature 'Users', feature: true do scenario 'Should show one error if email is already taken' do visit new_user_session_path - fill_in 'user_name', with: 'Another user name' - fill_in 'user_username', with: 'anotheruser' - fill_in 'user_email', with: user.email - fill_in 'user_password_sign_up', with: '12341234' + fill_in 'new_user_name', with: 'Another user name' + fill_in 'new_user_username', with: 'anotheruser' + fill_in 'new_user_email', with: user.email + fill_in 'new_user_password', with: '12341234' expect { click_button 'Sign up' }.to change { User.count }.by(0) expect(page).to have_text('Email has already been taken') expect(number_of_errors_on_page(page)).to be(1), 'errors on page:\n #{errors_on_page page}' -- cgit v1.2.1 From fdeeca3a15b4ef9ebcdc0fd386009b42a13626eb Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Fri, 22 Apr 2016 14:16:24 -0500 Subject: Reduce width of parallel diffs --- app/assets/stylesheets/pages/diff.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index e7c8198ba45..ed14b2cd1fe 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -98,7 +98,11 @@ } td.line_content.parallel { - width: 50%; + width: 46%; + } + + .add-diff-note { + margin-left: -65px; } } -- cgit v1.2.1 From 702380f1aed9d20cc48d24164e4910613ec18703 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 22 Apr 2016 16:13:59 -0400 Subject: Add letter_opener_web gem Sent emails in the development environment will no longer automatically be opened in the browser. If a sent email needs to be viewed, it can be found at the `/rails/letter_opener` route. --- Gemfile | 2 +- Gemfile.lock | 8 ++++++-- config/environments/development.rb | 2 +- config/routes.rb | 10 ++++++---- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index 67cc3f34b8c..05cf0219166 100644 --- a/Gemfile +++ b/Gemfile @@ -243,7 +243,7 @@ group :development do gem 'brakeman', '~> 3.2.0', require: false gem "annotate", "~> 2.7.0" - gem "letter_opener", '~> 1.1.2' + gem 'letter_opener_web', '~> 1.3.0' gem 'quiet_assets', '~> 1.0.2' gem 'rerun', '~> 0.11.0' gem 'bullet', require: false diff --git a/Gemfile.lock b/Gemfile.lock index b00d7b35c84..1ac0b20bbaf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -450,8 +450,12 @@ GEM kgio (2.10.0) launchy (2.4.3) addressable (~> 2.3) - letter_opener (1.1.2) + letter_opener (1.4.1) launchy (~> 2.2) + letter_opener_web (1.3.0) + actionmailer (>= 3.2) + letter_opener (~> 1.0) + railties (>= 3.2) licensee (8.0.0) rugged (>= 0.24b) listen (3.0.5) @@ -958,7 +962,7 @@ DEPENDENCIES jquery-turbolinks (~> 2.1.0) jquery-ui-rails (~> 5.0.0) kaminari (~> 0.16.3) - letter_opener (~> 1.1.2) + letter_opener_web (~> 1.3.0) licensee (~> 8.0.0) loofah (~> 2.0.3) mail_room (~> 0.6.1) diff --git a/config/environments/development.rb b/config/environments/development.rb index 689694a3480..4f39016bfa4 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -36,7 +36,7 @@ Rails.application.configure do # For having correct urls in mails config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } # Open sent mails in browser - config.action_mailer.delivery_method = :letter_opener + config.action_mailer.delivery_method = :letter_opener_web # Don't make a mess when bootstrapping a development environment config.action_mailer.perform_deliveries = (ENV['BOOTSTRAP'] != '1') diff --git a/config/routes.rb b/config/routes.rb index 2f820aafed1..d664434e1a6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,16 +16,18 @@ Rails.application.routes.draw do end end - # Make the built-in Rails routes available in development, otherwise they'd - # get swallowed by the `namespace/project` route matcher below. - # - # See https://git.io/va79N if Rails.env.development? + # Make the built-in Rails routes available in development, otherwise they'd + # get swallowed by the `namespace/project` route matcher below. + # + # See https://git.io/va79N get '/rails/mailers' => 'rails/mailers#index' get '/rails/mailers/:path' => 'rails/mailers#preview' get '/rails/info/properties' => 'rails/info#properties' get '/rails/info/routes' => 'rails/info#routes' get '/rails/info' => 'rails/info#index' + + mount LetterOpenerWeb::Engine, at: '/rails/letter_opener' end namespace :ci do -- cgit v1.2.1 From d3462e711c0b3cc17ef47e1ffffa6f40f98b5e98 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 22 Apr 2016 23:19:55 +0200 Subject: Fix issue with impersonation --- app/controllers/admin/application_controller.rb | 8 +- app/controllers/admin/impersonation_controller.rb | 38 --------- app/controllers/admin/impersonations_controller.rb | 28 +++++++ app/controllers/admin/users_controller.rb | 16 ++++ app/views/layouts/header/_default.html.haml | 2 +- config/routes.rb | 6 +- .../admin/impersonation_controller_spec.rb | 19 ----- .../admin/impersonations_controller_spec.rb | 95 ++++++++++++++++++++++ spec/controllers/admin/users_controller_spec.rb | 49 ++++++++++- 9 files changed, 192 insertions(+), 69 deletions(-) delete mode 100644 app/controllers/admin/impersonation_controller.rb create mode 100644 app/controllers/admin/impersonations_controller.rb delete mode 100644 spec/controllers/admin/impersonation_controller_spec.rb create mode 100644 spec/controllers/admin/impersonations_controller_spec.rb diff --git a/app/controllers/admin/application_controller.rb b/app/controllers/admin/application_controller.rb index 9083bfb41cf..cf795d977ce 100644 --- a/app/controllers/admin/application_controller.rb +++ b/app/controllers/admin/application_controller.rb @@ -6,12 +6,6 @@ class Admin::ApplicationController < ApplicationController layout 'admin' def authenticate_admin! - return render_404 unless current_user.is_admin? - end - - def authorize_impersonator! - if session[:impersonator_id] - User.find_by!(username: session[:impersonator_id]).admin? - end + render_404 unless current_user.is_admin? end end diff --git a/app/controllers/admin/impersonation_controller.rb b/app/controllers/admin/impersonation_controller.rb deleted file mode 100644 index bf98af78615..00000000000 --- a/app/controllers/admin/impersonation_controller.rb +++ /dev/null @@ -1,38 +0,0 @@ -class Admin::ImpersonationController < Admin::ApplicationController - skip_before_action :authenticate_admin!, only: :destroy - - before_action :user - before_action :authorize_impersonator! - - def create - if @user.blocked? - flash[:alert] = "You cannot impersonate a blocked user" - - redirect_to admin_user_path(@user) - else - session[:impersonator_id] = current_user.username - session[:impersonator_return_to] = admin_user_path(@user) - - warden.set_user(user, scope: 'user') - - flash[:alert] = "You are impersonating #{user.username}." - - redirect_to root_path - end - end - - def destroy - redirect = session[:impersonator_return_to] - - warden.set_user(user, scope: 'user') - - session[:impersonator_return_to] = nil - session[:impersonator_id] = nil - - redirect_to redirect || root_path - end - - def user - @user ||= User.find_by!(username: params[:id] || session[:impersonator_id]) - end -end diff --git a/app/controllers/admin/impersonations_controller.rb b/app/controllers/admin/impersonations_controller.rb new file mode 100644 index 00000000000..1ca3dd8228d --- /dev/null +++ b/app/controllers/admin/impersonations_controller.rb @@ -0,0 +1,28 @@ +class Admin::ImpersonationsController < Admin::ApplicationController + skip_before_action :authenticate_admin! + before_action :authenticate_impersonator! + + def destroy + redirect_path = admin_user_path(current_user) + + warden.set_user(impersonator, scope: :user) + + session[:impersonator_id] = nil + + redirect_to redirect_path + end + + private + + def user + @user ||= User.find(params[:id]) + end + + def impersonator + @impersonator ||= User.find(session[:impersonator_id]) if session[:impersonator_id] + end + + def authenticate_impersonator! + render_404 unless impersonator && impersonator.is_admin? && !impersonator.blocked? + end +end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 9abf08d0e19..b8976fa09a9 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -31,6 +31,22 @@ class Admin::UsersController < Admin::ApplicationController user end + def impersonate + if user.blocked? + flash[:alert] = "You cannot impersonate a blocked user" + + redirect_to admin_user_path(user) + else + session[:impersonator_id] = current_user.id + + warden.set_user(user, scope: :user) + + flash[:alert] = "You are now impersonating #{user.username}" + + redirect_to root_path + end + end + def block if user.block redirect_back_or_admin_user(notice: "Successfully blocked") diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 3beb8ff7c0d..cde9e1b918b 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -15,7 +15,7 @@ - if current_user - if session[:impersonator_id] %li.impersonation - = link_to stop_impersonation_admin_users_path, method: :delete, title: 'Stop Impersonation', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do + = link_to admin_impersonation_path, method: :delete, title: 'Stop Impersonation', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do = icon('user-secret fw') - if current_user.is_admin? %li diff --git a/config/routes.rb b/config/routes.rb index 2f820aafed1..9c6fb682fc9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -212,8 +212,6 @@ Rails.application.routes.draw do resources :keys, only: [:show, :destroy] resources :identities, except: [:show] - delete 'stop_impersonation' => 'impersonation#destroy', on: :collection - member do get :projects get :keys @@ -223,12 +221,14 @@ Rails.application.routes.draw do put :unblock put :unlock put :confirm - post 'impersonate' => 'impersonation#create' + post :impersonate patch :disable_two_factor delete 'remove/:email_id', action: 'remove_email', as: 'remove_email' end end + resource :impersonation, only: :destroy + resources :abuse_reports, only: [:index, :destroy] resources :spam_logs, only: [:index, :destroy] diff --git a/spec/controllers/admin/impersonation_controller_spec.rb b/spec/controllers/admin/impersonation_controller_spec.rb deleted file mode 100644 index d7a7ba1c5b6..00000000000 --- a/spec/controllers/admin/impersonation_controller_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'spec_helper' - -describe Admin::ImpersonationController do - let(:admin) { create(:admin) } - - before do - sign_in(admin) - end - - describe 'CREATE #impersonation when blocked' do - let(:blocked_user) { create(:user, state: :blocked) } - - it 'does not allow impersonation' do - post :create, id: blocked_user.username - - expect(flash[:alert]).to eq 'You cannot impersonate a blocked user' - end - end -end diff --git a/spec/controllers/admin/impersonations_controller_spec.rb b/spec/controllers/admin/impersonations_controller_spec.rb new file mode 100644 index 00000000000..8b48c6b6ea3 --- /dev/null +++ b/spec/controllers/admin/impersonations_controller_spec.rb @@ -0,0 +1,95 @@ +require 'spec_helper' + +describe Admin::ImpersonationsController do + let(:impersonator) { create(:admin) } + let(:user) { create(:user) } + + describe "DELETE destroy" do + context "when not signed in" do + it "redirects to the sign in page" do + delete :destroy + + expect(response).to redirect_to(new_user_session_path) + end + end + + context "when signed in" do + before do + sign_in(user) + end + + context "when not impersonating" do + it "responds with status 404" do + delete :destroy + + expect(response.status).to eq(404) + end + + it "doesn't sign us in" do + delete :destroy + + expect(warden.user).to eq(user) + end + end + + context "when impersonating" do + before do + session[:impersonator_id] = impersonator.id + end + + context "when the impersonator is not impersonator (anymore)" do + before do + impersonator.admin = false + impersonator.save + end + + it "responds with status 404" do + delete :destroy + + expect(response.status).to eq(404) + end + + it "doesn't sign us in as the impersonator" do + delete :destroy + + expect(warden.user).to eq(user) + end + end + + context "when the impersonator is admin" do + context "when the impersonator is blocked" do + before do + impersonator.block! + end + + it "responds with status 404" do + delete :destroy + + expect(response.status).to eq(404) + end + + it "doesn't sign us in as the impersonator" do + delete :destroy + + expect(warden.user).to eq(user) + end + end + + context "when the impersonator is not blocked" do + it "redirects to the impersonated user's page" do + delete :destroy + + expect(response).to redirect_to(admin_user_path(user)) + end + + it "signs us in as the impersonator" do + delete :destroy + + expect(warden.user).to eq(impersonator) + end + end + end + end + end + end +end diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index 9ef8ba1b097..ce2a62ae1fd 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -2,9 +2,10 @@ require 'spec_helper' describe Admin::UsersController do let(:user) { create(:user) } + let(:admin) { create(:admin) } before do - sign_in(create(:admin)) + sign_in(admin) end describe 'DELETE #user with projects' do @@ -112,4 +113,50 @@ describe Admin::UsersController do patch :disable_two_factor, id: user.to_param end end + + describe "POST impersonate" do + context "when the user is blocked" do + before do + user.block! + end + + it "shows a notice" do + post :impersonate, id: user.username + + expect(flash[:alert]).to eq("You cannot impersonate a blocked user") + end + + it "doesn't sign us in as the user" do + post :impersonate, id: user.username + + expect(warden.user).to eq(admin) + end + end + + context "when the user is not blocked" do + it "stores the impersonator in the session" do + post :impersonate, id: user.username + + expect(session[:impersonator_id]).to eq(admin.id) + end + + it "signs us in as the user" do + post :impersonate, id: user.username + + expect(warden.user).to eq(user) + end + + it "redirects to root" do + post :impersonate, id: user.username + + expect(response).to redirect_to(root_path) + end + + it "shows a notice" do + post :impersonate, id: user.username + + expect(flash[:alert]).to eq("You are now impersonating #{user.username}") + end + end + end end -- cgit v1.2.1 From b992e2520cc93b3161f6e7c46dde66f10fe13a12 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 22 Apr 2016 21:46:47 +0000 Subject: Fix typo --- spec/controllers/admin/impersonations_controller_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/controllers/admin/impersonations_controller_spec.rb b/spec/controllers/admin/impersonations_controller_spec.rb index 8b48c6b6ea3..eb82476b179 100644 --- a/spec/controllers/admin/impersonations_controller_spec.rb +++ b/spec/controllers/admin/impersonations_controller_spec.rb @@ -37,7 +37,7 @@ describe Admin::ImpersonationsController do session[:impersonator_id] = impersonator.id end - context "when the impersonator is not impersonator (anymore)" do + context "when the impersonator is not admin (anymore)" do before do impersonator.admin = false impersonator.save -- cgit v1.2.1 From 0ab98a8a407cb9764c9c28554c8f077906a9eb9b Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 22 Apr 2016 21:55:49 +0000 Subject: Remove unused method --- app/controllers/admin/impersonations_controller.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/controllers/admin/impersonations_controller.rb b/app/controllers/admin/impersonations_controller.rb index 1ca3dd8228d..2d64923c478 100644 --- a/app/controllers/admin/impersonations_controller.rb +++ b/app/controllers/admin/impersonations_controller.rb @@ -14,10 +14,6 @@ class Admin::ImpersonationsController < Admin::ApplicationController private - def user - @user ||= User.find(params[:id]) - end - def impersonator @impersonator ||= User.find(session[:impersonator_id]) if session[:impersonator_id] end -- cgit v1.2.1 From c6c985bc690c88f2819787824a50b22cc86cacf4 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 22 Apr 2016 21:58:09 +0000 Subject: Store original user in variable --- app/controllers/admin/impersonations_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin/impersonations_controller.rb b/app/controllers/admin/impersonations_controller.rb index 2d64923c478..2db824c87ef 100644 --- a/app/controllers/admin/impersonations_controller.rb +++ b/app/controllers/admin/impersonations_controller.rb @@ -3,13 +3,13 @@ class Admin::ImpersonationsController < Admin::ApplicationController before_action :authenticate_impersonator! def destroy - redirect_path = admin_user_path(current_user) + original_user = current_user warden.set_user(impersonator, scope: :user) session[:impersonator_id] = nil - redirect_to redirect_path + redirect_to admin_user_path(original_user) end private -- cgit v1.2.1 From 03ae2cdbff49d4f72d32529963a2173c7308da40 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 24 Apr 2016 20:07:59 -0700 Subject: Filter confidential issues from milestones API if user does not have access Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/15579 --- CHANGELOG | 2 ++ lib/api/milestones.rb | 10 ++++++++- spec/requests/api/milestones_spec.rb | 40 +++++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2d1c561fb82..4ce16b44493 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,8 @@ v 8.7.1 (unreleased) - Fix license detection to detect all license files, not only known licenses. !3878 - Use the `can?` helper instead of `current_user.can?`. !3882 - Prevent users from deleting Webhooks via API they do not own + - Use the `can?` helper instead of `current_user.can?` + - Filter confidential issues from milestones API if user does not have access v 8.7.0 - Gitlab::GitAccess and Gitlab::GitAccessWiki are now instrumented diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 84b4d4cdd6d..132043cf3f7 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -105,7 +105,15 @@ module API authorize! :read_milestone, user_project @milestone = user_project.milestones.find(params[:milestone_id]) - present paginate(@milestone.issues), with: Entities::Issue, current_user: current_user + + finder_params = { + project_id: user_project.id, + milestone_title: @milestone.title, + state: 'all' + } + + issues = IssuesFinder.new(current_user, finder_params).execute + present paginate(issues), with: Entities::Issue, current_user: current_user end end diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb index 344f0fe0b7f..cb9c3dde5ee 100644 --- a/spec/requests/api/milestones_spec.rb +++ b/spec/requests/api/milestones_spec.rb @@ -127,7 +127,7 @@ describe API::API, api: true do describe 'GET /projects/:id/milestones/:milestone_id/issues' do before do - milestone.issues << create(:issue) + milestone.issues << create(:issue, project: project) end it 'should return project issues for a particular milestone' do get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user) @@ -141,4 +141,42 @@ describe API::API, api: true do expect(response.status).to eq(401) end end + + describe 'confidential issues' do + it 'should return confidential issues to team members' do + public_project = create(:project, :public) + user = create(:user) + milestone = create(:milestone, project: public_project) + issue = create(:issue, project: public_project) + confidential_issue = create(:issue, confidential: true, project: public_project) + public_project.team << [user, :developer] + milestone.issues << issue + milestone.issues << confidential_issue + + get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", user) + + expect(response.status).to eq(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(2) + expect(json_response.map { |issue| issue['id'] }).to include(issue.id, confidential_issue.id) + end + + it 'should not return confidential issues to regular users' do + public_project = create(:project, :public) + normal_user = create(:user) + milestone = create(:milestone, project: public_project) + issue = create(:issue, project: public_project) + confidential_issue = create(:issue, confidential: true, project: public_project) + public_project.team << [user, :developer] + milestone.issues << issue + milestone.issues << confidential_issue + + get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", normal_user) + + expect(response.status).to eq(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(1) + expect(json_response.map { |issue| issue['id'] }).to include(issue.id) + end + end end -- cgit v1.2.1 From 5fc6a7dc14aa05748049eebd0a53d5e615cd1a9a Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 25 Apr 2016 13:51:17 +0200 Subject: Update using_docker_build.md, clarify the 'privileged' mode requirement [ci skip] --- doc/ci/docker/using_docker_build.md | 64 +++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md index 4b1788a9af0..bb2a6d1137d 100644 --- a/doc/ci/docker/using_docker_build.md +++ b/doc/ci/docker/using_docker_build.md @@ -8,7 +8,7 @@ This is one of new trends in Continuous Integration/Deployment to: 1. create application image, 1. run test against created image, -1. push image to remote registry, +1. push image to remote registry, 1. deploy server from pushed image It's also useful in case when your application already has the `Dockerfile` that can be used to create and test image: @@ -46,22 +46,22 @@ GitLab Runner then executes build scripts as `gitlab-runner` user. For more information how to install Docker on different systems checkout the [Supported installations](https://docs.docker.com/installation/). 3. Add `gitlab-runner` user to `docker` group: - + ```bash $ sudo usermod -aG docker gitlab-runner ``` 4. Verify that `gitlab-runner` has access to Docker: - + ```bash $ sudo -u gitlab-runner -H docker info ``` - + You can now verify that everything works by adding `docker info` to `.gitlab-ci.yml`: ```yaml before_script: - docker info - + build_image: script: - docker build -t my-docker-image . @@ -88,24 +88,56 @@ In order to do that follow the steps: --token RUNNER_TOKEN \ --executor docker \ --description "My Docker Runner" \ - --docker-image "gitlab/dind:latest" \ + --docker-image "docker:latest" \ --docker-privileged ``` - - The above command will register new Runner to use special [gitlab/dind](https://registry.hub.docker.com/u/gitlab/dind/) image which is provided by GitLab Inc. - The image at the start runs Docker daemon in [docker-in-docker](https://blog.docker.com/2013/09/docker-can-now-run-within-docker/) mode. + + The above command will register a new Runner to use special `docker:latest` image which is provided by Docker + creators. **Notice that it's using the `privileged` mode to start build and service containers.** If you want to use + [docker-in-docker](https://blog.docker.com/2013/09/docker-can-now-run-within-docker/) mode, you always have to use + `privileged = true` in your docker containers. + + The above command will create a `config.toml` entry similar to this: + + ``` + [[runners]] + url = "https://gitlab.com/ci" + token = TOKEN + executor = "docker" + [runners.docker] + tls_verify = false + image = "docker:latest" + privileged = true + disable_cache = false + volumes = ["/cache"] + [runners.cache] + Insecure = false + ``` + + If you want to use Shared Runners available on your GitLab CE/EE installation, to build docker images, then + make sure that your Shared Runners configuration have `privileged` mode set to `true`. 1. You can now use `docker` from build script: - + ```yaml + image: docker:latest + + services: + - docker:dind + before_script: - docker info - - build_image: + + build: + stage: build script: - - docker build -t my-docker-image . - - docker run my-docker-image /script/to/run/tests + - docker build -t my-docker-image . + - docker run my-docker-image /script/to/run/tests ``` -1. However, by enabling `--docker-privileged` you are effectively disables all security mechanisms of containers and exposing your host to privilege escalation which can lead to container breakout. -For more information, check out [Runtime privilege](https://docs.docker.com/reference/run/#runtime-privilege-linux-capabilities-and-lxc-configuration). \ No newline at end of file +1. However, by enabling `--docker-privileged` you are effectively disables all security mechanisms of containers and + exposing your host to privilege escalation which can lead to container breakout. + + For more information, check out [Runtime privilege](https://docs.docker.com/reference/run/#runtime-privilege-linux-capabilities-and-lxc-configuration). + +An example project using this approach can be found here: https://gitlab.com/gitlab-examples/docker. -- cgit v1.2.1 From 5542c9456c44816d45caba42b00389da0b1d1f26 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 25 Apr 2016 14:42:17 +0100 Subject: Updated project group sharing UI Closes #13991 --- app/assets/stylesheets/framework/selects.scss | 12 +++- app/assets/stylesheets/framework/variables.scss | 4 +- app/assets/stylesheets/pages/profile.scss | 17 +---- app/assets/stylesheets/pages/settings.scss | 14 ++++ app/views/doorkeeper/applications/index.html.haml | 4 +- app/views/profiles/keys/_key.html.haml | 2 +- app/views/profiles/keys/_key_table.html.haml | 2 +- app/views/projects/group_links/index.html.haml | 79 ++++++++++++----------- 8 files changed, 72 insertions(+), 62 deletions(-) create mode 100644 app/assets/stylesheets/pages/settings.scss diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss index eae5f062dda..6efc6ec1e4b 100644 --- a/app/assets/stylesheets/framework/selects.scss +++ b/app/assets/stylesheets/framework/selects.scss @@ -7,13 +7,11 @@ .select2-choice { background: #fff; border-color: $input-border; - border-color: $border-white-light; height: 35px; padding: $gl-vert-padding $gl-btn-padding; font-size: $gl-font-size; line-height: 1.42857143; - - @include border-radius($border-radius-default); + border-radius: $border-radius-base; .select2-arrow { background-image: none; @@ -199,6 +197,14 @@ } } +.select2-highlighted { + .group-result { + .group-path { + color: #fff; + } + } +} + .group-result { .group-image { float: left; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 30ca27ab104..300f941bda6 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -71,8 +71,8 @@ $gl-avatar-size: 40px; $error-exclamation-point: #e62958; $border-radius-default: 2px; $btn-transparent-color: #8f8f8f; -$ssh-key-icon-color: #8f8f8f; -$ssh-key-icon-size: 18px; +$settings-icon-color: #8f8f8f; +$settings-icon-size: 18px; $provider-btn-group-border: #e5e5e5; $provider-btn-not-active-color: #4688f1; diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index a9656e5cae7..01f98479623 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -18,7 +18,8 @@ } .account-btn-link, -.profile-settings-sidebar a { +.profile-settings-sidebar a, +.settings-sidebar a { color: $md-link-color; } @@ -123,12 +124,6 @@ } } -.key-icon { - color: $ssh-key-icon-color; - font-size: $ssh-key-icon-size; - line-height: 42px; -} - .key-created-at { line-height: 42px; } @@ -180,14 +175,6 @@ } } -.profile-settings-message { - line-height: 32px; - color: $warning-message-color; - background-color: $warning-message-bg; - border: 1px solid $warning-message-border; - border-radius: $border-radius-base; -} - .oauth-applications { form { display: inline-block; diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss new file mode 100644 index 00000000000..67dbeca7bbd --- /dev/null +++ b/app/assets/stylesheets/pages/settings.scss @@ -0,0 +1,14 @@ +.settings-list-icon { + color: $settings-icon-color; + font-size: $settings-icon-size; + line-height: 42px; +} + +.settings-message { + padding: 5px; + line-height: 1.3; + color: $warning-message-color; + background-color: $warning-message-bg; + border: 1px solid $warning-message-border; + border-radius: $border-radius-base; +} diff --git a/app/views/doorkeeper/applications/index.html.haml b/app/views/doorkeeper/applications/index.html.haml index 79df17ba612..3998e66f40d 100644 --- a/app/views/doorkeeper/applications/index.html.haml +++ b/app/views/doorkeeper/applications/index.html.haml @@ -44,7 +44,7 @@ = icon('pencil') = render 'delete_form', application: application, small: true - else - .profile-settings-message.text-center + .settings-message.text-center You don't have any applications .oauth-authorized-applications.prepend-top-20.append-bottom-default - if user_oauth_applications? @@ -78,5 +78,5 @@ %td= token.scopes %td= render 'doorkeeper/authorized_applications/delete_form', token: token - else - .profile-settings-message.text-center + .settings-message.text-center You don't have any authorized applications diff --git a/app/views/profiles/keys/_key.html.haml b/app/views/profiles/keys/_key.html.haml index 4dbaa662b66..3276db6692c 100644 --- a/app/views/profiles/keys/_key.html.haml +++ b/app/views/profiles/keys/_key.html.haml @@ -1,6 +1,6 @@ %li.key-list-item .pull-left.append-right-10 - = icon 'key', class: "key-icon hidden-xs" + = icon 'key', class: "settings-list-icon hidden-xs" .key-list-item-info = link_to path_to_key(key, is_admin), class: "title" do = key.title diff --git a/app/views/profiles/keys/_key_table.html.haml b/app/views/profiles/keys/_key_table.html.haml index 296cafa6e31..e78763bdcb2 100644 --- a/app/views/profiles/keys/_key_table.html.haml +++ b/app/views/profiles/keys/_key_table.html.haml @@ -4,7 +4,7 @@ %ul.well-list = render partial: 'profiles/keys/key', collection: @keys, locals: { is_admin: is_admin } - else - %p.profile-settings-message.text-center + %p.settings-message.text-center - if is_admin There are no SSH keys associated with this account. - else diff --git a/app/views/projects/group_links/index.html.haml b/app/views/projects/group_links/index.html.haml index 13f5fc141fa..627419c1b18 100644 --- a/app/views/projects/group_links/index.html.haml +++ b/app/views/projects/group_links/index.html.haml @@ -1,41 +1,44 @@ - page_title "Groups" -%h3.page_title Share project with other groups -%p.light - Projects can be stored in only one group at once. However you can share a project with other groups here. -%hr -- if @group_links.present? - .enabled-groups.panel.panel-default - .panel-heading - Already shared with - %ul.well-list - - @group_links.each do |group_link| - - group = group_link.group - %li - .pull-right - = link_to namespace_project_group_link_path(@project.namespace, @project, group_link), method: :delete, class: 'btn btn-sm' do - %i.icon-remove - disable sharing - = link_to group do - %strong - %i.icon-folder-open - = group.name - %br - .light up to #{group_link.human_access} - - -.available-groups - %h4 - Can be shared with - %div - = form_tag namespace_project_group_links_path(@project.namespace, @project), method: :post, class: 'form-horizontal' do +.row.prepend-top-default + .col-lg-3.settings-sidebar + %h4.prepend-top-0 + Share project with other groups + %p + Projects can be stored in only one group at once. However you can share a project with other groups here. + .col-lg-9 + %h5.prepend-top-0 + Set a group to share + = form_tag namespace_project_group_links_path(@project.namespace, @project), method: :post do .form-group - = label_tag :link_group_id, 'Group', class: 'control-label' - .col-sm-10 - = groups_select_tag(:link_group_id, skip_group: @project.group.try(:path)) + = label_tag :link_group_id, "Group", class: "label-light" + = groups_select_tag(:link_group_id, skip_group: @project.group.try(:path)) .form-group - = label_tag :link_group_access, 'Max access level', class: 'control-label' - .col-sm-10 - = select_tag :link_group_access, options_for_select(ProjectGroupLink.access_options, ProjectGroupLink.default_access), class: "form-control" - .form-actions - = submit_tag "Share", class: "btn btn-create" - + = label_tag :link_group_access, "Max access level", class: "label-light" + = select_tag :link_group_access, options_for_select(ProjectGroupLink.access_options, ProjectGroupLink.default_access), class: "form-control" + = submit_tag "Share", class: "btn btn-create" + .col-sm-12 + %hr + .col-lg-3.settings-sidebar + %h4.prepend-top-0 + .col-lg-9.append-bottom-default + %h5.prepend-top-0 + Groups you share with (#{@group_links.size}) + - if @group_links.present? + %ul.well-list + - @group_links.each do |group_link| + - group = group_link.group + %li + .pull-left.append-right-10.hidden-xs + = icon("folder-open-o", class: "settings-list-icon") + .pull-left + = link_to group do + = group.name + %br + up to #{group_link.human_access} + .pull-right + = link_to namespace_project_group_link_path(@project.namespace, @project, group_link), method: :delete, class: "btn btn-transparent" do + %span.sr-only disable sharing + = icon("trash") + - else + .settings-message.text-center + There are no groups with access to your project, add one in the form above -- cgit v1.2.1 From 172947f3660ee695e5126a8319fb82cbca1fa360 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 25 Apr 2016 14:55:03 +0100 Subject: Updated select box to match design --- app/assets/stylesheets/framework/forms.scss | 18 ++++++++++++++++++ app/views/projects/group_links/index.html.haml | 4 +++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss index 54cb5461113..558b133f593 100644 --- a/app/assets/stylesheets/framework/forms.scss +++ b/app/assets/stylesheets/framework/forms.scss @@ -78,6 +78,24 @@ label { border-radius: 3px; } +.select-wrapper { + position: relative; + + .caret { + position: absolute; + right: 10px; + top: $gl-padding; + color: $gray-darkest; + pointer-events: none; + } +} + +.select-control { + padding-left: 10px; + padding-right: 10px; + -webkit-appearance: none; +} + .form-control-inline { display: inline; } diff --git a/app/views/projects/group_links/index.html.haml b/app/views/projects/group_links/index.html.haml index 627419c1b18..13cdac2102f 100644 --- a/app/views/projects/group_links/index.html.haml +++ b/app/views/projects/group_links/index.html.haml @@ -14,7 +14,9 @@ = groups_select_tag(:link_group_id, skip_group: @project.group.try(:path)) .form-group = label_tag :link_group_access, "Max access level", class: "label-light" - = select_tag :link_group_access, options_for_select(ProjectGroupLink.access_options, ProjectGroupLink.default_access), class: "form-control" + .select-wrapper + = select_tag :link_group_access, options_for_select(ProjectGroupLink.access_options, ProjectGroupLink.default_access), class: "form-control select-control" + %span.caret = submit_tag "Share", class: "btn btn-create" .col-sm-12 %hr -- cgit v1.2.1 From 756185533cfef42f85f5ad5cf687768e9ed82bb5 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 25 Apr 2016 16:26:41 +0100 Subject: Project deploy keys updated UI Closes #13992 --- app/assets/stylesheets/pages/projects.scss | 27 +++++++- app/controllers/projects/deploy_keys_controller.rb | 31 +++++---- .../projects/deploy_keys/_deploy_key.html.haml | 45 ++++++------- app/views/projects/deploy_keys/_form.html.haml | 31 ++++----- app/views/projects/deploy_keys/index.html.haml | 73 ++++++++++------------ 5 files changed, 110 insertions(+), 97 deletions(-) diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index fcca9d4faf5..9561ac39050 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -202,8 +202,31 @@ min-width: 200px; } -.deploy-project-label { - margin: 1px; +.deploy-key-content { + @media (min-width: $screen-sm-min) { + float: left; + + &:last-child { + float: right; + } + } +} + +.deploy-key-projects { + @media (min-width: $screen-sm-min) { + line-height: 42px; + } +} + +a.deploy-project-label { + padding: 5px; + margin-right: 5px; + color: $gl-gray; + background-color: $row-hover; + + &:hover { + color: $gl-link-color; + } } .vs-public { diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb index 7d09288bc80..83d5ced9be8 100644 --- a/app/controllers/projects/deploy_keys_controller.rb +++ b/app/controllers/projects/deploy_keys_controller.rb @@ -7,31 +7,24 @@ class Projects::DeployKeysController < Projects::ApplicationController layout "project_settings" def index - @enabled_keys = @project.deploy_keys - - @available_keys = accessible_keys - @enabled_keys - @available_project_keys = current_user.project_deploy_keys - @enabled_keys - @available_public_keys = DeployKey.are_public - @enabled_keys - - # Public keys that are already used by another accessible project are already - # in @available_project_keys. - @available_public_keys -= @available_project_keys + @key = DeployKey.new + set_index_vars end def new - @key = @project.deploy_keys.new - - respond_with(@key) + redirect_to namespace_project_deploy_keys_path(@project.namespace, + @project) end def create @key = DeployKey.new(deploy_key_params) + set_index_vars if @key.valid? && @project.deploy_keys << @key redirect_to namespace_project_deploy_keys_path(@project.namespace, @project) else - render "new" + render "index" end end @@ -51,6 +44,18 @@ class Projects::DeployKeysController < Projects::ApplicationController protected + def set_index_vars + @enabled_keys ||= @project.deploy_keys + + @available_keys ||= accessible_keys - @enabled_keys + @available_project_keys ||= current_user.project_deploy_keys - @enabled_keys + @available_public_keys ||= DeployKey.are_public - @enabled_keys + + # Public keys that are already used by another accessible project are already + # in @available_project_keys. + @available_public_keys -= @available_project_keys + end + def accessible_keys @accessible_keys ||= current_user.accessible_deploy_keys end diff --git a/app/views/projects/deploy_keys/_deploy_key.html.haml b/app/views/projects/deploy_keys/_deploy_key.html.haml index 8d66bae8cdf..450aaeb367c 100644 --- a/app/views/projects/deploy_keys/_deploy_key.html.haml +++ b/app/views/projects/deploy_keys/_deploy_key.html.haml @@ -1,32 +1,27 @@ %li - .pull-right + .pull-left.append-right-10.hidden-xs + = icon "key", class: "key-icon" + .deploy-key-content.key-list-item-info + %strong.title + = deploy_key.title + .description + = deploy_key.fingerprint + .deploy-key-content.prepend-left-default.deploy-key-projects + - deploy_key.projects.each do |project| + - if can?(current_user, :read_project, project) + = link_to namespace_project_path(project.namespace, project), class: "label deploy-project-label" do + = project.name_with_namespace + .deploy-key-content + %span.key-created-at + created #{time_ago_with_tooltip(deploy_key.created_at)} + .visible-xs-block.visible-sm-block - if @available_keys.include?(deploy_key) - = link_to enable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-sm', method: :put do - = icon('plus') + = link_to enable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: "btn btn-sm prepend-left-10", method: :put do Enable - else - if deploy_key.destroyed_when_orphaned? && deploy_key.almost_orphaned? - = link_to 'Remove', disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), data: { confirm: 'You are going to remove deploy key. Are you sure?'}, method: :put, class: "btn btn-remove delete-key btn-sm pull-right" + = link_to disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), data: { confirm: "You are going to remove deploy key. Are you sure?" }, method: :put, class: "btn btn-warning btn-sm prepend-left-10" do + Remove - else - = link_to disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-sm', method: :put do - = icon('power-off') + = link_to disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: "btn btn-warning btn-sm prepend-left-10", method: :put do Disable - - = icon('key') - %strong= deploy_key.title - %br - %code.key-fingerprint= deploy_key.fingerprint - - %p.light.prepend-top-10 - - if deploy_key.public? - %span.label.label-info.deploy-project-label - Public deploy key - - - deploy_key.projects.each do |project| - - if can?(current_user, :read_project, project) - %span.label.label-gray.deploy-project-label - = link_to namespace_project_path(project.namespace, project) do - = project.name_with_namespace - - %small.pull-right - Created #{time_ago_with_tooltip(deploy_key.created_at)} diff --git a/app/views/projects/deploy_keys/_form.html.haml b/app/views/projects/deploy_keys/_form.html.haml index f6565f85836..894c36a96df 100644 --- a/app/views/projects/deploy_keys/_form.html.haml +++ b/app/views/projects/deploy_keys/_form.html.haml @@ -1,18 +1,13 @@ -%div - = form_for [@project.namespace.becomes(Namespace), @project, @key], url: namespace_project_deploy_keys_path, html: { class: 'deploy-key-form form-horizontal js-requires-input' } do |f| - = form_errors(@key) - - .form-group - = f.label :title, class: "control-label" - .col-sm-10= f.text_field :title, class: 'form-control', autofocus: true, required: true - .form-group - = f.label :key, class: "control-label" - .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") - = f.text_area :key, class: "form-control thin_area", rows: 5, required: true - - .form-actions - = f.submit 'Create Deploy Key', class: "btn-create btn" - = link_to "Cancel", namespace_project_deploy_keys_path(@project.namespace, @project), class: "btn btn-cancel" += form_for [@project.namespace.becomes(Namespace), @project, @key], url: namespace_project_deploy_keys_path, html: { class: "js-requires-input" } do |f| + = form_errors(@key) + .form-group + = f.label :title, class: "label-light" + = f.text_field :title, class: 'form-control', autofocus: true, required: true + .form-group + = f.label :key, class: "label-light" + = f.text_area :key, class: "form-control", rows: 5, required: true + .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") + = f.submit "Add key", class: "btn-create btn" diff --git a/app/views/projects/deploy_keys/index.html.haml b/app/views/projects/deploy_keys/index.html.haml index 8e24c778b7c..d82ef31ab4b 100644 --- a/app/views/projects/deploy_keys/index.html.haml +++ b/app/views/projects/deploy_keys/index.html.haml @@ -1,43 +1,38 @@ - page_title "Deploy Keys" -%h3.page-title - Deploy keys allow read-only access to the repository - - = link_to new_namespace_project_deploy_key_path(@project.namespace, @project), class: "btn btn-new pull-right", title: "New Deploy Key" do - %i.fa.fa-plus - New Deploy Key - -%p.light - Deploy keys can be used for CI, staging or production servers. - You can create a deploy key or add an existing one - -%hr.clearfix - -.row - .col-md-6.enabled-keys - %h5 - %strong.cgreen Enabled deploy keys - for this project - %ul.bordered-list - = render @enabled_keys - - if @enabled_keys.blank? - .light-well - .nothing-here-block Create a #{link_to 'new deploy key', new_namespace_project_deploy_key_path(@project.namespace, @project)} or add an existing one - .col-md-6.available-keys - - # If there are available public deploy keys but no available project deploy keys, only public deploy keys are shown. - - if @available_project_keys.any? || @available_public_keys.blank? - %h5 - %strong Deploy keys - from projects you have access to - %ul.bordered-list +.row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + = page_title + %p + Deploy keys allow read-only access to your repository. Deploy keys can be used for CI, staging or production servers. You can create a deploy key or add an existing one. + .col-lg-9 + %h5.prepend-top-0 + Create a new deploy key for this project + = render "form" + .col-lg-9.col-lg-offset-3 + %hr + .col-lg-9.col-lg-offset-3.append-bottom-default + %h5.prepend-top-0 + Enabled deploy keys for this project (#{@enabled_keys.size}) + - if @enabled_keys.any? + %ul.well-list + = render @enabled_keys + - else + .profile-settings-message.text-center + No deploy keys found. Create one with the form above or add existing one below. + .col-lg-9.col-lg-offset-3.append-bottom-default + %h5.prepend-top-0 + Deploy keys from projects you have access to (#{@available_project_keys.size}) + - if @available_project_keys.any? + %ul.well-list = render @available_project_keys - - if @available_project_keys.blank? - .light-well - .nothing-here-block Deploy keys from projects you have access to will be displayed here - - - if @available_public_keys.any? - %h5 - %strong Public deploy keys - available to any project - %ul.bordered-list + - else + .profile-settings-message.text-center + No deploy keys from your projects could be found. Create one with the form above or add existing one below. + - if @available_public_keys.any? + .col-lg-9.col-lg-offset-3.append-bottom-default + %h5.prepend-top-0 + Public deploy keys available to any project (#{@available_public_keys.size}) + %ul.well-list = render @available_public_keys -- cgit v1.2.1 From ca988b2be7a8c1144cb050b517fa4c763f5ca496 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 25 Apr 2016 16:56:17 +0100 Subject: Fixed failing tests --- app/views/projects/group_links/index.html.haml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/views/projects/group_links/index.html.haml b/app/views/projects/group_links/index.html.haml index 13cdac2102f..2b904544f28 100644 --- a/app/views/projects/group_links/index.html.haml +++ b/app/views/projects/group_links/index.html.haml @@ -18,11 +18,9 @@ = select_tag :link_group_access, options_for_select(ProjectGroupLink.access_options, ProjectGroupLink.default_access), class: "form-control select-control" %span.caret = submit_tag "Share", class: "btn btn-create" - .col-sm-12 + .col-lg-9.col-lg-offset-3 %hr - .col-lg-3.settings-sidebar - %h4.prepend-top-0 - .col-lg-9.append-bottom-default + .col-lg-9.col-lg-offset-3.append-bottom-default.enabled-groups %h5.prepend-top-0 Groups you share with (#{@group_links.size}) - if @group_links.present? -- cgit v1.2.1 From 97bd349146bfb3acef77ec413cd0def552d00472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 25 Apr 2016 11:49:52 +0200 Subject: Improve Milestones API specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- CHANGELOG | 2 -- spec/requests/api/milestones_spec.rb | 63 ++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 38 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4ce16b44493..2d1c561fb82 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,8 +8,6 @@ v 8.7.1 (unreleased) - Fix license detection to detect all license files, not only known licenses. !3878 - Use the `can?` helper instead of `current_user.can?`. !3882 - Prevent users from deleting Webhooks via API they do not own - - Use the `can?` helper instead of `current_user.can?` - - Filter confidential issues from milestones API if user does not have access v 8.7.0 - Gitlab::GitAccess and Gitlab::GitAccessWiki are now instrumented diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb index cb9c3dde5ee..241995041bb 100644 --- a/spec/requests/api/milestones_spec.rb +++ b/spec/requests/api/milestones_spec.rb @@ -140,43 +140,34 @@ describe API::API, api: true do get api("/projects/#{project.id}/milestones/#{milestone.id}/issues") expect(response.status).to eq(401) end - end - - describe 'confidential issues' do - it 'should return confidential issues to team members' do - public_project = create(:project, :public) - user = create(:user) - milestone = create(:milestone, project: public_project) - issue = create(:issue, project: public_project) - confidential_issue = create(:issue, confidential: true, project: public_project) - public_project.team << [user, :developer] - milestone.issues << issue - milestone.issues << confidential_issue - - get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", user) - - expect(response.status).to eq(200) - expect(json_response).to be_an Array - expect(json_response.size).to eq(2) - expect(json_response.map { |issue| issue['id'] }).to include(issue.id, confidential_issue.id) - end - - it 'should not return confidential issues to regular users' do - public_project = create(:project, :public) - normal_user = create(:user) - milestone = create(:milestone, project: public_project) - issue = create(:issue, project: public_project) - confidential_issue = create(:issue, confidential: true, project: public_project) - public_project.team << [user, :developer] - milestone.issues << issue - milestone.issues << confidential_issue - - get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", normal_user) - expect(response.status).to eq(200) - expect(json_response).to be_an Array - expect(json_response.size).to eq(1) - expect(json_response.map { |issue| issue['id'] }).to include(issue.id) + describe 'confidential issues' do + let(:public_project) { create(:project, :public) } + let(:milestone) { create(:milestone, project: public_project) } + let(:issue) { create(:issue, project: public_project) } + let(:confidential_issue) { create(:issue, confidential: true, project: public_project) } + before do + public_project.team << [user, :developer] + milestone.issues << issue << confidential_issue + end + + it 'returns confidential issues to team members' do + get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", user) + + expect(response.status).to eq(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(2) + expect(json_response.map { |issue| issue['id'] }).to include(issue.id, confidential_issue.id) + end + + it 'does not return confidential issues to regular users' do + get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", create(:user)) + + expect(response.status).to eq(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(1) + expect(json_response.map { |issue| issue['id'] }).to include(issue.id) + end end end end -- cgit v1.2.1 From 54493b9aaef6b2209889a414cf3a26da131eb0ca Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 25 Apr 2016 17:45:05 +0100 Subject: Updated tests for deploy keys --- app/views/projects/deploy_keys/index.html.haml | 10 ++++------ features/project/deploy_keys.feature | 1 - features/steps/project/deploy_keys.rb | 14 +++++++------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/app/views/projects/deploy_keys/index.html.haml b/app/views/projects/deploy_keys/index.html.haml index d82ef31ab4b..e230834e8ba 100644 --- a/app/views/projects/deploy_keys/index.html.haml +++ b/app/views/projects/deploy_keys/index.html.haml @@ -12,7 +12,7 @@ = render "form" .col-lg-9.col-lg-offset-3 %hr - .col-lg-9.col-lg-offset-3.append-bottom-default + .col-lg-9.col-lg-offset-3.append-bottom-default.deploy-keys %h5.prepend-top-0 Enabled deploy keys for this project (#{@enabled_keys.size}) - if @enabled_keys.any? @@ -21,8 +21,7 @@ - else .profile-settings-message.text-center No deploy keys found. Create one with the form above or add existing one below. - .col-lg-9.col-lg-offset-3.append-bottom-default - %h5.prepend-top-0 + %h5.prepend-top-default Deploy keys from projects you have access to (#{@available_project_keys.size}) - if @available_project_keys.any? %ul.well-list @@ -30,9 +29,8 @@ - else .profile-settings-message.text-center No deploy keys from your projects could be found. Create one with the form above or add existing one below. - - if @available_public_keys.any? - .col-lg-9.col-lg-offset-3.append-bottom-default - %h5.prepend-top-0 + - if @available_public_keys.any? + %h5.prepend-top-default Public deploy keys available to any project (#{@available_public_keys.size}) %ul.well-list = render @available_public_keys diff --git a/features/project/deploy_keys.feature b/features/project/deploy_keys.feature index 47cf774094f..960b4100ee5 100644 --- a/features/project/deploy_keys.feature +++ b/features/project/deploy_keys.feature @@ -21,7 +21,6 @@ Feature: Project Deploy Keys Scenario: I add new deploy key Given I visit project deploy keys page - When I click 'New Deploy Key' And I submit new deploy key Then I should be on deploy keys page And I should see newly created deploy key diff --git a/features/steps/project/deploy_keys.rb b/features/steps/project/deploy_keys.rb index a4d6c9a1b8e..83b9ef48392 100644 --- a/features/steps/project/deploy_keys.rb +++ b/features/steps/project/deploy_keys.rb @@ -8,19 +8,19 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps end step 'I should see project deploy key' do - page.within '.enabled-keys' do + page.within '.deploy-keys' do expect(page).to have_content deploy_key.title end end step 'I should see other project deploy key' do - page.within '.available-keys' do + page.within '.deploy-keys' do expect(page).to have_content other_deploy_key.title end end step 'I should see public deploy key' do - page.within '.available-keys' do + page.within '.deploy-keys' do expect(page).to have_content public_deploy_key.title end end @@ -32,7 +32,7 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps step 'I submit new deploy key' do fill_in "deploy_key_title", with: "laptop" fill_in "deploy_key_key", with: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzrEJUIR6Y03TCE9rIJ+GqTBvgb8t1jI9h5UBzCLuK4VawOmkLornPqLDrGbm6tcwM/wBrrLvVOqi2HwmkKEIecVO0a64A4rIYScVsXIniHRS6w5twyn1MD3sIbN+socBDcaldECQa2u1dI3tnNVcs8wi77fiRe7RSxePsJceGoheRQgC8AZ510UdIlO+9rjIHUdVN7LLyz512auAfYsgx1OfablkQ/XJcdEwDNgi9imI6nAXhmoKUm1IPLT2yKajTIC64AjLOnE0YyCh6+7RFMpiMyu1qiOCpdjYwTgBRiciNRZCH8xIedyCoAmiUgkUT40XYHwLuwiPJICpkAzp7Q== user@laptop" - click_button "Create" + click_button "Add key" end step 'I should be on deploy keys page' do @@ -40,7 +40,7 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps end step 'I should see newly created deploy key' do - page.within '.enabled-keys' do + page.within '.deploy-keys' do expect(page).to have_content(deploy_key.title) end end @@ -56,7 +56,7 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps end step 'I should only see the same deploy key once' do - page.within '.available-keys' do + page.within '.deploy-keys' do expect(page).to have_selector('ul li', count: 1) end end @@ -66,7 +66,7 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps end step 'I click attach deploy key' do - page.within '.available-keys' do + page.within '.deploy-keys' do click_link 'Enable' end end -- cgit v1.2.1 From 9eac51376fe87d5fe92fe402041af0fb42016b62 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Mon, 25 Apr 2016 14:15:02 -0400 Subject: Changes support from IE 10+ to IE 11+ --- doc/install/requirements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/requirements.md b/doc/install/requirements.md index eb9fe5e1b1b..58f409746cd 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -142,4 +142,4 @@ On a very active server (10,000 active users) the Sidekiq process can use 1GB+ o - Firefox (Latest released version and [latest ESR version](https://www.mozilla.org/en-US/firefox/organizations/)) - Safari 7+ (known problem: required fields in html5 do not work) - Opera (Latest released version) -- Internet Explorer (IE) 10+ but please make sure that you have the `Compatibility View` mode disabled. +- Internet Explorer (IE) 11+ but please make sure that you have the `Compatibility View` mode disabled. -- cgit v1.2.1 From d5267dfd0dac8e4cab4919bf8aca611de3a5497b Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 24 Apr 2016 21:45:26 -0700 Subject: Prevent private snippets in public/internal projects from being leaked via API Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/15580 --- app/finders/snippets_finder.rb | 2 +- lib/api/project_snippets.rb | 15 ++++-- spec/requests/api/project_snippets_spec.rb | 87 ++++++++++++++++++++++++++++++ spec/requests/api/projects_spec.rb | 2 +- 4 files changed, 99 insertions(+), 7 deletions(-) diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb index a41172816b8..01cbf91c658 100644 --- a/app/finders/snippets_finder.rb +++ b/app/finders/snippets_finder.rb @@ -51,7 +51,7 @@ class SnippetsFinder snippets = project.snippets.fresh if current_user - if project.team.member?(current_user.id) + if project.team.member?(current_user.id) || current_user.admin? snippets else snippets.public_and_internal diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb index 22ce3c6a066..ce1bf0d26d2 100644 --- a/lib/api/project_snippets.rb +++ b/lib/api/project_snippets.rb @@ -11,6 +11,11 @@ module API end not_found! end + + def snippets_for_current_user + finder_params = { filter: :by_project, project: user_project } + SnippetsFinder.new.execute(current_user, finder_params) + end end # Get a project snippets @@ -20,7 +25,7 @@ module API # Example Request: # GET /projects/:id/snippets get ":id/snippets" do - present paginate(user_project.snippets), with: Entities::ProjectSnippet + present paginate(snippets_for_current_user), with: Entities::ProjectSnippet end # Get a project snippet @@ -31,7 +36,7 @@ module API # Example Request: # GET /projects/:id/snippets/:snippet_id get ":id/snippets/:snippet_id" do - @snippet = user_project.snippets.find(params[:snippet_id]) + @snippet = snippets_for_current_user.find(params[:snippet_id]) present @snippet, with: Entities::ProjectSnippet end @@ -73,7 +78,7 @@ module API # Example Request: # PUT /projects/:id/snippets/:snippet_id put ":id/snippets/:snippet_id" do - @snippet = user_project.snippets.find(params[:snippet_id]) + @snippet = snippets_for_current_user.find(params[:snippet_id]) authorize! :update_project_snippet, @snippet attrs = attributes_for_keys [:title, :file_name, :visibility_level] @@ -97,7 +102,7 @@ module API # DELETE /projects/:id/snippets/:snippet_id delete ":id/snippets/:snippet_id" do begin - @snippet = user_project.snippets.find(params[:snippet_id]) + @snippet = snippets_for_current_user.find(params[:snippet_id]) authorize! :update_project_snippet, @snippet @snippet.destroy rescue @@ -113,7 +118,7 @@ module API # Example Request: # GET /projects/:id/snippets/:snippet_id/raw get ":id/snippets/:snippet_id/raw" do - @snippet = user_project.snippets.find(params[:snippet_id]) + @snippet = snippets_for_current_user.find(params[:snippet_id]) env['api.format'] = :txt content_type 'text/plain' diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb index 3722ddf5a33..9706d060cfa 100644 --- a/spec/requests/api/project_snippets_spec.rb +++ b/spec/requests/api/project_snippets_spec.rb @@ -15,4 +15,91 @@ describe API::API, api: true do expect(json_response['expires_at']).to be_nil end end + + describe 'GET /projects/:project_id/snippets/' do + it 'all snippets available to team member' do + project = create(:project, :public) + user = create(:user) + project.team << [user, :developer] + public_snippet = create(:project_snippet, :public, project: project) + internal_snippet = create(:project_snippet, :internal, project: project) + private_snippet = create(:project_snippet, :private, project: project) + + get api("/projects/#{project.id}/snippets/", user) + + expect(response.status).to eq(200) + expect(json_response.size).to eq(3) + expect(json_response.map{ |snippet| snippet['id']} ).to include(public_snippet.id, internal_snippet.id, private_snippet.id) + end + + it 'hides private snippets from regular user' do + project = create(:project, :public) + user = create(:user) + create(:project_snippet, :private, project: project) + + get api("/projects/#{project.id}/snippets/", user) + expect(response.status).to eq(200) + expect(json_response.size).to eq(0) + end + end + + describe 'POST /projects/:project_id/snippets/' do + it 'creates a new snippet' do + admin = create(:admin) + project = create(:project) + params = { + title: 'Test Title', + file_name: 'test.rb', + code: 'puts "hello world"', + visibility_level: Gitlab::VisibilityLevel::PUBLIC + } + + post api("/projects/#{project.id}/snippets/", admin), params + + expect(response.status).to eq(201) + snippet = ProjectSnippet.find(json_response['id']) + expect(snippet.content).to eq(params[:code]) + expect(snippet.title).to eq(params[:title]) + expect(snippet.file_name).to eq(params[:file_name]) + expect(snippet.visibility_level).to eq(params[:visibility_level]) + end + end + + describe 'PUT /projects/:project_id/snippets/:id/' do + it 'updates snippet' do + admin = create(:admin) + snippet = create(:project_snippet, author: admin) + new_content = 'New content' + + put api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin), code: new_content + + expect(response.status).to eq(200) + snippet.reload + expect(snippet.content).to eq(new_content) + end + end + + describe 'DELETE /projects/:project_id/snippets/:id/' do + it 'deletes snippet' do + admin = create(:admin) + snippet = create(:project_snippet, author: admin) + + delete api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin) + + expect(response.status).to eq(200) + end + end + + describe 'GET /projects/:project_id/snippets/:id/raw' do + it 'returns raw text' do + admin = create(:admin) + snippet = create(:project_snippet, author: admin) + + get api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/raw", admin) + + expect(response.status).to eq(200) + expect(response.content_type).to eq 'text/plain' + expect(response.body).to eq(snippet.content) + end + end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index fccd08bd6da..66193eac051 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -11,7 +11,7 @@ describe API::API, api: true do let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } let(:project2) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace) } let(:project3) { create(:project, path: 'project3', creator_id: user.id, namespace: user.namespace) } - let(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') } + let(:snippet) { create(:project_snippet, :public, author: user, project: project, title: 'example') } let(:project_member) { create(:project_member, :master, user: user, project: project) } let(:project_member2) { create(:project_member, :developer, user: user3, project: project) } let(:user4) { create(:user) } -- cgit v1.2.1 From ef340f6e777875e1bbb38752e64ba7bea3ab2f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 21 Apr 2016 17:13:14 +0200 Subject: Ensure URL in all Service subclasses are valid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- app/helpers/issues_helper.rb | 48 +++++++---- app/models/project_services/buildkite_service.rb | 4 +- .../project_services/issue_tracker_service.rb | 2 +- app/models/project_services/jira_service.rb | 2 + app/models/project_services/slack_service.rb | 2 +- spec/helpers/issues_helper_spec.rb | 36 ++++++++ spec/models/external_wiki_service_spec.rb | 60 -------------- .../models/project_services/bamboo_service_spec.rb | 95 +++++++--------------- .../project_services/buildkite_service_spec.rb | 17 ++++ .../project_services/builds_email_service_spec.rb | 81 +++++++++--------- .../project_services/campfire_service_spec.rb | 42 ++++++++++ .../custom_issue_tracker_service_spec.rb | 49 +++++++++++ .../project_services/drone_ci_service_spec.rb | 13 +-- .../emails_on_push_service_spec.rb | 17 ++++ .../project_services/external_wiki_service_spec.rb | 65 +++++++++++++++ .../project_services/flowdock_service_spec.rb | 14 ++++ .../project_services/gemnasium_service_spec.rb | 16 ++++ .../gitlab_issue_tracker_service_spec.rb | 14 ++++ .../project_services/hipchat_service_spec.rb | 14 ++++ spec/models/project_services/irker_service_spec.rb | 14 ++-- spec/models/project_services/jira_service_spec.rb | 26 +++++- .../pivotaltracker_service_spec.rb | 42 ++++++++++ .../project_services/pushover_service_spec.rb | 20 +++-- .../project_services/redmine_service_spec.rb | 49 +++++++++++ spec/models/project_services/slack_service_spec.rb | 17 ++-- .../project_services/teamcity_service_spec.rb | 95 +++++++--------------- .../issue_tracker_service_shared_example.rb | 7 ++ 27 files changed, 579 insertions(+), 282 deletions(-) delete mode 100644 spec/models/external_wiki_service_spec.rb create mode 100644 spec/models/project_services/campfire_service_spec.rb create mode 100644 spec/models/project_services/custom_issue_tracker_service_spec.rb create mode 100644 spec/models/project_services/emails_on_push_service_spec.rb create mode 100644 spec/models/project_services/external_wiki_service_spec.rb create mode 100644 spec/models/project_services/pivotaltracker_service_spec.rb create mode 100644 spec/models/project_services/redmine_service_spec.rb create mode 100644 spec/support/issue_tracker_service_shared_example.rb diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index afe1e11a0da..198d39455d7 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -16,31 +16,49 @@ module IssuesHelper def url_for_project_issues(project = @project, options = {}) return '' if project.nil? - if options[:only_path] - project.issues_tracker.project_path - else - project.issues_tracker.project_url - end + url = + if options[:only_path] + project.issues_tracker.project_path + else + project.issues_tracker.project_url + end + + # Ensure we return a valid URL to prevent possible XSS. + URI.parse(url).to_s + rescue URI::InvalidURIError + '' end def url_for_new_issue(project = @project, options = {}) return '' if project.nil? - if options[:only_path] - project.issues_tracker.new_issue_path - else - project.issues_tracker.new_issue_url - end + url = + if options[:only_path] + project.issues_tracker.new_issue_path + else + project.issues_tracker.new_issue_url + end + + # Ensure we return a valid URL to prevent possible XSS. + URI.parse(url).to_s + rescue URI::InvalidURIError + '' end def url_for_issue(issue_iid, project = @project, options = {}) return '' if project.nil? - if options[:only_path] - project.issues_tracker.issue_path(issue_iid) - else - project.issues_tracker.issue_url(issue_iid) - end + url = + if options[:only_path] + project.issues_tracker.issue_path(issue_iid) + else + project.issues_tracker.issue_url(issue_iid) + end + + # Ensure we return a valid URL to prevent possible XSS. + URI.parse(url).to_s + rescue URI::InvalidURIError + '' end def bulk_update_milestone_options diff --git a/app/models/project_services/buildkite_service.rb b/app/models/project_services/buildkite_service.rb index 3efbfd2eec3..861cc974ec4 100644 --- a/app/models/project_services/buildkite_service.rb +++ b/app/models/project_services/buildkite_service.rb @@ -26,7 +26,7 @@ class BuildkiteService < CiService prop_accessor :project_url, :token, :enable_ssl_verification - validates :project_url, presence: true, if: :activated? + validates :project_url, presence: true, url: true, if: :activated? validates :token, presence: true, if: :activated? after_save :compose_service_hook, if: :activated? @@ -91,7 +91,7 @@ class BuildkiteService < CiService { type: 'text', name: 'project_url', placeholder: "#{ENDPOINT}/example/project" }, - + { type: 'checkbox', name: 'enable_ssl_verification', title: "Enable SSL verification" } diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb index 25045224ce5..c5501e06411 100644 --- a/app/models/project_services/issue_tracker_service.rb +++ b/app/models/project_services/issue_tracker_service.rb @@ -21,7 +21,7 @@ class IssueTrackerService < Service - validates :project_url, :issues_url, :new_issue_url, presence: true, if: :activated? + validates :project_url, :issues_url, :new_issue_url, presence: true, url: true, if: :activated? default_value_for :category, 'issue_tracker' diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 1ed42c4f3e7..b4418ba9284 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -28,6 +28,8 @@ class JiraService < IssueTrackerService prop_accessor :username, :password, :api_url, :jira_issue_transition_id, :title, :description, :project_url, :issues_url, :new_issue_url + validates :api_url, presence: true, url: true, if: :activated? + before_validation :set_api_url, :set_jira_issue_transition_id before_update :reset_password diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index fd65027f084..7092b757549 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -22,7 +22,7 @@ class SlackService < Service prop_accessor :webhook, :username, :channel boolean_accessor :notify_only_broken_builds - validates :webhook, presence: true, if: :activated? + validates :webhook, presence: true, url: true, if: :activated? def initialize_properties if properties.nil? diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index 543593cf389..bffe2c18b6f 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -30,6 +30,18 @@ describe IssuesHelper do expect(url_for_project_issues).to eq "" end + it 'returns an empty string if project_url is invalid' do + expect(project).to receive_message_chain('issues_tracker.project_url') { 'javascript:alert("foo");' } + + expect(url_for_project_issues(project)).to eq '' + end + + it 'returns an empty string if project_path is invalid' do + expect(project).to receive_message_chain('issues_tracker.project_path') { 'javascript:alert("foo");' } + + expect(url_for_project_issues(project, only_path: true)).to eq '' + end + describe "when external tracker was enabled and then config removed" do before do @project = ext_project @@ -68,6 +80,18 @@ describe IssuesHelper do expect(url_for_issue(issue.iid)).to eq "" end + it 'returns an empty string if issue_url is invalid' do + expect(project).to receive_message_chain('issues_tracker.issue_url') { 'javascript:alert("foo");' } + + expect(url_for_issue(issue.iid, project)).to eq '' + end + + it 'returns an empty string if issue_path is invalid' do + expect(project).to receive_message_chain('issues_tracker.issue_path') { 'javascript:alert("foo");' } + + expect(url_for_issue(issue.iid, project, only_path: true)).to eq '' + end + describe "when external tracker was enabled and then config removed" do before do @project = ext_project @@ -105,6 +129,18 @@ describe IssuesHelper do expect(url_for_new_issue).to eq "" end + it 'returns an empty string if issue_url is invalid' do + expect(project).to receive_message_chain('issues_tracker.new_issue_url') { 'javascript:alert("foo");' } + + expect(url_for_new_issue(project)).to eq '' + end + + it 'returns an empty string if issue_path is invalid' do + expect(project).to receive_message_chain('issues_tracker.new_issue_path') { 'javascript:alert("foo");' } + + expect(url_for_new_issue(project, only_path: true)).to eq '' + end + describe "when external tracker was enabled and then config removed" do before do @project = ext_project diff --git a/spec/models/external_wiki_service_spec.rb b/spec/models/external_wiki_service_spec.rb deleted file mode 100644 index d37978720bf..00000000000 --- a/spec/models/external_wiki_service_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# build_events :boolean default(FALSE), not null -# - -require 'spec_helper' - -describe ExternalWikiService, models: true do - include ExternalWikiHelper - describe "Associations" do - it { should belong_to :project } - it { should have_one :service_hook } - end - - describe "Validations" do - context "active" do - before do - subject.active = true - end - - it { should validate_presence_of :external_wiki_url } - end - end - - describe 'External wiki' do - let(:project) { create(:project) } - - context 'when it is active' do - before do - properties = { 'external_wiki_url' => 'https://gitlab.com' } - @service = project.create_external_wiki_service(active: true, properties: properties) - end - - after do - @service.destroy! - end - - it 'should replace the wiki url' do - wiki_path = get_project_wiki_path(project) - expect(wiki_path).to match('https://gitlab.com') - end - end - end -end diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb index 31b2c90122d..e771f35811e 100644 --- a/spec/models/project_services/bamboo_service_spec.rb +++ b/spec/models/project_services/bamboo_service_spec.rb @@ -27,86 +27,51 @@ describe BambooService, models: true do end describe 'Validations' do - describe '#bamboo_url' do - it 'does not validate the presence of bamboo_url if service is not active' do - bamboo_service = service - bamboo_service.active = false - - expect(bamboo_service).not_to validate_presence_of(:bamboo_url) - end - - it 'validates the presence of bamboo_url if service is active' do - bamboo_service = service - bamboo_service.active = true - - expect(bamboo_service).to validate_presence_of(:bamboo_url) - end - end + subject { service } - describe '#build_key' do - it 'does not validate the presence of build_key if service is not active' do - bamboo_service = service - bamboo_service.active = false + context 'when service is active' do + before { subject.active = true } - expect(bamboo_service).not_to validate_presence_of(:build_key) - end + it { is_expected.to validate_presence_of(:build_key) } + it { is_expected.to validate_presence_of(:bamboo_url) } + it_behaves_like 'issue tracker service URL attribute', :bamboo_url - it 'validates the presence of build_key if service is active' do - bamboo_service = service - bamboo_service.active = true + describe '#username' do + it 'does not validate the presence of username if password is nil' do + subject.password = nil - expect(bamboo_service).to validate_presence_of(:build_key) - end - end + expect(subject).not_to validate_presence_of(:username) + end - describe '#username' do - it 'does not validate the presence of username if service is not active' do - bamboo_service = service - bamboo_service.active = false + it 'validates the presence of username if password is present' do + subject.password = 'secret' - expect(bamboo_service).not_to validate_presence_of(:username) + expect(subject).to validate_presence_of(:username) + end end - it 'does not validate the presence of username if username is nil' do - bamboo_service = service - bamboo_service.active = true - bamboo_service.password = nil + describe '#password' do + it 'does not validate the presence of password if username is nil' do + subject.username = nil - expect(bamboo_service).not_to validate_presence_of(:username) - end + expect(subject).not_to validate_presence_of(:password) + end - it 'validates the presence of username if service is active and username is present' do - bamboo_service = service - bamboo_service.active = true - bamboo_service.password = 'secret' + it 'validates the presence of password if username is present' do + subject.username = 'john' - expect(bamboo_service).to validate_presence_of(:username) + expect(subject).to validate_presence_of(:password) + end end end - describe '#password' do - it 'does not validate the presence of password if service is not active' do - bamboo_service = service - bamboo_service.active = false - - expect(bamboo_service).not_to validate_presence_of(:password) - end - - it 'does not validate the presence of password if username is nil' do - bamboo_service = service - bamboo_service.active = true - bamboo_service.username = nil - - expect(bamboo_service).not_to validate_presence_of(:password) - end - - it 'validates the presence of password if service is active and username is present' do - bamboo_service = service - bamboo_service.active = true - bamboo_service.username = 'john' + context 'when service is inactive' do + before { subject.active = false } - expect(bamboo_service).to validate_presence_of(:password) - end + it { is_expected.not_to validate_presence_of(:build_key) } + it { is_expected.not_to validate_presence_of(:bamboo_url) } + it { is_expected.not_to validate_presence_of(:username) } + it { is_expected.not_to validate_presence_of(:password) } end end diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb index 88cd624877a..60364df2015 100644 --- a/spec/models/project_services/buildkite_service_spec.rb +++ b/spec/models/project_services/buildkite_service_spec.rb @@ -26,6 +26,23 @@ describe BuildkiteService, models: true do it { is_expected.to have_one :service_hook } end + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:project_url) } + it { is_expected.to validate_presence_of(:token) } + it_behaves_like 'issue tracker service URL attribute', :project_url + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:project_url) } + it { is_expected.not_to validate_presence_of(:token) } + end + end + describe 'commits methods' do before do @project = Project.new diff --git a/spec/models/project_services/builds_email_service_spec.rb b/spec/models/project_services/builds_email_service_spec.rb index 7c23c2efccd..236df8f047d 100644 --- a/spec/models/project_services/builds_email_service_spec.rb +++ b/spec/models/project_services/builds_email_service_spec.rb @@ -1,76 +1,71 @@ require 'spec_helper' describe BuildsEmailService do - let(:build) { create(:ci_build) } - let(:data) { Gitlab::BuildDataBuilder.build(build) } - let!(:project) { create(:project, :public, ci_id: 1) } - let(:service) { described_class.new(project: project, active: true) } + let(:data) { Gitlab::BuildDataBuilder.build(create(:ci_build)) } + + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:recipients) } + + context 'when pusher is added' do + before { subject.add_pusher = true } + + it { is_expected.not_to validate_presence_of(:recipients) } + end + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:recipients) } + end + end describe '#execute' do it 'sends email' do - service.recipients = 'test@gitlab.com' + subject.recipients = 'test@gitlab.com' data[:build_status] = 'failed' + expect(BuildEmailWorker).to receive(:perform_async) - service.execute(data) + + subject.execute(data) end it 'does not send email with succeeded build and notify_only_broken_builds on' do - expect(service).to receive(:notify_only_broken_builds).and_return(true) + expect(subject).to receive(:notify_only_broken_builds).and_return(true) data[:build_status] = 'success' + expect(BuildEmailWorker).not_to receive(:perform_async) - service.execute(data) + + subject.execute(data) end it 'does not send email with failed build and build_allow_failure is true' do data[:build_status] = 'failed' data[:build_allow_failure] = true + expect(BuildEmailWorker).not_to receive(:perform_async) - service.execute(data) + + subject.execute(data) end it 'does not send email with unknown build status' do data[:build_status] = 'foo' - expect(BuildEmailWorker).not_to receive(:perform_async) - service.execute(data) - end - it 'does not send email when recipients list is empty' do - service.recipients = ' ,, ' - data[:build_status] = 'failed' expect(BuildEmailWorker).not_to receive(:perform_async) - service.execute(data) - end - end - - describe 'validations' do - - context 'when pusher is not added' do - before { service.add_pusher = false } - - it 'does not allow empty recipient input' do - service.recipients = '' - expect(service.valid?).to be false - end - - it 'does allow non-empty recipient input' do - service.recipients = 'test@example.com' - expect(service.valid?).to be true - end + subject.execute(data) end - context 'when pusher is added' do - before { service.add_pusher = true } + it 'does not send email when recipients list is empty' do + subject.recipients = ' ,, ' + data[:build_status] = 'failed' - it 'does allow empty recipient input' do - service.recipients = '' - expect(service.valid?).to be true - end + expect(BuildEmailWorker).not_to receive(:perform_async) - it 'does allow non-empty recipient input' do - service.recipients = 'test@example.com' - expect(service.valid?).to be true - end + subject.execute(data) end end end diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb new file mode 100644 index 00000000000..3e6da42803b --- /dev/null +++ b/spec/models/project_services/campfire_service_spec.rb @@ -0,0 +1,42 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null +# + +require 'spec_helper' + +describe CampfireService, models: true do + describe 'Associations' do + it { is_expected.to belong_to :project } + it { is_expected.to have_one :service_hook } + end + + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:token) } + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:token) } + end + end +end diff --git a/spec/models/project_services/custom_issue_tracker_service_spec.rb b/spec/models/project_services/custom_issue_tracker_service_spec.rb new file mode 100644 index 00000000000..ff976f8ec59 --- /dev/null +++ b/spec/models/project_services/custom_issue_tracker_service_spec.rb @@ -0,0 +1,49 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null +# + +require 'spec_helper' + +describe CustomIssueTrackerService, models: true do + describe 'Associations' do + it { is_expected.to belong_to :project } + it { is_expected.to have_one :service_hook } + end + + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:project_url) } + it { is_expected.to validate_presence_of(:issues_url) } + it { is_expected.to validate_presence_of(:new_issue_url) } + it_behaves_like 'issue tracker service URL attribute', :project_url + it_behaves_like 'issue tracker service URL attribute', :issues_url + it_behaves_like 'issue tracker service URL attribute', :new_issue_url + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:project_url) } + it { is_expected.not_to validate_presence_of(:issues_url) } + it { is_expected.not_to validate_presence_of(:new_issue_url) } + end + end +end diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb index a2cf68a9e38..3a8e67438fc 100644 --- a/spec/models/project_services/drone_ci_service_spec.rb +++ b/spec/models/project_services/drone_ci_service_spec.rb @@ -28,25 +28,18 @@ describe DroneCiService, models: true do describe 'validations' do context 'active' do - before { allow(subject).to receive(:activated?).and_return(true) } + before { subject.active = true } it { is_expected.to validate_presence_of(:token) } it { is_expected.to validate_presence_of(:drone_url) } - it { is_expected.to allow_value('ewf9843kdnfdfs89234n').for(:token) } - it { is_expected.to allow_value('http://ci.example.com').for(:drone_url) } - it { is_expected.not_to allow_value('this is not url').for(:drone_url) } - it { is_expected.not_to allow_value('http//noturl').for(:drone_url) } - it { is_expected.not_to allow_value('ftp://ci.example.com').for(:drone_url) } + it_behaves_like 'issue tracker service URL attribute', :drone_url end context 'inactive' do - before { allow(subject).to receive(:activated?).and_return(false) } + before { subject.active = false } it { is_expected.not_to validate_presence_of(:token) } it { is_expected.not_to validate_presence_of(:drone_url) } - it { is_expected.to allow_value('ewf9843kdnfdfs89234n').for(:token) } - it { is_expected.to allow_value('http://drone.example.com').for(:drone_url) } - it { is_expected.to allow_value('ftp://drone.example.com').for(:drone_url) } end end diff --git a/spec/models/project_services/emails_on_push_service_spec.rb b/spec/models/project_services/emails_on_push_service_spec.rb new file mode 100644 index 00000000000..e6f78898c82 --- /dev/null +++ b/spec/models/project_services/emails_on_push_service_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe EmailsOnPushService do + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:recipients) } + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:recipients) } + end + end +end diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb new file mode 100644 index 00000000000..5fe5ea7d2df --- /dev/null +++ b/spec/models/project_services/external_wiki_service_spec.rb @@ -0,0 +1,65 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null +# + +require 'spec_helper' + +describe ExternalWikiService, models: true do + include ExternalWikiHelper + describe "Associations" do + it { should belong_to :project } + it { should have_one :service_hook } + end + + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:external_wiki_url) } + it_behaves_like 'issue tracker service URL attribute', :external_wiki_url + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:external_wiki_url) } + end + end + + describe 'External wiki' do + let(:project) { create(:project) } + + context 'when it is active' do + before do + properties = { 'external_wiki_url' => 'https://gitlab.com' } + @service = project.create_external_wiki_service(active: true, properties: properties) + end + + after do + @service.destroy! + end + + it 'should replace the wiki url' do + wiki_path = get_project_wiki_path(project) + expect(wiki_path).to match('https://gitlab.com') + end + end + end +end diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb index ff7fbcaa004..b7e627e6518 100644 --- a/spec/models/project_services/flowdock_service_spec.rb +++ b/spec/models/project_services/flowdock_service_spec.rb @@ -26,6 +26,20 @@ describe FlowdockService, models: true do it { is_expected.to have_one :service_hook } end + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:token) } + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:token) } + end + end + describe "Execute" do let(:user) { create(:user) } let(:project) { create(:project) } diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb index ecb3ccb1673..a08f1ac229f 100644 --- a/spec/models/project_services/gemnasium_service_spec.rb +++ b/spec/models/project_services/gemnasium_service_spec.rb @@ -26,6 +26,22 @@ describe GemnasiumService, models: true do it { is_expected.to have_one :service_hook } end + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:token) } + it { is_expected.to validate_presence_of(:api_key) } + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:token) } + it { is_expected.not_to validate_presence_of(:api_key) } + end + end + describe "Execute" do let(:user) { create(:user) } let(:project) { create(:project) } diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb index 3518dbd1728..7a1f106d6e3 100644 --- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb +++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb @@ -26,6 +26,20 @@ describe GitlabIssueTrackerService, models: true do it { is_expected.to have_one :service_hook } end + describe 'Validations' do + context 'when service is active' do + subject { described_class.new(project: create(:project), active: true) } + + it { is_expected.to validate_presence_of(:issues_url) } + it_behaves_like 'issue tracker service URL attribute', :issues_url + end + + context 'when service is inactive' do + subject { described_class.new(project: create(:project), active: false) } + + it { is_expected.not_to validate_presence_of(:issues_url) } + end + end describe 'project and issue urls' do let(:project) { create(:project) } diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index d878162a220..6fb5cad5011 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -26,6 +26,20 @@ describe HipchatService, models: true do it { is_expected.to have_one :service_hook } end + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:token) } + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:token) } + end + end + describe "Execute" do let(:hipchat) { HipchatService.new } let(:user) { create(:user, username: 'username') } diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb index b783b1a576e..4ee022a5171 100644 --- a/spec/models/project_services/irker_service_spec.rb +++ b/spec/models/project_services/irker_service_spec.rb @@ -29,14 +29,16 @@ describe IrkerService, models: true do end describe 'Validations' do - before do - subject.active = true - subject.properties['recipients'] = _recipients + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:recipients) } end - context 'active' do - let(:_recipients) { nil } - it { should validate_presence_of :recipients } + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:recipients) } end end diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 2f8193170ae..5309cfb99ff 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -26,6 +26,30 @@ describe JiraService, models: true do it { is_expected.to have_one :service_hook } end + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:api_url) } + it { is_expected.to validate_presence_of(:project_url) } + it { is_expected.to validate_presence_of(:issues_url) } + it { is_expected.to validate_presence_of(:new_issue_url) } + it_behaves_like 'issue tracker service URL attribute', :api_url + it_behaves_like 'issue tracker service URL attribute', :project_url + it_behaves_like 'issue tracker service URL attribute', :issues_url + it_behaves_like 'issue tracker service URL attribute', :new_issue_url + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:api_url) } + it { is_expected.not_to validate_presence_of(:project_url) } + it { is_expected.not_to validate_presence_of(:issues_url) } + it { is_expected.not_to validate_presence_of(:new_issue_url) } + end + end + describe "Execute" do let(:user) { create(:user) } let(:project) { create(:project) } @@ -72,7 +96,7 @@ describe JiraService, models: true do context "when a password was previously set" do before do - @jira_service = JiraService.create( + @jira_service = JiraService.create!( project: create(:project), properties: { api_url: 'http://jira.example.com/rest/api/2', diff --git a/spec/models/project_services/pivotaltracker_service_spec.rb b/spec/models/project_services/pivotaltracker_service_spec.rb new file mode 100644 index 00000000000..f37edd4d970 --- /dev/null +++ b/spec/models/project_services/pivotaltracker_service_spec.rb @@ -0,0 +1,42 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null +# + +require 'spec_helper' + +describe PivotaltrackerService, models: true do + describe 'Associations' do + it { is_expected.to belong_to :project } + it { is_expected.to have_one :service_hook } + end + + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:token) } + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:token) } + end + end +end diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb index 96039f9491b..555d9757b47 100644 --- a/spec/models/project_services/pushover_service_spec.rb +++ b/spec/models/project_services/pushover_service_spec.rb @@ -27,14 +27,20 @@ describe PushoverService, models: true do end describe 'Validations' do - context 'active' do - before do - subject.active = true - end + context 'when service is active' do + before { subject.active = true } - it { is_expected.to validate_presence_of :api_key } - it { is_expected.to validate_presence_of :user_key } - it { is_expected.to validate_presence_of :priority } + it { is_expected.to validate_presence_of(:api_key) } + it { is_expected.to validate_presence_of(:user_key) } + it { is_expected.to validate_presence_of(:priority) } + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:api_key) } + it { is_expected.not_to validate_presence_of(:user_key) } + it { is_expected.not_to validate_presence_of(:priority) } end end diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb new file mode 100644 index 00000000000..7d14f6e8280 --- /dev/null +++ b/spec/models/project_services/redmine_service_spec.rb @@ -0,0 +1,49 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null +# + +require 'spec_helper' + +describe RedmineService, models: true do + describe 'Associations' do + it { is_expected.to belong_to :project } + it { is_expected.to have_one :service_hook } + end + + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:project_url) } + it { is_expected.to validate_presence_of(:issues_url) } + it { is_expected.to validate_presence_of(:new_issue_url) } + it_behaves_like 'issue tracker service URL attribute', :project_url + it_behaves_like 'issue tracker service URL attribute', :issues_url + it_behaves_like 'issue tracker service URL attribute', :new_issue_url + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:project_url) } + it { is_expected.not_to validate_presence_of(:issues_url) } + it { is_expected.not_to validate_presence_of(:new_issue_url) } + end + end +end diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb index 478d59be08b..a97b7560137 100644 --- a/spec/models/project_services/slack_service_spec.rb +++ b/spec/models/project_services/slack_service_spec.rb @@ -26,13 +26,18 @@ describe SlackService, models: true do it { is_expected.to have_one :service_hook } end - describe "Validations" do - context "active" do - before do - subject.active = true - end + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } - it { is_expected.to validate_presence_of :webhook } + it { is_expected.to validate_presence_of(:webhook) } + it_behaves_like 'issue tracker service URL attribute', :webhook + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:webhook) } end end diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb index bc7423cee69..ad24b895170 100644 --- a/spec/models/project_services/teamcity_service_spec.rb +++ b/spec/models/project_services/teamcity_service_spec.rb @@ -27,86 +27,51 @@ describe TeamcityService, models: true do end describe 'Validations' do - describe '#teamcity_url' do - it 'does not validate the presence of teamcity_url if service is not active' do - teamcity_service = service - teamcity_service.active = false - - expect(teamcity_service).not_to validate_presence_of(:teamcity_url) - end - - it 'validates the presence of teamcity_url if service is active' do - teamcity_service = service - teamcity_service.active = true - - expect(teamcity_service).to validate_presence_of(:teamcity_url) - end - end + subject { service } - describe '#build_type' do - it 'does not validate the presence of build_type if service is not active' do - teamcity_service = service - teamcity_service.active = false + context 'when service is active' do + before { subject.active = true } - expect(teamcity_service).not_to validate_presence_of(:build_type) - end + it { is_expected.to validate_presence_of(:build_type) } + it { is_expected.to validate_presence_of(:teamcity_url) } + it_behaves_like 'issue tracker service URL attribute', :teamcity_url - it 'validates the presence of build_type if service is active' do - teamcity_service = service - teamcity_service.active = true + describe '#username' do + it 'does not validate the presence of username if password is nil' do + subject.password = nil - expect(teamcity_service).to validate_presence_of(:build_type) - end - end + expect(subject).not_to validate_presence_of(:username) + end - describe '#username' do - it 'does not validate the presence of username if service is not active' do - teamcity_service = service - teamcity_service.active = false + it 'validates the presence of username if password is present' do + subject.password = 'secret' - expect(teamcity_service).not_to validate_presence_of(:username) + expect(subject).to validate_presence_of(:username) + end end - it 'does not validate the presence of username if username is nil' do - teamcity_service = service - teamcity_service.active = true - teamcity_service.password = nil + describe '#password' do + it 'does not validate the presence of password if username is nil' do + subject.username = nil - expect(teamcity_service).not_to validate_presence_of(:username) - end + expect(subject).not_to validate_presence_of(:password) + end - it 'validates the presence of username if service is active and username is present' do - teamcity_service = service - teamcity_service.active = true - teamcity_service.password = 'secret' + it 'validates the presence of password if username is present' do + subject.username = 'john' - expect(teamcity_service).to validate_presence_of(:username) + expect(subject).to validate_presence_of(:password) + end end end - describe '#password' do - it 'does not validate the presence of password if service is not active' do - teamcity_service = service - teamcity_service.active = false - - expect(teamcity_service).not_to validate_presence_of(:password) - end - - it 'does not validate the presence of password if username is nil' do - teamcity_service = service - teamcity_service.active = true - teamcity_service.username = nil - - expect(teamcity_service).not_to validate_presence_of(:password) - end - - it 'validates the presence of password if service is active and username is present' do - teamcity_service = service - teamcity_service.active = true - teamcity_service.username = 'john' + context 'when service is inactive' do + before { subject.active = false } - expect(teamcity_service).to validate_presence_of(:password) - end + it { is_expected.not_to validate_presence_of(:build_type) } + it { is_expected.not_to validate_presence_of(:teamcity_url) } + it { is_expected.not_to validate_presence_of(:username) } + it { is_expected.not_to validate_presence_of(:password) } end end diff --git a/spec/support/issue_tracker_service_shared_example.rb b/spec/support/issue_tracker_service_shared_example.rb new file mode 100644 index 00000000000..b6d7436c360 --- /dev/null +++ b/spec/support/issue_tracker_service_shared_example.rb @@ -0,0 +1,7 @@ +RSpec.shared_examples 'issue tracker service URL attribute' do |url_attr| + it { is_expected.to allow_value('https://example.com').for(url_attr) } + + it { is_expected.not_to allow_value('example.com').for(url_attr) } + it { is_expected.not_to allow_value('ftp://example.com').for(url_attr) } + it { is_expected.not_to allow_value('herp-and-derp').for(url_attr) } +end -- cgit v1.2.1 From cd0750e0457f26f8165be301ad628e1830bd1e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 25 Apr 2016 15:46:15 +0200 Subject: Prevent private project name and namespace from leaking in the new MR view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #15591. Signed-off-by: Rémy Coutable --- app/services/merge_requests/build_service.rb | 3 +++ spec/features/merge_requests/create_new_mr_spec.rb | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb index fa34753c4fd..3544752d47a 100644 --- a/app/services/merge_requests/build_service.rb +++ b/app/services/merge_requests/build_service.rb @@ -7,6 +7,9 @@ module MergeRequests merge_request.can_be_created = false merge_request.compare_commits = [] merge_request.source_project = project unless merge_request.source_project + + merge_request.target_project = nil unless can?(current_user, :read_project, merge_request.target_project) + merge_request.target_project ||= (project.forked_from_project || project) merge_request.target_branch ||= merge_request.target_project.default_branch diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb index 00b60bd0e75..e296078bad8 100644 --- a/spec/features/merge_requests/create_new_mr_spec.rb +++ b/spec/features/merge_requests/create_new_mr_spec.rb @@ -30,4 +30,14 @@ feature 'Create New Merge Request', feature: true, js: true do expect(page).to have_content 'git checkout -b orphaned-branch origin/orphaned-branch' end + + context 'when target project cannot be viewed by the current user' do + it 'does not leak the private project name & namespace' do + private_project = create(:project, :private) + + visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_project_id: private_project.id }) + + expect(page).not_to have_content private_project.to_reference + end + end end -- cgit v1.2.1 From d388d687dda8e4a0303a8b6977172bc78f8b4222 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 25 Apr 2016 15:31:34 -0500 Subject: Increase screen width breakpoint for hide/show discussion --- app/assets/stylesheets/pages/notes.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 55b1ad97eb0..9619d65db85 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -215,7 +215,7 @@ ul.notes { } .discussion-actions { - @media (max-width: $screen-sm-max) { + @media (max-width: $screen-md-max) { float: none; margin-left: 0; -- cgit v1.2.1 From bf021fbbba92924e4925a0f085a70f75472a24e4 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 25 Apr 2016 16:12:32 -0500 Subject: Break in middle of word if a span within parallel view --- app/assets/stylesheets/pages/diff.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index ed14b2cd1fe..1a7d5f9666e 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -131,8 +131,13 @@ margin: 0; padding: 0 0.5em; border: none; + &.parallel { display: table-cell; + + span { + word-break: break-all; + } } } -- cgit v1.2.1 From df0cdc8cb4757a500b511e176f77b2c6a337a57e Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 25 Apr 2016 08:27:29 +0100 Subject: Escape key closes the dropdown Fixes #15432 --- app/assets/javascripts/gl_dropdown.js.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 29466e9f2ed..1d1bfeb2e77 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -184,6 +184,9 @@ class GitLabDropdown @dropdown.on "shown.bs.dropdown", @opened @dropdown.on "hidden.bs.dropdown", @hidden @dropdown.on "click", ".dropdown-menu, .dropdown-menu-close", @shouldPropagate + @dropdown.on 'keyup', (e) => + if e.which is 27 # Escape key + $('.dropdown-menu-close', @dropdown).trigger 'click' if @dropdown.find(".dropdown-toggle-page").length @dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on "click", (e) => -- cgit v1.2.1 From 0158b86d8c1d5f72a249420e5f91ea8e59ff218b Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 26 Apr 2016 09:13:03 +0100 Subject: Updated label links to work correctly for filtering See !3846#note_5033951 --- app/assets/javascripts/labels_select.js.coffee | 2 +- app/helpers/labels_helper.rb | 2 +- spec/helpers/labels_helper_spec.rb | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/labels_select.js.coffee b/app/assets/javascripts/labels_select.js.coffee index 85517b18c5a..7d61cd9bf73 100644 --- a/app/assets/javascripts/labels_select.js.coffee +++ b/app/assets/javascripts/labels_select.js.coffee @@ -30,7 +30,7 @@ class @LabelsSelect if issueUpdateURL labelHTMLTemplate = _.template( '<% _.each(labels, function(label){ %> - issues?label_name=<%= _.escape(label.title) %>"> + issues?label_name[]=<%= _.escape(label.title) %>"> <%= _.escape(label.title) %> diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 3dded7c2f23..c99b137cdaa 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -37,7 +37,7 @@ module LabelsHelper link = send("namespace_project_#{type.to_s.pluralize}_path", project.namespace, project, - label_name: label.name) + label_name: [label.name]) if block_given? link_to link, &block diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index 39042ff7e91..501f150cfda 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -11,13 +11,13 @@ describe LabelsHelper do end it 'uses the instance variable' do - expect(link_to_label(label)).to match %r{} + expect(link_to_label(label)).to match %r{} end end context 'without @project set' do it "uses the label's project" do - expect(link_to_label(label)).to match %r{.*} + expect(link_to_label(label)).to match %r{.*} end end @@ -25,7 +25,7 @@ describe LabelsHelper do let(:another_project) { double('project', namespace: 'foo3', to_param: 'bar3') } it 'links to merge requests page' do - expect(link_to_label(label, project: another_project)).to match %r{.*} + expect(link_to_label(label, project: another_project)).to match %r{.*} end end @@ -33,7 +33,7 @@ describe LabelsHelper do ['issue', :issue, 'merge_request', :merge_request].each do |type| context "set to #{type}" do it 'links to correct page' do - expect(link_to_label(label, type: type)).to match %r{.*} + expect(link_to_label(label, type: type)).to match %r{.*} end end end -- cgit v1.2.1 From 180c45b37ee16c24ddcb5c26a631dbca4ac76335 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Fri, 22 Apr 2016 13:25:32 +0300 Subject: AwardsHandler follows code style conventions --- app/assets/javascripts/awards_handler.coffee | 66 ++++++++++++++++------------ app/assets/javascripts/notes.js.coffee | 8 ++-- app/views/votes/_votes_block.html.haml | 18 ++++---- 3 files changed, 50 insertions(+), 42 deletions(-) diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee index fcba9818726..21bd19ef07c 100644 --- a/app/assets/javascripts/awards_handler.coffee +++ b/app/assets/javascripts/awards_handler.coffee @@ -1,5 +1,5 @@ class @AwardsHandler - constructor: (@get_emojis_url, @post_emoji_url, @noteable_type, @noteable_id, @unicodes) -> + constructor: (@getEmojisUrl, @postEmojiUrl, @noteableType, @noteableId, @unicodes) -> $(".js-add-award").on "click", (event) => event.stopPropagation() event.preventDefault() @@ -23,13 +23,13 @@ class @AwardsHandler .find(".icon") .data "emoji" - if emoji is "thumbsup" and awards_handler.didUserClickEmoji $(this), "thumbsdown" - awards_handler.addAward "thumbsdown" + if emoji is "thumbsup" and awardsHandler.didUserClickEmoji $(this), "thumbsdown" + awardsHandler.addAward "thumbsdown" - else if emoji is "thumbsdown" and awards_handler.didUserClickEmoji $(this), "thumbsup" - awards_handler.addAward "thumbsup" + else if emoji is "thumbsdown" and awardsHandler.didUserClickEmoji $(this), "thumbsup" + awardsHandler.addAward "thumbsup" - awards_handler.addAward emoji + awardsHandler.addAward emoji $(this).trigger 'blur' @@ -47,7 +47,7 @@ class @AwardsHandler $("#emoji_search").focus() else $('.js-add-award').addClass "is-loading" - $.get @get_emojis_url, (response) => + $.get @getEmojisUrl, (response) => $('.js-add-award').removeClass "is-loading" $(".js-award-holder").append response setTimeout => @@ -99,25 +99,25 @@ class @AwardsHandler emojiIcon.remove() removeMeFromAuthorList: (emoji) -> - award_block = @findEmojiIcon(emoji).parent() - authors = award_block + awardBlock = @findEmojiIcon(emoji).parent() + authors = awardBlock .attr("data-original-title") .split(", ") authors.splice(authors.indexOf("me"),1) - award_block + awardBlock .closest(".js-emoji-btn") .attr("data-original-title", authors.join(", ")) - @resetTooltip(award_block) + @resetTooltip(awardBlock) addMeToAuthorList: (emoji) -> - award_block = @findEmojiIcon(emoji).parent() - origTitle = award_block.attr("data-original-title").trim() + awardBlock = @findEmojiIcon(emoji).parent() + origTitle = awardBlock.attr("data-original-title").trim() authors = [] if origTitle authors = origTitle.split(', ') authors.push("me") - award_block.attr("data-original-title", authors.join(", ")) - @resetTooltip(award_block) + awardBlock.attr("data-original-title", authors.join(", ")) + @resetTooltip(awardBlock) resetTooltip: (award) -> award.tooltip("destroy") @@ -139,20 +139,28 @@ class @AwardsHandler "" ) - emoji_node = $(nodes.join("\n")) + $(nodes.join("\n")) .insertBefore(".js-award-holder") .find(".emoji-icon") .data("emoji", emoji) $('.award-control').tooltip() resolveNameToCssClass: (emoji) -> - "emoji-#{@unicodes[emoji]}" + emoji_icon = $(".emoji-menu-content [data-emoji='#{emoji}']") + + if emoji_icon.length > 0 + unicodeName = emoji_icon.data('unicode-name') + else + # Find by alias + unicodeName = $(".emoji-menu-content [data-aliases*=':#{emoji}:']").data('unicode-name') + + "emoji-#{unicodeName}" postEmoji: (emoji, callback) -> - $.post @post_emoji_url, { note: { + $.post @postEmojiUrl, { note: { note: ":#{emoji}:" - noteable_type: @noteable_type - noteable_id: @noteable_id + noteable_type: @noteableType + noteable_id: @noteableId }},(data) -> if data.ok callback.call() @@ -166,21 +174,21 @@ class @AwardsHandler }, 200) addEmojiToFrequentlyUsedList: (emoji) -> - frequently_used_emojis = @getFrequentlyUsedEmojis() - frequently_used_emojis.push(emoji) - $.cookie('frequently_used_emojis', frequently_used_emojis.join(","), { expires: 365 }) + frequentlyUsedEmojis = @getFrequentlyUsedEmojis() + frequentlyUsedEmojis.push(emoji) + $.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(","), { expires: 365 }) getFrequentlyUsedEmojis: -> - frequently_used_emojis = ($.cookie('frequently_used_emojis') || "").split(",") - _.compact(_.uniq(frequently_used_emojis)) + frequentlyUsedEmojis = ($.cookie('frequently_used_emojis') || "").split(",") + _.compact(_.uniq(frequentlyUsedEmojis)) renderFrequentlyUsedBlock: -> if $.cookie('frequently_used_emojis') - frequently_used_emojis = @getFrequentlyUsedEmojis() + frequentlyUsedEmojis = @getFrequentlyUsedEmojis() ul = $("
    ") - for emoji in frequently_used_emojis + for emoji in frequentlyUsedEmojis do (emoji) -> $(".emoji-menu-content [data-emoji='#{emoji}']").closest("li").clone().appendTo(ul) @@ -196,8 +204,8 @@ class @AwardsHandler if term # Generate a search result block h5 = $("
    ").text("Search results").addClass("emoji-search") - found_emojis = @searchEmojis(term).show() - ul = $("
      ").addClass("emoji-menu-list emoji-menu-search").append(found_emojis) + foundEmojis = @searchEmojis(term).show() + ul = $("
        ").addClass("emoji-menu-list emoji-menu-search").append(foundEmojis) $(".emoji-menu-content ul, .emoji-menu-content h5").hide() $(".emoji-menu-content").append(h5).append(ul) else diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index 82e210fed7d..efb3e8e2198 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -167,8 +167,8 @@ class @Notes return if note.award - awards_handler.addAwardToEmojiBar(note.note) - awards_handler.scrollToAwards() + awardsHandler.addAwardToEmojiBar(note.note) + awardsHandler.scrollToAwards() # render note if it not present in loaded list # or skip if rendered @@ -373,11 +373,11 @@ class @Notes new GLForm form if scrollTo? and myLastNote? - # scroll to the bottom + # scroll to the bottom # so the open of the last element doesn't make a jump $('html, body').scrollTop($(document).height()); $('html, body').animate({ - scrollTop: myLastNote.offset().top - 150 + scrollTop: myLastNote.offset().top - 150 }, 500, -> $noteText = form.find(".js-note-text") $noteText.focus() diff --git a/app/views/votes/_votes_block.html.haml b/app/views/votes/_votes_block.html.haml index 59e12798691..4beb8746444 100644 --- a/app/views/votes/_votes_block.html.haml +++ b/app/views/votes/_votes_block.html.haml @@ -15,16 +15,16 @@ - if current_user :javascript - var get_emojis_url = "#{emojis_path}"; - var post_emoji_url = "#{award_toggle_namespace_project_notes_path(@project.namespace, @project)}"; - var noteable_type = "#{votable.class.name.underscore}"; - var noteable_id = "#{votable.id}"; + var getEmojisUrl = "#{emojis_path}"; + var postEmojiUrl = "#{award_toggle_namespace_project_notes_path(@project.namespace, @project)}"; + var noteableType = "#{votable.class.name.underscore}"; + var noteableId = "#{votable.id}"; var unicodes = #{AwardEmoji.unicode.to_json}; - window.awards_handler = new AwardsHandler( - get_emojis_url, - post_emoji_url, - noteable_type, - noteable_id, + window.awardsHandler = new AwardsHandler( + getEmojisUrl, + postEmojiUrl, + noteableType, + noteableId, unicodes ); -- cgit v1.2.1 From 3e40b88547b97dc7937b93882d2f959c39ef5f31 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 26 Apr 2016 09:35:58 +0100 Subject: Project title dropdown tests Added a test for when on an issue page to check whether the project dropdown links will still work See !3870 --- spec/features/projects_spec.rb | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index 782c0bfe666..9dd0378d165 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -104,6 +104,33 @@ feature 'Project', feature: true do end end + describe 'project title' do + let(:user) { create(:user) } + let(:project) { create(:project, namespace: user.namespace) } + let(:project2) { create(:project, namespace: user.namespace, path: 'test') } + let(:issue) { create(:issue, project: project) } + + context 'on issues page', js: true do + before do + login_with(user) + project.team.add_user(user, Gitlab::Access::MASTER) + project2.team.add_user(user, Gitlab::Access::MASTER) + visit namespace_project_issue_path(project.namespace, project, issue) + end + + it 'click toggle and show dropdown' do + find('.js-projects-dropdown-toggle').click + expect(page).to have_css('.dropdown-menu-projects .dropdown-content li', count: 2) + + page.within '.dropdown-menu-projects' do + click_link project.name_with_namespace + end + + expect(page).to have_content project.name + end + end + end + def remove_with_confirm(button_text, confirm_with) click_button button_text fill_in 'confirm_name_input', with: confirm_with -- cgit v1.2.1 From 311c859d11f2ca6bcfc0bba04e778535dc4e0f83 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Mon, 25 Apr 2016 22:37:25 +0300 Subject: awards_handler: single quotes --- app/assets/javascripts/awards_handler.coffee | 128 +++++++++++++-------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee index 21bd19ef07c..bf95e06b4e5 100644 --- a/app/assets/javascripts/awards_handler.coffee +++ b/app/assets/javascripts/awards_handler.coffee @@ -1,58 +1,58 @@ class @AwardsHandler constructor: (@getEmojisUrl, @postEmojiUrl, @noteableType, @noteableId, @unicodes) -> - $(".js-add-award").on "click", (event) => + $('.js-add-award').on 'click', (event) => event.stopPropagation() event.preventDefault() @showEmojiMenu() - $("html").on 'click', (event) -> - if !$(event.target).closest(".emoji-menu").length - if $(".emoji-menu").is(":visible") - $(".emoji-menu").removeClass "is-visible" + $('html').on 'click', (event) -> + if !$(event.target).closest('.emoji-menu').length + if $('.emoji-menu').is(':visible') + $('.emoji-menu').removeClass 'is-visible' - $(".awards") - .off "click" - .on "click", ".js-emoji-btn", @handleClick + $('.awards') + .off 'click' + .on 'click', '.js-emoji-btn', @handleClick @renderFrequentlyUsedBlock() handleClick: (e) -> e.preventDefault() emoji = $(this) - .find(".icon") - .data "emoji" + .find('.icon') + .data 'emoji' - if emoji is "thumbsup" and awardsHandler.didUserClickEmoji $(this), "thumbsdown" - awardsHandler.addAward "thumbsdown" + if emoji is 'thumbsup' and awardsHandler.didUserClickEmoji $(this), 'thumbsdown' + awardsHandler.addAward 'thumbsdown' - else if emoji is "thumbsdown" and awardsHandler.didUserClickEmoji $(this), "thumbsup" - awardsHandler.addAward "thumbsup" + else if emoji is 'thumbsdown' and awardsHandler.didUserClickEmoji $(this), 'thumbsup' + awardsHandler.addAward 'thumbsup' awardsHandler.addAward emoji $(this).trigger 'blur' didUserClickEmoji: (that, emoji) -> - if $(that).siblings("button:has([data-emoji=#{emoji}])").attr("data-original-title") - $(that).siblings("button:has([data-emoji=#{emoji}])").attr("data-original-title").indexOf('me') > -1 + if $(that).siblings("button:has([data-emoji=#{emoji}])").attr('data-original-title') + $(that).siblings("button:has([data-emoji=#{emoji}])").attr('data-original-title').indexOf('me') > -1 showEmojiMenu: -> - if $(".emoji-menu").length - if $(".emoji-menu").is ".is-visible" - $(".emoji-menu").removeClass "is-visible" - $("#emoji_search").blur() + if $('.emoji-menu').length + if $('.emoji-menu').is '.is-visible' + $('.emoji-menu').removeClass 'is-visible' + $('#emoji_search').blur() else - $(".emoji-menu").addClass "is-visible" - $("#emoji_search").focus() + $('.emoji-menu').addClass 'is-visible' + $('#emoji_search').focus() else - $('.js-add-award').addClass "is-loading" + $('.js-add-award').addClass 'is-loading' $.get @getEmojisUrl, (response) => - $('.js-add-award').removeClass "is-loading" - $(".js-award-holder").append response + $('.js-add-award').removeClass 'is-loading' + $('.js-award-holder').append response setTimeout => - $(".emoji-menu").addClass "is-visible" - $("#emoji_search").focus() + $('.emoji-menu').addClass 'is-visible' + $('#emoji_search').focus() @setupSearch() , 200 @@ -60,7 +60,7 @@ class @AwardsHandler @postEmoji emoji, => @addAwardToEmojiBar(emoji) - $(".emoji-menu").removeClass "is-visible" + $('.emoji-menu').removeClass 'is-visible' addAwardToEmojiBar: (emoji) -> @addEmojiToFrequentlyUsedList(emoji) @@ -69,9 +69,9 @@ class @AwardsHandler if @isActive(emoji) @decrementCounter(emoji) else - counter = @findEmojiIcon(emoji).siblings(".js-counter") + counter = @findEmojiIcon(emoji).siblings('.js-counter') counter.text(parseInt(counter.text()) + 1) - counter.parent().addClass("active") + counter.parent().addClass('active') @addMeToAuthorList(emoji) else @createEmoji(emoji) @@ -80,47 +80,47 @@ class @AwardsHandler @findEmojiIcon(emoji).length > 0 isActive: (emoji) -> - @findEmojiIcon(emoji).parent().hasClass("active") + @findEmojiIcon(emoji).parent().hasClass('active') decrementCounter: (emoji) -> - counter = @findEmojiIcon(emoji).siblings(".js-counter") + counter = @findEmojiIcon(emoji).siblings('.js-counter') emojiIcon = counter.parent() if parseInt(counter.text()) > 1 counter.text(parseInt(counter.text()) - 1) - emojiIcon.removeClass("active") + emojiIcon.removeClass('active') @removeMeFromAuthorList(emoji) - else if emoji == "thumbsup" || emoji == "thumbsdown" - emojiIcon.tooltip("destroy") + else if emoji == 'thumbsup' || emoji == 'thumbsdown' + emojiIcon.tooltip('destroy') counter.text(0) - emojiIcon.removeClass("active") + emojiIcon.removeClass('active') @removeMeFromAuthorList(emoji) else - emojiIcon.tooltip("destroy") + emojiIcon.tooltip('destroy') emojiIcon.remove() removeMeFromAuthorList: (emoji) -> awardBlock = @findEmojiIcon(emoji).parent() authors = awardBlock - .attr("data-original-title") - .split(", ") - authors.splice(authors.indexOf("me"),1) + .attr('data-original-title') + .split(', ') + authors.splice(authors.indexOf('me'),1) awardBlock - .closest(".js-emoji-btn") - .attr("data-original-title", authors.join(", ")) + .closest('.js-emoji-btn') + .attr('data-original-title', authors.join(', ')) @resetTooltip(awardBlock) addMeToAuthorList: (emoji) -> awardBlock = @findEmojiIcon(emoji).parent() - origTitle = awardBlock.attr("data-original-title").trim() + origTitle = awardBlock.attr('data-original-title').trim() authors = [] if origTitle authors = origTitle.split(', ') - authors.push("me") - awardBlock.attr("data-original-title", authors.join(", ")) + authors.push('me') + awardBlock.attr('data-original-title', authors.join(', ')) @resetTooltip(awardBlock) resetTooltip: (award) -> - award.tooltip("destroy") + award.tooltip('destroy') # "destroy" call is asynchronous and there is no appropriate callback on it, this is why we need to set timeout. setTimeout (-> @@ -140,16 +140,16 @@ class @AwardsHandler ) $(nodes.join("\n")) - .insertBefore(".js-award-holder") - .find(".emoji-icon") - .data("emoji", emoji) + .insertBefore('.js-award-holder') + .find('.emoji-icon') + .data('emoji', emoji) $('.award-control').tooltip() resolveNameToCssClass: (emoji) -> - emoji_icon = $(".emoji-menu-content [data-emoji='#{emoji}']") + emojiIcon = $(".emoji-menu-content [data-emoji='#{emoji}']") - if emoji_icon.length > 0 - unicodeName = emoji_icon.data('unicode-name') + if emojiIcon.length > 0 + unicodeName = emojiIcon.data('unicode-name') else # Find by alias unicodeName = $(".emoji-menu-content [data-aliases*=':#{emoji}:']").data('unicode-name') @@ -176,40 +176,40 @@ class @AwardsHandler addEmojiToFrequentlyUsedList: (emoji) -> frequentlyUsedEmojis = @getFrequentlyUsedEmojis() frequentlyUsedEmojis.push(emoji) - $.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(","), { expires: 365 }) + $.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(','), { expires: 365 }) getFrequentlyUsedEmojis: -> - frequentlyUsedEmojis = ($.cookie('frequently_used_emojis') || "").split(",") + frequentlyUsedEmojis = ($.cookie('frequently_used_emojis') || '').split(',') _.compact(_.uniq(frequentlyUsedEmojis)) renderFrequentlyUsedBlock: -> if $.cookie('frequently_used_emojis') frequentlyUsedEmojis = @getFrequentlyUsedEmojis() - ul = $("
          ") + ul = $('
            ') for emoji in frequentlyUsedEmojis do (emoji) -> - $(".emoji-menu-content [data-emoji='#{emoji}']").closest("li").clone().appendTo(ul) + $(".emoji-menu-content [data-emoji='#{emoji}']").closest('li').clone().appendTo(ul) - $("input.emoji-search").after(ul).after($("
            ").text("Frequently used")) + $('input.emoji-search').after(ul).after($('
            ').text('Frequently used')) setupSearch: -> - $("input.emoji-search").keyup (ev) => + $('input.emoji-search').keyup (ev) => term = $(ev.target).val() # Clean previous search results - $("ul.emoji-menu-search, h5.emoji-search").remove() + $('ul.emoji-menu-search, h5.emoji-search').remove() if term # Generate a search result block - h5 = $("
            ").text("Search results").addClass("emoji-search") + h5 = $('
            ').text('Search results').addClass('emoji-search') foundEmojis = @searchEmojis(term).show() - ul = $("
              ").addClass("emoji-menu-list emoji-menu-search").append(foundEmojis) - $(".emoji-menu-content ul, .emoji-menu-content h5").hide() - $(".emoji-menu-content").append(h5).append(ul) + ul = $('
                ').addClass('emoji-menu-list emoji-menu-search').append(foundEmojis) + $('.emoji-menu-content ul, .emoji-menu-content h5').hide() + $('.emoji-menu-content').append(h5).append(ul) else - $(".emoji-menu-content").children().show() + $('.emoji-menu-content').children().show() searchEmojis: (term)-> $(".emoji-menu-content [data-emoji*='#{term}']").closest("li").clone() -- cgit v1.2.1 From 2e072034a6a30eaf9478875140c541b9b072f7aa Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 26 Apr 2016 11:54:37 +0200 Subject: Send 'admin emails' weekly, not daily Daily seems to be to spammy, so let's default to weekly instead. --- config/gitlab.yml.example | 4 ++-- config/initializers/1_settings.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index d9c15f81404..20d65a8f334 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -168,9 +168,9 @@ production: &base # once per hour you will have concurrent 'git fsck' jobs. repository_check_worker: cron: "20 * * * *" - # Send admin emails once a day + # Send admin emails once a week admin_email_worker: - cron: "0 0 * * *" + cron: "0 0 * * 0" # Remove outdated repository archives repository_archive_cache_worker: diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 10c25044b75..e32f7c15e65 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -245,7 +245,7 @@ Settings.cron_jobs['repository_check_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['repository_check_worker']['cron'] ||= '20 * * * *' Settings.cron_jobs['repository_check_worker']['job_class'] = 'RepositoryCheck::BatchWorker' Settings.cron_jobs['admin_email_worker'] ||= Settingslogic.new({}) -Settings.cron_jobs['admin_email_worker']['cron'] ||= '0 0 * * *' +Settings.cron_jobs['admin_email_worker']['cron'] ||= '0 0 * * 0' Settings.cron_jobs['admin_email_worker']['job_class'] = 'AdminEmailWorker' Settings.cron_jobs['repository_archive_cache_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['repository_archive_cache_worker']['cron'] ||= '0 * * * *' -- cgit v1.2.1 From 4c772d9bc849e21349d6b01701db9beccf903c44 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 26 Apr 2016 10:56:18 +0100 Subject: Project webhooks updated UI Closes #13993 --- app/assets/stylesheets/framework/typography.scss | 10 ++ app/views/projects/hooks/_project_hook.html.haml | 15 +++ app/views/projects/hooks/index.html.haml | 161 +++++++++++------------ 3 files changed, 101 insertions(+), 85 deletions(-) create mode 100644 app/views/projects/hooks/_project_hook.html.haml diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index 0a5b4b8834c..b2535ddf4bd 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -205,6 +205,10 @@ h1, h2, h3, h4, h5, h6 { font-weight: 600; } +.light-header { + font-weight: 600; +} + /** CODE **/ pre { font-family: $monospace_font; @@ -259,3 +263,9 @@ h1, h2, h3, h4 { color: $gl-gray; } } + +.text-right-lg { + @media (min-width: $screen-lg-min) { + text-align: right; + } +} diff --git a/app/views/projects/hooks/_project_hook.html.haml b/app/views/projects/hooks/_project_hook.html.haml new file mode 100644 index 00000000000..62eba5888a4 --- /dev/null +++ b/app/views/projects/hooks/_project_hook.html.haml @@ -0,0 +1,15 @@ +%li + .row + .col-md-8.col-lg-7 + %strong.light-header= hook.url + %div + - %w(push_events tag_push_events issues_events note_events merge_requests_events build_events).each do |trigger| + - if hook.send(trigger) + %span.label.label-gray.deploy-project-label= trigger.titleize + .col-md-4.col-lg-5.text-right-lg.prepend-top-5 + %span.append-right-10.inline + SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"} + = link_to "Test", test_namespace_project_hook_path(@project.namespace, @project, hook), class: "btn btn-sm" + = link_to namespace_project_hook_path(@project.namespace, @project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-transparent" do + %span.sr-only Remove + = icon('trash') diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml index aae3abcad4b..6f1ee209430 100644 --- a/app/views/projects/hooks/index.html.haml +++ b/app/views/projects/hooks/index.html.haml @@ -1,88 +1,79 @@ - page_title "Webhooks" -%h3.page-title - Webhooks +.row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + = page_title + %p + #{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 + %h5.prepend-top-0 + Add new webhook + = form_for [@project.namespace.becomes(Namespace), @project, @hook], as: :hook, url: namespace_project_hooks_path(@project.namespace, @project) do |f| + = form_errors(@hook) -%p.light - #{link_to "Webhooks ", help_page_path("web_hooks", "web_hooks"), class: "vlink"} can be - used for binding events when something is happening within the project. - -%hr.clearfix - -= form_for [@project.namespace.becomes(Namespace), @project, @hook], as: :hook, url: namespace_project_hooks_path(@project.namespace, @project), html: { class: 'form-horizontal' } do |f| - = form_errors(@hook) - - .form-group - = f.label :url, "URL", class: 'control-label' - .col-sm-10 - = f.text_field :url, class: "form-control", placeholder: 'http://example.com/trigger-ci.json' - .form-group - = f.label :url, "Trigger", class: 'control-label' - .col-sm-10.prepend-top-10 - %div - = f.check_box :push_events, class: 'pull-left' - .prepend-left-20 - = f.label :push_events, class: 'list-label' do - %strong Push events - %p.light - This url will be triggered by a push to the repository - %div - = f.check_box :tag_push_events, class: 'pull-left' - .prepend-left-20 - = f.label :tag_push_events, class: 'list-label' do - %strong Tag push events - %p.light - This url will be triggered when a new tag is pushed to the repository - %div - = f.check_box :note_events, class: 'pull-left' - .prepend-left-20 - = f.label :note_events, class: 'list-label' do - %strong Comments - %p.light - This url will be triggered when someone adds a comment - %div - = f.check_box :issues_events, class: 'pull-left' - .prepend-left-20 - = f.label :issues_events, class: 'list-label' do - %strong Issues events - %p.light - This url will be triggered when an issue is created/updated/merged - %div - = f.check_box :merge_requests_events, class: 'pull-left' - .prepend-left-20 - = f.label :merge_requests_events, class: 'list-label' do - %strong Merge Request events - %p.light - This url will be triggered when a merge request is created/updated/merged - %div - = f.check_box :build_events, class: 'pull-left' - .prepend-left-20 - = f.label :build_events, class: 'list-label' do - %strong Build events - %p.light - This url will be triggered when the build status changes - .form-group - = f.label :enable_ssl_verification, "SSL verification", class: 'control-label checkbox' - .col-sm-10 - .checkbox - = f.label :enable_ssl_verification do - = f.check_box :enable_ssl_verification - %strong Enable SSL verification - .form-actions - = f.submit "Add Webhook", class: "btn btn-create" - --if @hooks.any? - .panel.panel-default - .panel-heading + .form-group + = f.label :url, "URL", class: "label-light" + = f.text_field :url, class: "form-control", placeholder: "http://example.com/trigger-ci.json" + .form-group + = f.label :url, "Trigger", class: "label-light" + %div + = f.check_box :push_events, class: "pull-left" + .prepend-left-20 + = f.label :push_events, class: "label-light append-bottom-0" do + Push events + %p.light + This url will be triggered by a push to the repository + %div + = f.check_box :tag_push_events, class: "pull-left" + .prepend-left-20 + = f.label :tag_push_events, class: "label-light append-bottom-0" do + Tag push events + %p.light + This url will be triggered when a new tag is pushed to the repository + %div + = f.check_box :note_events, class: "pull-left" + .prepend-left-20 + = f.label :note_events, class: "label-light append-bottom-0" do + Comments + %p.light + This url will be triggered when someone adds a comment + %div + = f.check_box :issues_events, class: "pull-left" + .prepend-left-20 + = f.label :issues_events, class: "label-light append-bottom-0" do + Issues events + %p.light + This url will be triggered when an issue is created/updated/merged + %div + = f.check_box :merge_requests_events, class: "pull-left" + .prepend-left-20 + = f.label :merge_requests_events, class: "label-light append-bottom-0" do + Merge Request events + %p.light + This url will be triggered when a merge request is created/updated/merged + %div + = f.check_box :build_events, class: "pull-left" + .prepend-left-20 + = f.label :build_events, class: "label-light append-bottom-0" do + Build events + %p.light + This url will be triggered when the build status changes + .form-group + = f.label :enable_ssl_verification, "SSL verification", class: "label-light" + %div + = f.check_box :enable_ssl_verification, class: "pull-left" + .prepend-left-20 + = f.label :enable_ssl_verification, class: "label-light append-bottom-0" do + Enable SSL verification + = f.submit "Add Webhook", class: "btn btn-create" + %hr + %h5.prepend-top-default Webhooks (#{@hooks.count}) - %ul.content-list - - @hooks.each do |hook| - %li - .controls - = link_to 'Test Hook', test_namespace_project_hook_path(@project.namespace, @project, hook), class: "btn btn-sm btn-grouped" - = link_to 'Remove', namespace_project_hook_path(@project.namespace, @project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-sm btn-grouped" - .monospace= hook.url - %div - - %w(push_events tag_push_events issues_events note_events merge_requests_events build_events).each do |trigger| - - if hook.send(trigger) - %span.label.label-gray= trigger.titleize - %span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"} + - if @hooks.any? + %ul.well-list + - @hooks.each do |hook| + = render "project_hook", hook: hook + - else + %p.profile-settings-message.text-center.append-bottom-0 + No webhooks found, add one in the form above. -- cgit v1.2.1 From 3c0ab15a744835889934f4399908d6dd49ecab62 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 26 Apr 2016 13:35:52 +0200 Subject: Do not fsck projects less than a day old This should bring the number of false positives down. --- app/workers/repository_check/batch_worker.rb | 4 ++-- spec/workers/repository_check/batch_worker_spec.rb | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/workers/repository_check/batch_worker.rb b/app/workers/repository_check/batch_worker.rb index 44b3145d50f..a3e16fa5212 100644 --- a/app/workers/repository_check/batch_worker.rb +++ b/app/workers/repository_check/batch_worker.rb @@ -33,8 +33,8 @@ module RepositoryCheck # has to sit and wait for this query to finish. def project_ids limit = 10_000 - never_checked_projects = Project.where('last_repository_check_at IS NULL').limit(limit). - pluck(:id) + never_checked_projects = Project.where('last_repository_check_at IS NULL AND created_at < ?', 24.hours.ago). + limit(limit).pluck(:id) old_check_projects = Project.where('last_repository_check_at < ?', 1.month.ago). reorder('last_repository_check_at ASC').limit(limit).pluck(:id) never_checked_projects + old_check_projects diff --git a/spec/workers/repository_check/batch_worker_spec.rb b/spec/workers/repository_check/batch_worker_spec.rb index f486e45ddad..27727d6abf9 100644 --- a/spec/workers/repository_check/batch_worker_spec.rb +++ b/spec/workers/repository_check/batch_worker_spec.rb @@ -4,7 +4,7 @@ describe RepositoryCheck::BatchWorker do subject { described_class.new } it 'prefers projects that have never been checked' do - projects = create_list(:project, 3) + projects = create_list(:project, 3, created_at: 1.week.ago) projects[0].update_column(:last_repository_check_at, 4.months.ago) projects[2].update_column(:last_repository_check_at, 3.months.ago) @@ -12,7 +12,7 @@ describe RepositoryCheck::BatchWorker do end it 'sorts projects by last_repository_check_at' do - projects = create_list(:project, 3) + projects = create_list(:project, 3, created_at: 1.week.ago) projects[0].update_column(:last_repository_check_at, 2.months.ago) projects[1].update_column(:last_repository_check_at, 4.months.ago) projects[2].update_column(:last_repository_check_at, 3.months.ago) @@ -21,7 +21,7 @@ describe RepositoryCheck::BatchWorker do end it 'excludes projects that were checked recently' do - projects = create_list(:project, 3) + projects = create_list(:project, 3, created_at: 1.week.ago) projects[0].update_column(:last_repository_check_at, 2.days.ago) projects[1].update_column(:last_repository_check_at, 2.months.ago) projects[2].update_column(:last_repository_check_at, 3.days.ago) @@ -30,10 +30,17 @@ describe RepositoryCheck::BatchWorker do end it 'does nothing when repository checks are disabled' do - create(:empty_project) + create(:empty_project, created_at: 1.week.ago) current_settings = double('settings', repository_checks_enabled: false) expect(subject).to receive(:current_settings) { current_settings } expect(subject.perform).to eq(nil) end + + it 'skips projects created less than 24 hours ago' do + project = create(:empty_project) + project.update_column(:created_at, 23.hours.ago) + + expect(subject.perform).to eq([]) + end end -- cgit v1.2.1 From b651303ea63874e7cc9428c09770bee138cc68ec Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 26 Apr 2016 14:14:34 +0100 Subject: Updated tests --- features/steps/project/hooks.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/steps/project/hooks.rb b/features/steps/project/hooks.rb index 4994df589a7..b1ffe7f7b4c 100644 --- a/features/steps/project/hooks.rb +++ b/features/steps/project/hooks.rb @@ -48,12 +48,12 @@ class Spinach::Features::ProjectHooks < Spinach::FeatureSteps step 'I click test hook button' do stub_request(:post, @hook.url).to_return(status: 200) - click_link 'Test Hook' + click_link 'Test' end step 'I click test hook button with invalid URL' do stub_request(:post, @hook.url).to_raise(SocketError) - click_link 'Test Hook' + click_link 'Test' end step 'hook should be triggered' do -- cgit v1.2.1 From cdf91da3ebb2ca8795ea88365792333a957e6cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 26 Apr 2016 15:46:06 +0200 Subject: Sidekiq MemoryKiller sends a `SIGKILL` signal, not `SIGTERM` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ci skip] Signed-off-by: Rémy Coutable --- doc/operations/sidekiq_memory_killer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/operations/sidekiq_memory_killer.md b/doc/operations/sidekiq_memory_killer.md index 811c2192a19..b5e78348989 100644 --- a/doc/operations/sidekiq_memory_killer.md +++ b/doc/operations/sidekiq_memory_killer.md @@ -36,5 +36,5 @@ The MemoryKiller is controlled using environment variables. Existing jobs get 30 seconds to finish. After that, the MemoryKiller tells Sidekiq to shut down, and an external supervision mechanism (e.g. Runit) must restart Sidekiq. -- `SIDEKIQ_MEMORY_KILLER_SHUTDOWN_SIGNAL`: defaults to 'SIGTERM'. The name of +- `SIDEKIQ_MEMORY_KILLER_SHUTDOWN_SIGNAL`: defaults to `SIGKILL`. The name of the final signal sent to the Sidekiq process when we want it to shut down. -- cgit v1.2.1 From 40b0afddbf3cb66462893b7c5c7f09204d59d60a Mon Sep 17 00:00:00 2001 From: Karlo Soriano Date: Tue, 26 Apr 2016 21:54:40 +0800 Subject: Add JS prefix to user tab classes I'm not entirely sure if this project uses the `js-` prefix for classes that are for js purposes only. But as I was working on a feature, I noticed that these classes were those kind of classes. --- app/assets/javascripts/user_tabs.js.coffee | 2 +- app/views/users/show.html.haml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/user_tabs.js.coffee b/app/assets/javascripts/user_tabs.js.coffee index 09b7eec9104..c2aeffe2381 100644 --- a/app/assets/javascripts/user_tabs.js.coffee +++ b/app/assets/javascripts/user_tabs.js.coffee @@ -92,7 +92,7 @@ class @UserTabs @setCurrentAction(action) activateTab: (action) -> - @parentEl.find(".nav-links .#{action}-tab a").tab('show') + @parentEl.find(".nav-links .js-#{action}-tab a").tab('show') setTab: (source, action) -> return if @loaded[action] is true diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 3028491e5b6..0dff27f9654 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -69,13 +69,13 @@ = @user.location %ul.nav-links.center.user-profile-nav - %li.activity-tab + %li.js-activity-tab = link_to user_calendar_activities_path, data: {target: 'div#activity', action: 'activity', toggle: 'tab'} do Activity - %li.groups-tab + %li.js-groups-tab = link_to user_groups_path, data: {target: 'div#groups', action: 'groups', toggle: 'tab'} do Groups - %li.contributed-tab + %li.js-contributed-tab = link_to user_contributed_projects_path, data: {target: 'div#contributed', action: 'contributed', toggle: 'tab'} do Contributed projects %li.projects-tab -- cgit v1.2.1 From a3d6b61063b8a3864ba9823166fa08fdeeb9d2d9 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 26 Apr 2016 15:50:31 +0100 Subject: Protected branches UI Closes #14027 --- app/assets/stylesheets/framework/common.scss | 1 + app/assets/stylesheets/framework/typography.scss | 4 ++ app/assets/stylesheets/pages/projects.scss | 17 ++++--- .../protected_branches/_branches_list.html.haml | 56 +++++++++++---------- .../projects/protected_branches/index.html.haml | 58 +++++++++++----------- 5 files changed, 77 insertions(+), 59 deletions(-) diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 2ade341c9dd..3386523dbf7 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -11,6 +11,7 @@ .prepend-top-10 { margin-top: 10px } .prepend-top-default { margin-top: $gl-padding !important; } .prepend-top-20 { margin-top: 20px } +.prepend-left-5 { margin-left: 5px } .prepend-left-10 { margin-left: 10px } .prepend-left-default { margin-left: $gl-padding; } .prepend-left-20 { margin-left: 20px } diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index 0a5b4b8834c..64b1c247386 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -205,6 +205,10 @@ h1, h2, h3, h4, h5, h6 { font-weight: 600; } +.light-header { + font-weight: 600; +} + /** CODE **/ pre { font-family: $monospace_font; diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index fcca9d4faf5..0dd44cdc14e 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -256,12 +256,6 @@ } } -table.table.protected-branches-list tr.no-border { - th, td { - border: 0; - } -} - .project-import .btn { float: left; margin-right: 10px; @@ -474,3 +468,14 @@ pre.light-well { color: #fff; } } + +.protected-branches-list { + a { + color: $gl-gray; + font-weight: 600; + + &:hover { + color: $gl-link-color; + } + } +} diff --git a/app/views/projects/protected_branches/_branches_list.html.haml b/app/views/projects/protected_branches/_branches_list.html.haml index f68449b1863..b9e9dd8aaea 100644 --- a/app/views/projects/protected_branches/_branches_list.html.haml +++ b/app/views/projects/protected_branches/_branches_list.html.haml @@ -1,35 +1,41 @@ -- unless @branches.empty? - %br - %h4 Already Protected: - .table-holder +%h5.prepend-top-0 + Already Protected (#{@branches.size}) +- if @branches.empty? + %p.profile-settings-message.text-center + No branches are protected, protect a branch with the form above. +- else + - can_admin_project = can?(current_user, :admin_project, @project) + .table-responsive %table.table.protected-branches-list + %colgroup + %col{ width: "30%" } + %col{ width: "30%" } + %col{ width: "25%" } + - if can_admin_project + %col %thead - %tr.no-border + %tr %th Branch - %th Developers can push %th Last commit - %th - + %th Developers can push + - if can_admin_project + %th %tbody - @branches.each do |branch| - @url = namespace_project_protected_branch_path(@project.namespace, @project, branch) %tr %td - = link_to namespace_project_commits_path(@project.namespace, @project, branch.name) do - %strong= branch.name - - if @project.root_ref?(branch.name) - %span.label.label-info default - %td - = check_box_tag "developers_can_push", branch.id, branch.developers_can_push, "data-url" => @url - %td - - if commit = branch.commit - = link_to namespace_project_commit_path(@project.namespace, @project, commit.id), class: 'commit_short_id' do - = commit.short_id - · - #{time_ago_with_tooltip(commit.committed_date)} - - else - (branch was removed from repository) + = link_to(branch.name, namespace_project_commits_path(@project.namespace, @project, branch.name)) + - if @project.root_ref?(branch.name) + %span.label.label-info.prepend-left-5 default + %td + - if commit = branch.commit + = link_to(commit.short_id, namespace_project_commit_path(@project.namespace, @project, commit.id), class: 'commit_short_id') + #{time_ago_with_tooltip(commit.committed_date)} + - else + (branch was removed from repository) + %td + = check_box_tag("developers_can_push", branch.id, branch.developers_can_push, data: { url: @url }) + - if can_admin_project %td - .pull-right - - if can? current_user, :admin_project, @project - = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-remove btn-sm" + = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-warning btn-sm" diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml index 653b02da4db..c7d317dbaee 100644 --- a/app/views/projects/protected_branches/index.html.haml +++ b/app/views/projects/protected_branches/index.html.haml @@ -1,31 +1,33 @@ - page_title "Protected branches" -%h3.page-title Protected branches -%p.light Keep stable branches secure and force developers to use Merge Requests -%hr -.well - %p Protected branches are designed to - %ul - %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 Read more about #{link_to "project permissions", help_page_path("permissions", "permissions"), class: "underlined-link"} +.row.prepend-top-default.append-bottom-default + .col-lg-3 + %h4.prepend-top-0 + = page_title + %p Keep stable branches secure and force developers to use Merge Requests + .col-lg-9 + %h5.prepend-top-0 + Protect a branch + .account-well.append-bottom-default + %p.light-header.append-bottom-0 Protected branches are designed to + %ul + %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"} + - if can? current_user, :admin_project, @project + = form_for [@project.namespace.becomes(Namespace), @project, @protected_branch] do |f| + = form_errors(@protected_branch) -- if can? current_user, :admin_project, @project - = form_for [@project.namespace.becomes(Namespace), @project, @protected_branch], html: { class: 'form-horizontal' } do |f| - = form_errors(@protected_branch) - - .form-group - = f.label :name, "Branch", class: 'control-label' - .col-sm-10 - = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: true}, {class: "select2", data: {placeholder: "Select branch"}}) - .form-group - .col-sm-offset-2.col-sm-10 - .checkbox - = f.label :developers_can_push do - = f.check_box :developers_can_push - %strong Developers can push - .help-block Allow developers to push to this branch - .form-actions - = f.submit 'Protect', class: "btn-create btn" -= render 'branches_list' + .form-group + = f.label :name, "Branch", class: "label-light" + = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: true}, {class: "select2", data: {placeholder: "Select branch"}}) + .form-group + = f.check_box :developers_can_push, class: "pull-left" + .prepend-left-20 + = 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 + = f.submit "Protect", class: "btn-create btn" + %hr + = render "branches_list" -- cgit v1.2.1 From 9f85b7bc58485831a61da0f9acc530511ea7474a Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 26 Apr 2016 16:56:14 +0200 Subject: Initialize wikis on legacy projects during check --- .../repository_check/single_repository_worker.rb | 34 +++++++++++++++------- .../single_repository_worker_spec.rb | 33 +++++++++++++++++---- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/app/workers/repository_check/single_repository_worker.rb b/app/workers/repository_check/single_repository_worker.rb index a76729e3c74..f2d12ba5a7d 100644 --- a/app/workers/repository_check/single_repository_worker.rb +++ b/app/workers/repository_check/single_repository_worker.rb @@ -1,9 +1,9 @@ module RepositoryCheck class SingleRepositoryWorker include Sidekiq::Worker - + sidekiq_options retry: false - + def perform(project_id) project = Project.find(project_id) project.update_columns( @@ -11,20 +11,32 @@ module RepositoryCheck last_repository_check_at: Time.now, ) end - + private - + def check(project) - repositories = [project.repository] - repositories << project.wiki.repository if project.wiki_enabled? - # Use 'map do', not 'all? do', to prevent short-circuiting - repositories.map { |repository| git_fsck(repository.path_to_repo) }.all? + if !git_fsck(project.repository) + false + elsif project.wiki_enabled? + # Historically some projects never had their wiki repos initialized; + # this happens on project creation now. Let's initialize an empty repo + # if it is not already there. + begin + project.create_wiki + rescue Rugged::RepositoryError + end + + git_fsck(project.wiki.repository) + else + true + end end - - def git_fsck(path) + + def git_fsck(repository) + path = repository.path_to_repo cmd = %W(nice git --git-dir=#{path} fsck) output, status = Gitlab::Popen.popen(cmd) - + if status.zero? true else diff --git a/spec/workers/repository_check/single_repository_worker_spec.rb b/spec/workers/repository_check/single_repository_worker_spec.rb index 087e4c667d8..5a03bb77ebd 100644 --- a/spec/workers/repository_check/single_repository_worker_spec.rb +++ b/spec/workers/repository_check/single_repository_worker_spec.rb @@ -12,7 +12,7 @@ describe RepositoryCheck::SingleRepositoryWorker do subject.perform(project.id) expect(project.reload.last_repository_check_failed).to eq(false) - destroy_wiki(project) + break_wiki(project) subject.perform(project.id) expect(project.reload.last_repository_check_failed).to eq(true) @@ -20,15 +20,38 @@ describe RepositoryCheck::SingleRepositoryWorker do it 'skips wikis when disabled' do project = create(:project_empty_repo, wiki_enabled: false) - # Make sure the test would fail if it checked the wiki repo - destroy_wiki(project) + # Make sure the test would fail if the wiki repo was checked + break_wiki(project) subject.perform(project.id) expect(project.reload.last_repository_check_failed).to eq(false) end - def destroy_wiki(project) - FileUtils.rm_rf(project.wiki.repository.path_to_repo) + it 'creates missing wikis' do + project = create(:project_empty_repo, wiki_enabled: true) + FileUtils.rm_rf(wiki_path(project)) + + subject.perform(project.id) + + expect(project.reload.last_repository_check_failed).to eq(false) + end + + it 'does not create a wiki if the main repo does not exist at all' do + project = create(:project_empty_repo) + FileUtils.rm_rf(project.repository.path_to_repo) + FileUtils.rm_rf(wiki_path(project)) + + subject.perform(project.id) + + expect(File.exist?(wiki_path(project))).to eq(false) + end + + def break_wiki(project) + FileUtils.rm_rf(wiki_path(project) + '/objects') + end + + def wiki_path(project) + project.wiki.repository.path_to_repo end end -- cgit v1.2.1 From 1cc614f2bdd30b4fce35ee9e680f9272b9012978 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Sun, 24 Apr 2016 17:33:54 -0600 Subject: Remove the Devise Async gem. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The extra gem isn’t necessary anymore since Rails 4.2 has ActiveJob integration. Resolves #15575. --- CHANGELOG | 1 + Gemfile | 1 - Gemfile.lock | 3 --- app/models/user.rb | 2 +- config/initializers/devise_async.rb | 1 - 5 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 config/initializers/devise_async.rb diff --git a/CHANGELOG b/CHANGELOG index 558897ad892..2be50c5bb11 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ v 8.8.0 (unreleased) - Fix error when visiting commit builds page before build was updated - Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project - Updated search UI + - Replace Devise Async with Devise ActiveJob integration. !3902 (Connor Shea) v 8.7.1 (unreleased) - Throttle the update of `project.last_activity_at` to 1 minute. !3848 diff --git a/Gemfile b/Gemfile index 6e15da8dc6a..5dd27e24306 100644 --- a/Gemfile +++ b/Gemfile @@ -19,7 +19,6 @@ gem "pg", '~> 0.18.2', group: :postgres # Authentication libraries gem 'devise', '~> 3.5.4' -gem 'devise-async', '~> 0.9.0' gem 'doorkeeper', '~> 2.2.0' gem 'omniauth', '~> 1.3.1' gem 'omniauth-auth0', '~> 1.4.1' diff --git a/Gemfile.lock b/Gemfile.lock index 679c52eff25..c3c52eebbfa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -164,8 +164,6 @@ GEM responders thread_safe (~> 0.1) warden (~> 1.2.3) - devise-async (0.9.0) - devise (~> 3.2) devise-two-factor (2.0.1) activesupport attr_encrypted (~> 1.3.2) @@ -918,7 +916,6 @@ DEPENDENCIES database_cleaner (~> 1.4.0) default_value_for (~> 3.0.0) devise (~> 3.5.4) - devise-async (~> 0.9.0) devise-two-factor (~> 2.0.0) diffy (~> 3.0.3) doorkeeper (~> 2.2.0) diff --git a/app/models/user.rb b/app/models/user.rb index ab48f8f1960..b6f405c6981 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -91,7 +91,7 @@ class User < ActiveRecord::Base devise :two_factor_backupable, otp_number_of_backup_codes: 10 serialize :otp_backup_codes, JSON - devise :lockable, :async, :recoverable, :rememberable, :trackable, + devise :lockable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :confirmable, :registerable attr_accessor :force_random_password diff --git a/config/initializers/devise_async.rb b/config/initializers/devise_async.rb deleted file mode 100644 index 05a1852cdbd..00000000000 --- a/config/initializers/devise_async.rb +++ /dev/null @@ -1 +0,0 @@ -Devise::Async.backend = :sidekiq -- cgit v1.2.1 From c402aeef027b73b71ad3ca49f79bc2aa6d47b97d Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Sat, 16 Apr 2016 16:13:59 -0600 Subject: Allow alternative names for the CHANGELOG file. "CHANGELOG", "NEWS", "HISTORY", and "CHANGES" are recognized as Changelog files. Also adds relevant tests for each of these names. Resolves #14864. --- CHANGELOG | 1 + app/models/repository.rb | 2 +- spec/models/repository_spec.rb | 38 +++++++++++++++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2be50c5bb11..af259b67d50 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ v 8.8.0 (unreleased) - Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project - Updated search UI - Replace Devise Async with Devise ActiveJob integration. !3902 (Connor Shea) + - Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea) v 8.7.1 (unreleased) - Throttle the update of `project.last_activity_at` to 1 minute. !3848 diff --git a/app/models/repository.rb b/app/models/repository.rb index 61c8dce6060..d495c8d18f5 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -457,7 +457,7 @@ class Repository def changelog cache.fetch(:changelog) do tree(:head).blobs.find do |file| - file.name =~ /\A(changelog|history)/i + file.name =~ /\A(changelog|history|changes|news)/i end end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index c19524a01f8..a306cc4aef8 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -134,7 +134,43 @@ describe Repository, models: true do end end - describe '#license_blob' do + describe "#changelog" do + before do + repository.send(:cache).expire(:changelog) + end + + it 'accepts changelog' do + expect(repository.tree).to receive(:blobs).and_return([TestBlob.new('changelog')]) + + expect(repository.changelog.name).to eq('changelog') + end + + it 'accepts news instead of changelog' do + expect(repository.tree).to receive(:blobs).and_return([TestBlob.new('news')]) + + expect(repository.changelog.name).to eq('news') + end + + it 'accepts history instead of changelog' do + expect(repository.tree).to receive(:blobs).and_return([TestBlob.new('history')]) + + expect(repository.changelog.name).to eq('history') + end + + it 'accepts changes instead of changelog' do + expect(repository.tree).to receive(:blobs).and_return([TestBlob.new('changes')]) + + expect(repository.changelog.name).to eq('changes') + end + + it 'is case-insensitive' do + expect(repository.tree).to receive(:blobs).and_return([TestBlob.new('CHANGELOG')]) + + expect(repository.changelog.name).to eq('CHANGELOG') + end + end + + describe "#license_blob" do before do repository.send(:cache).expire(:license_blob) repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'master') -- cgit v1.2.1 From be67a4843cc37790402404650cb96a6f02552b54 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 26 Apr 2016 12:55:38 -0400 Subject: Prevent privilege escalation via notes API Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/15577 --- app/services/notes/create_service.rb | 11 ++++++++++ spec/requests/api/notes_spec.rb | 41 +++++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb index 2bb312bb252..01586994813 100644 --- a/app/services/notes/create_service.rb +++ b/app/services/notes/create_service.rb @@ -5,6 +5,8 @@ module Notes note.author = current_user note.system = false + return unless valid_project?(note) + if note.save # Finish the harder work in the background NewNoteWorker.perform_in(2.seconds, note.id, params) @@ -13,5 +15,14 @@ module Notes note end + + private + + def valid_project?(note) + return false unless project + return true if note.for_commit? + + note.noteable.try(:project) == project + end end end diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index ec9eda0a2ed..49091fc0f49 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::API, api: true do include ApiHelpers let(:user) { create(:user) } - let!(:project) { create(:project, namespace: user.namespace ) } + let!(:project) { create(:project, namespace: user.namespace) } let!(:issue) { create(:issue, project: project, author: user) } let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) } let!(:snippet) { create(:project_snippet, project: project, author: user) } @@ -45,7 +45,7 @@ describe API::API, api: true do end it "should return a 404 error when issue id not found" do - get api("/projects/#{project.id}/issues/123/notes", user) + get api("/projects/#{project.id}/issues/12345/notes", user) expect(response.status).to eq(404) end @@ -106,7 +106,7 @@ describe API::API, api: true do end it "should return a 404 error if issue note not found" do - get api("/projects/#{project.id}/issues/#{issue.id}/notes/123", user) + get api("/projects/#{project.id}/issues/#{issue.id}/notes/12345", user) expect(response.status).to eq(404) end @@ -134,7 +134,7 @@ describe API::API, api: true do end it "should return a 404 error if snippet note not found" do - get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/123", user) + get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/12345", user) expect(response.status).to eq(404) end end @@ -191,6 +191,27 @@ describe API::API, api: true do expect(response.status).to eq(401) end end + + context 'when user does not have access to create noteable' do + let(:private_issue) { create(:issue, project: create(:project, :private)) } + + ## + # We are posting to project user has access to, but we use issue id + # from a different project, see #15577 + # + before do + post api("/projects/#{project.id}/issues/#{private_issue.id}/notes", user), + body: 'Hi!' + end + + it 'responds with 500' do + expect(response.status).to eq 500 + end + + it 'does not create new note' do + expect(private_issue.notes.reload).to be_empty + end + end end describe "POST /projects/:id/noteable/:noteable_id/notes to test observer on create" do @@ -211,7 +232,7 @@ describe API::API, api: true do end it 'should return a 404 error when note id not found' do - put api("/projects/#{project.id}/issues/#{issue.id}/notes/123", user), + put api("/projects/#{project.id}/issues/#{issue.id}/notes/12345", user), body: 'Hello!' expect(response.status).to eq(404) end @@ -233,7 +254,7 @@ describe API::API, api: true do it 'should return a 404 error when note id not found' do put api("/projects/#{project.id}/snippets/#{snippet.id}/"\ - "notes/123", user), body: "Hello!" + "notes/12345", user), body: "Hello!" expect(response.status).to eq(404) end end @@ -248,7 +269,7 @@ describe API::API, api: true do it 'should return a 404 error when note id not found' do put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/"\ - "notes/123", user), body: "Hello!" + "notes/12345", user), body: "Hello!" expect(response.status).to eq(404) end end @@ -268,7 +289,7 @@ describe API::API, api: true do end it 'returns a 404 error when note id not found' do - delete api("/projects/#{project.id}/issues/#{issue.id}/notes/123", user) + delete api("/projects/#{project.id}/issues/#{issue.id}/notes/12345", user) expect(response.status).to eq(404) end @@ -288,7 +309,7 @@ describe API::API, api: true do it 'returns a 404 error when note id not found' do delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\ - "notes/123", user) + "notes/12345", user) expect(response.status).to eq(404) end @@ -308,7 +329,7 @@ describe API::API, api: true do it 'returns a 404 error when note id not found' do delete api("/projects/#{project.id}/merge_requests/"\ - "#{merge_request.id}/notes/123", user) + "#{merge_request.id}/notes/12345", user) expect(response.status).to eq(404) end -- cgit v1.2.1 From d8d00b5bc29f7b89f95c436cd6900d1548f111b7 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Wed, 23 Mar 2016 11:10:17 -0500 Subject: Add Hide/show whitespace changes button on diff and commit view --- app/helpers/diff_helper.rb | 22 ++++++++++++++++++++++ app/views/projects/diffs/_diffs.html.haml | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 97466d532f4..eca4ba695a1 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -128,4 +128,26 @@ module DiffHelper title end end + + def hide_whitespaces? + params[:w] == '1' + end + + def params_with_whitespace + hide_whitespaces? ? request.query_parameters.except(:w) : request.query_parameters.merge(w: 1) + end + + def toggle_whitespace_link(url) + link_to "#{hide_whitespaces? ? 'Show' : 'Hide'} whitespace changes", url, class: "btn btn-default" + end + + def commit_diff_whitespace_link(project, commit) + url = namespace_project_commit_path(project.namespace, project, commit.id, params_with_whitespace) + toggle_whitespace_link(url) + end + + def diff_merge_request_whitespace_link(project, merge_request) + url = diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, params_with_whitespace) + toggle_whitespace_link(url) + end end diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index eaab99973a4..fbfff9bc895 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -5,6 +5,10 @@ .content-block.oneline-block.files-changed .inline-parallel-buttons + - if current_controller?(:commit) + = commit_diff_whitespace_link(@project, @commit) + - if current_controller?(:merge_requests) + = diff_merge_request_whitespace_link(@project, @merge_request) .btn-group = inline_diff_btn = parallel_diff_btn -- cgit v1.2.1 From f0bdf5c692fbfe7623eda509f17fe34f7424f141 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Tue, 29 Mar 2016 16:13:39 -0500 Subject: Hide whitespace toggle button for new merge requests --- app/views/projects/diffs/_diffs.html.haml | 10 ++++++---- app/views/projects/merge_requests/_new_submit.html.haml | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index fbfff9bc895..6d2b85ed994 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -1,3 +1,4 @@ +- show_whitespace_toggle = local_assigns.fetch :show_whitespace_toggle, true - if diff_view == 'parallel' - fluid_layout true @@ -5,10 +6,11 @@ .content-block.oneline-block.files-changed .inline-parallel-buttons - - if current_controller?(:commit) - = commit_diff_whitespace_link(@project, @commit) - - if current_controller?(:merge_requests) - = diff_merge_request_whitespace_link(@project, @merge_request) + - if show_whitespace_toggle + - if current_controller?(:commit) + = commit_diff_whitespace_link(@project, @commit) + - if current_controller?(:merge_requests) + = diff_merge_request_whitespace_link(@project, @merge_request) .btn-group = inline_diff_btn = parallel_diff_btn diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml index 2f14a91e64f..18b3f9e1549 100644 --- a/app/views/projects/merge_requests/_new_submit.html.haml +++ b/app/views/projects/merge_requests/_new_submit.html.haml @@ -42,7 +42,7 @@ %h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits. %p To preserve performance the line changes are not shown. - else - = render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @merge_request.diff_refs + = render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @merge_request.diff_refs, show_whitespace_toggle: false - if @ci_commit #builds.builds.tab-pane = render "projects/merge_requests/show/builds" -- cgit v1.2.1 From 473591403197c0b0fd985f4f01d59e6e31b57a60 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 4 Apr 2016 11:35:56 -0500 Subject: Update syntax --- app/views/projects/diffs/_diffs.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index 6d2b85ed994..22adebd91e5 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -1,4 +1,4 @@ -- show_whitespace_toggle = local_assigns.fetch :show_whitespace_toggle, true +- show_whitespace_toggle = local_assigns.fetch(:show_whitespace_toggle, true) - if diff_view == 'parallel' - fluid_layout true @@ -9,7 +9,7 @@ - if show_whitespace_toggle - if current_controller?(:commit) = commit_diff_whitespace_link(@project, @commit) - - if current_controller?(:merge_requests) + - elsif current_controller?(:merge_requests) = diff_merge_request_whitespace_link(@project, @merge_request) .btn-group = inline_diff_btn -- cgit v1.2.1 From 64c2d9bd3ce5c3151dd14be01916a4a72a4abc55 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 4 Apr 2016 11:45:21 -0500 Subject: Use new method hide_whitespaces? --- app/helpers/diff_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index eca4ba695a1..2f80dc5ccc0 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -23,7 +23,7 @@ module DiffHelper end def diff_options - options = { ignore_whitespace_change: params[:w] == '1' } + options = { ignore_whitespace_change: hide_whitespaces? } if diff_hard_limit_enabled? options.merge!(Commit.max_diff_options) end -- cgit v1.2.1 From 66a5d0fd266075f0362bb3ec9dea1a584d7c5c5f Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 4 Apr 2016 12:01:59 -0500 Subject: Rename method --- app/helpers/diff_helper.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 2f80dc5ccc0..06e5b95297e 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -23,7 +23,7 @@ module DiffHelper end def diff_options - options = { ignore_whitespace_change: hide_whitespaces? } + options = { ignore_whitespace_change: hide_whitespace? } if diff_hard_limit_enabled? options.merge!(Commit.max_diff_options) end @@ -129,16 +129,16 @@ module DiffHelper end end - def hide_whitespaces? + def hide_whitespace? params[:w] == '1' end def params_with_whitespace - hide_whitespaces? ? request.query_parameters.except(:w) : request.query_parameters.merge(w: 1) + hide_whitespace? ? request.query_parameters.except(:w) : request.query_parameters.merge(w: 1) end def toggle_whitespace_link(url) - link_to "#{hide_whitespaces? ? 'Show' : 'Hide'} whitespace changes", url, class: "btn btn-default" + link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: "btn btn-default" end def commit_diff_whitespace_link(project, commit) -- cgit v1.2.1 From a1a9a1cf8d26fc85598eb982a78720282055a96f Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Tue, 5 Apr 2016 13:01:13 -0500 Subject: Specs for toggle Whitespaces Changes --- .../merge_requests/toggle_whitespace_changes.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 spec/features/merge_requests/toggle_whitespace_changes.rb diff --git a/spec/features/merge_requests/toggle_whitespace_changes.rb b/spec/features/merge_requests/toggle_whitespace_changes.rb new file mode 100644 index 00000000000..85b8d6975fc --- /dev/null +++ b/spec/features/merge_requests/toggle_whitespace_changes.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +feature 'Toggle Whitespace Changes', js: true, feature: true do + let(:merge_request) { create(:merge_request) } + let(:project) { merge_request.source_project } + + before do + login_as :admin + visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request) + end + + it 'should have a button to toggle whitespace changes' do + expect(page).to have_content "Hide whitespace changes" + end + + describe 'clicking hide whitespace changes button' do + it 'should hide whitespace changes' do + find('a', text: "Hide whitespace changes").click + expect(page).to have_content "Show whitespace changes" + end + end +end -- cgit v1.2.1 From 5d5df26ab1b65b094eaa2ca2ca6db49b6d8530ea Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Tue, 5 Apr 2016 16:09:49 -0500 Subject: Add documentation for "Hide whitespace changes" button --- doc/workflow/merge_requests.md | 6 +++--- doc/workflow/merge_requests/commit_compare.png | Bin 89631 -> 110376 bytes doc/workflow/merge_requests/merge_request_diff.png | Bin 120422 -> 166226 bytes .../merge_request_diff_without_whitespace.png | Bin 98887 -> 121476 bytes .../merge_requests/toggle_whitespace_changes.rb | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/workflow/merge_requests.md b/doc/workflow/merge_requests.md index 6d57b5d98cd..3a47838e977 100644 --- a/doc/workflow/merge_requests.md +++ b/doc/workflow/merge_requests.md @@ -12,9 +12,9 @@ Locate the section for your GitLab remote in the `.git/config` file. It looks li fetch = +refs/heads/*:refs/remotes/origin/* ``` -Now add the line `fetch = +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*` to this section. +Now add the line `fetch = +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*` to this section. -It should looks like this: +It should look like this: ``` [remote "origin"] @@ -43,7 +43,7 @@ $ git checkout origin/merge-requests/1 ![MR diff](merge_requests/merge_request_diff.png) -It you add `w=1` option to URL, you can see diff without whitespace changes. +If you click to "Hide whitespace changes" button, you can see diff without whitespace changes. ![MR diff without whitespace](merge_requests/merge_request_diff_without_whitespace.png) diff --git a/doc/workflow/merge_requests/commit_compare.png b/doc/workflow/merge_requests/commit_compare.png index 46b3a56a59b..dfd7ee220f0 100644 Binary files a/doc/workflow/merge_requests/commit_compare.png and b/doc/workflow/merge_requests/commit_compare.png differ diff --git a/doc/workflow/merge_requests/merge_request_diff.png b/doc/workflow/merge_requests/merge_request_diff.png index ed08ae91bec..f368423c746 100644 Binary files a/doc/workflow/merge_requests/merge_request_diff.png and b/doc/workflow/merge_requests/merge_request_diff.png differ diff --git a/doc/workflow/merge_requests/merge_request_diff_without_whitespace.png b/doc/workflow/merge_requests/merge_request_diff_without_whitespace.png index 67d67a64d12..b2d03bb66f9 100644 Binary files a/doc/workflow/merge_requests/merge_request_diff_without_whitespace.png and b/doc/workflow/merge_requests/merge_request_diff_without_whitespace.png differ diff --git a/spec/features/merge_requests/toggle_whitespace_changes.rb b/spec/features/merge_requests/toggle_whitespace_changes.rb index 85b8d6975fc..1d7981d9fb5 100644 --- a/spec/features/merge_requests/toggle_whitespace_changes.rb +++ b/spec/features/merge_requests/toggle_whitespace_changes.rb @@ -13,7 +13,7 @@ feature 'Toggle Whitespace Changes', js: true, feature: true do expect(page).to have_content "Hide whitespace changes" end - describe 'clicking hide whitespace changes button' do + describe 'clicking "Hide whitespace changes" button' do it 'should hide whitespace changes' do find('a', text: "Hide whitespace changes").click expect(page).to have_content "Show whitespace changes" -- cgit v1.2.1 From 89df29e09f1ed31e9d2b0b8c1791be41641da04d Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Thu, 7 Apr 2016 12:52:54 -0500 Subject: Use click_link --- spec/features/merge_requests/toggle_whitespace_changes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/merge_requests/toggle_whitespace_changes.rb b/spec/features/merge_requests/toggle_whitespace_changes.rb index 1d7981d9fb5..a3c02e6c55a 100644 --- a/spec/features/merge_requests/toggle_whitespace_changes.rb +++ b/spec/features/merge_requests/toggle_whitespace_changes.rb @@ -15,7 +15,7 @@ feature 'Toggle Whitespace Changes', js: true, feature: true do describe 'clicking "Hide whitespace changes" button' do it 'should hide whitespace changes' do - find('a', text: "Hide whitespace changes").click + click_link "Hide whitespace changes" expect(page).to have_content "Show whitespace changes" end end -- cgit v1.2.1 From 0392dffdb64ff70f299a1f41c6a68c202bfb8068 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Thu, 7 Apr 2016 12:57:51 -0500 Subject: Update wording --- doc/workflow/merge_requests.md | 2 +- spec/features/merge_requests/toggle_whitespace_changes.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/workflow/merge_requests.md b/doc/workflow/merge_requests.md index 3a47838e977..1b5718c91c1 100644 --- a/doc/workflow/merge_requests.md +++ b/doc/workflow/merge_requests.md @@ -43,7 +43,7 @@ $ git checkout origin/merge-requests/1 ![MR diff](merge_requests/merge_request_diff.png) -If you click to "Hide whitespace changes" button, you can see diff without whitespace changes. +If you click the "Hide whitespace changes" button, you can see the diff without whitespace changes. ![MR diff without whitespace](merge_requests/merge_request_diff_without_whitespace.png) diff --git a/spec/features/merge_requests/toggle_whitespace_changes.rb b/spec/features/merge_requests/toggle_whitespace_changes.rb index a3c02e6c55a..cfae3fa131d 100644 --- a/spec/features/merge_requests/toggle_whitespace_changes.rb +++ b/spec/features/merge_requests/toggle_whitespace_changes.rb @@ -9,12 +9,12 @@ feature 'Toggle Whitespace Changes', js: true, feature: true do visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request) end - it 'should have a button to toggle whitespace changes' do + it 'has a button to toggle whitespace changes' do expect(page).to have_content "Hide whitespace changes" end describe 'clicking "Hide whitespace changes" button' do - it 'should hide whitespace changes' do + it 'toggles the "Hide whitespace changes" button' do click_link "Hide whitespace changes" expect(page).to have_content "Show whitespace changes" end -- cgit v1.2.1 From 7f263ca1de525e44bea1f97a22d95ad947848128 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Thu, 7 Apr 2016 13:15:28 -0500 Subject: Use variables instead of let --- spec/features/merge_requests/toggle_whitespace_changes.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/features/merge_requests/toggle_whitespace_changes.rb b/spec/features/merge_requests/toggle_whitespace_changes.rb index cfae3fa131d..bf4fd5289d1 100644 --- a/spec/features/merge_requests/toggle_whitespace_changes.rb +++ b/spec/features/merge_requests/toggle_whitespace_changes.rb @@ -1,11 +1,10 @@ require 'spec_helper' feature 'Toggle Whitespace Changes', js: true, feature: true do - let(:merge_request) { create(:merge_request) } - let(:project) { merge_request.source_project } - before do login_as :admin + merge_request = create(:merge_request) + project = merge_request.source_project visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request) end -- cgit v1.2.1 From 5ba79f49a45041f5a805de00a1f737ade5ac5832 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Tue, 12 Apr 2016 12:49:34 -0500 Subject: Syntax and code improvements --- app/helpers/diff_helper.rb | 24 ++++++++++++---------- .../merge_requests/toggle_whitespace_changes.rb | 7 ++++--- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 06e5b95297e..5c7317bdd40 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -129,6 +129,18 @@ module DiffHelper end end + def commit_diff_whitespace_link(project, commit) + url = namespace_project_commit_path(project.namespace, project, commit.id, params_with_whitespace) + toggle_whitespace_link(url) + end + + def diff_merge_request_whitespace_link(project, merge_request) + url = diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, params_with_whitespace) + toggle_whitespace_link(url) + end + + private + def hide_whitespace? params[:w] == '1' end @@ -138,16 +150,6 @@ module DiffHelper end def toggle_whitespace_link(url) - link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: "btn btn-default" - end - - def commit_diff_whitespace_link(project, commit) - url = namespace_project_commit_path(project.namespace, project, commit.id, params_with_whitespace) - toggle_whitespace_link(url) - end - - def diff_merge_request_whitespace_link(project, merge_request) - url = diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, params_with_whitespace) - toggle_whitespace_link(url) + link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: 'btn btn-default' end end diff --git a/spec/features/merge_requests/toggle_whitespace_changes.rb b/spec/features/merge_requests/toggle_whitespace_changes.rb index bf4fd5289d1..0f98737b700 100644 --- a/spec/features/merge_requests/toggle_whitespace_changes.rb +++ b/spec/features/merge_requests/toggle_whitespace_changes.rb @@ -9,13 +9,14 @@ feature 'Toggle Whitespace Changes', js: true, feature: true do end it 'has a button to toggle whitespace changes' do - expect(page).to have_content "Hide whitespace changes" + expect(page).to have_content 'Hide whitespace changes' end describe 'clicking "Hide whitespace changes" button' do it 'toggles the "Hide whitespace changes" button' do - click_link "Hide whitespace changes" - expect(page).to have_content "Show whitespace changes" + click_link 'Hide whitespace changes' + + expect(page).to have_content 'Show whitespace changes' end end end -- cgit v1.2.1 From b82af5ef2f5c496751411a4c1a1be0c9cacd19b4 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Tue, 12 Apr 2016 12:57:15 -0500 Subject: Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index af259b67d50..8dff81166c3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -137,6 +137,7 @@ v 8.6.7 - Fix persistent XSS vulnerability in `commit_person_link` helper - Fix persistent XSS vulnerability in Label and Milestone dropdowns - Fix vulnerability that made it possible to enumerate private projects belonging to group + - Added button to toggle whitespaces changes on diff view v 8.6.6 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 -- cgit v1.2.1 From 99296b2efdb92ddf484e27ea3b8af4b058ea5911 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 18 Apr 2016 16:45:14 -0500 Subject: Hide button on mobile --- app/helpers/diff_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 5c7317bdd40..d78b0b5a155 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -150,6 +150,6 @@ module DiffHelper end def toggle_whitespace_link(url) - link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: 'btn btn-default' + link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: 'btn btn-default hidden-xs' end end -- cgit v1.2.1 From 22bd7f4d83a255e3e23d3e421fbb1a56f0c67394 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 18 Apr 2016 16:51:30 -0500 Subject: Allow to pass custom classes to button --- app/helpers/diff_helper.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index d78b0b5a155..9f73edb4553 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -129,14 +129,14 @@ module DiffHelper end end - def commit_diff_whitespace_link(project, commit) + def commit_diff_whitespace_link(project, commit, options) url = namespace_project_commit_path(project.namespace, project, commit.id, params_with_whitespace) - toggle_whitespace_link(url) + toggle_whitespace_link(url, options) end - def diff_merge_request_whitespace_link(project, merge_request) + def diff_merge_request_whitespace_link(project, merge_request, options) url = diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, params_with_whitespace) - toggle_whitespace_link(url) + toggle_whitespace_link(url, options) end private @@ -149,7 +149,10 @@ module DiffHelper hide_whitespace? ? request.query_parameters.except(:w) : request.query_parameters.merge(w: 1) end - def toggle_whitespace_link(url) - link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: 'btn btn-default hidden-xs' + def toggle_whitespace_link(url, options) + options[:class] ||= '' + options[:class] << ' btn btn-default' + + link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: options[:class] end end -- cgit v1.2.1 From 4d6c40df9a928054e3d1c6d6c477f3a35fa950f6 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 18 Apr 2016 16:51:41 -0500 Subject: Hide button on mobile --- app/views/projects/diffs/_diffs.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index 22adebd91e5..d9c4b410d32 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -8,9 +8,9 @@ .inline-parallel-buttons - if show_whitespace_toggle - if current_controller?(:commit) - = commit_diff_whitespace_link(@project, @commit) + = commit_diff_whitespace_link(@project, @commit, class: 'hidden-xs') - elsif current_controller?(:merge_requests) - = diff_merge_request_whitespace_link(@project, @merge_request) + = diff_merge_request_whitespace_link(@project, @merge_request, class: 'hidden-xs') .btn-group = inline_diff_btn = parallel_diff_btn -- cgit v1.2.1 From c98b25f420cafd8a9abc7148035aff04f672b330 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 25 Apr 2016 14:18:36 -0500 Subject: Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 8dff81166c3..0df5bb2de58 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,7 @@ v 8.8.0 (unreleased) - Updated search UI - Replace Devise Async with Devise ActiveJob integration. !3902 (Connor Shea) - Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea) + - Added button to toggle whitespaces changes on diff view v 8.7.1 (unreleased) - Throttle the update of `project.last_activity_at` to 1 minute. !3848 -- cgit v1.2.1 From 19d8f6731a3e3912d880cfeacf0a82f5aea65f34 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Tue, 26 Apr 2016 18:58:11 +0000 Subject: Update CHANGELOG --- CHANGELOG | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 0df5bb2de58..e52e52691c2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -138,7 +138,6 @@ v 8.6.7 - Fix persistent XSS vulnerability in `commit_person_link` helper - Fix persistent XSS vulnerability in Label and Milestone dropdowns - Fix vulnerability that made it possible to enumerate private projects belonging to group - - Added button to toggle whitespaces changes on diff view v 8.6.6 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 -- cgit v1.2.1 From 0ace42cdb90161ee7daf69b7a6a7af6ce4195208 Mon Sep 17 00:00:00 2001 From: Jason Roehm Date: Tue, 26 Apr 2016 21:41:52 -0400 Subject: fix: in recent versions of Docker, the /.dockerinit file doesn't exist; use /.dockerenv instead [ci skip] Signed-off-by: Jason Roehm --- doc/ci/ssh_keys/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ci/ssh_keys/README.md b/doc/ci/ssh_keys/README.md index 7f825e6a065..7c0fb225dac 100644 --- a/doc/ci/ssh_keys/README.md +++ b/doc/ci/ssh_keys/README.md @@ -57,7 +57,7 @@ before_script: # WARNING: Use this only with the Docker executor, if you use it with shell # you will overwrite your user's SSH config. - mkdir -p ~/.ssh - - '[[ -f /.dockerinit ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' + - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' ``` As a final step, add the _public_ key from the one you created earlier to the -- cgit v1.2.1 From eede0323453190440a8d738b5eab0723f54dee65 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 22 Apr 2016 12:43:10 -0700 Subject: Backport GitHub Enterprise import support from EE These changes were pulled from GitLab EE to support configuring an alternative API URL than the default https://api.github.com. In addition, the `verify_ssl` flag allows users to disable SSL cert checking. One modification: add a default `args` option if it does not exist to avoid breaking existing configurations. --- CHANGELOG | 1 + config/gitlab.yml.example | 2 ++ config/initializers/1_settings.rb | 24 ++++++++++++++ doc/integration/github.md | 14 ++++++++ lib/gitlab/github_import/client.rb | 15 ++++++--- spec/controllers/import/github_controller_spec.rb | 2 ++ spec/lib/gitlab/github_import/client_spec.rb | 40 +++++++++++++++++++++-- spec/services/projects/import_service_spec.rb | 13 ++++++-- 8 files changed, 101 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e52e52691c2..e8998773808 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ v 8.8.0 (unreleased) - Replace Devise Async with Devise ActiveJob integration. !3902 (Connor Shea) - Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea) - Added button to toggle whitespaces changes on diff view + - Backport GitLab Enterprise support from EE v 8.7.1 (unreleased) - Throttle the update of `project.last_activity_at` to 1 minute. !3848 diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index d9c15f81404..2790f1c8a29 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -350,6 +350,8 @@ production: &base # - { name: 'github', # app_id: 'YOUR_APP_ID', # app_secret: 'YOUR_APP_SECRET', + # url: "https://github.com/", + # verify_ssl: true, # args: { scope: 'user:email' } } # - { name: 'bitbucket', # app_id: 'YOUR_APP_ID', diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 10c25044b75..39641655181 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -140,6 +140,30 @@ Settings.omniauth.cas3['session_duration'] ||= 8.hours Settings.omniauth['session_tickets'] ||= Settingslogic.new({}) Settings.omniauth.session_tickets['cas3'] = 'ticket' +# Fill out omniauth-gitlab settings. It is needed for easy set up GHE or GH by just specifying url. + +github_default_url = "https://github.com" +github_settings = Settings.omniauth['providers'].find { |provider| provider["name"] == "github"} + +if github_settings + # For compatibility with old config files (before 7.8) + # where people dont have url in github settings + if github_settings['url'].blank? + github_settings['url'] = github_default_url + end + + github_settings["args"] ||= Settingslogic.new({}) + + if github_settings["url"].include?(github_default_url) + github_settings["args"]["client_options"] = OmniAuth::Strategies::GitHub.default_options[:client_options] + else + github_settings["args"]["client_options"] = { + "site" => File.join(github_settings["url"], "api/v3"), + "authorize_url" => File.join(github_settings["url"], "login/oauth/authorize"), + "token_url" => File.join(github_settings["url"], "login/oauth/access_token") + } + end +end Settings['shared'] ||= Settingslogic.new({}) Settings.shared['path'] = File.expand_path(Settings.shared['path'] || "shared", Rails.root) diff --git a/doc/integration/github.md b/doc/integration/github.md index 1890edd7a4c..ac17e2069f0 100644 --- a/doc/integration/github.md +++ b/doc/integration/github.md @@ -60,12 +60,26 @@ GitHub will generate an application ID and secret key for you to use. For installation from source: + For GitHub.com: + + ``` + - { name: 'github', app_id: 'YOUR_APP_ID', + app_secret: 'YOUR_APP_SECRET', + args: { scope: 'user:email' } } + ``` + + + For GitHub Enterprise: + ``` - { name: 'github', app_id: 'YOUR_APP_ID', app_secret: 'YOUR_APP_SECRET', + url: "https://github.example.com/", args: { scope: 'user:email' } } ``` + __Replace `https://github.example.com/` with your GitHub URL__ + 1. Change 'YOUR_APP_ID' to the client ID from the GitHub application page from step 7. 1. Change 'YOUR_APP_SECRET' to the client secret from the GitHub application page from step 7. diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb index 74d1529e1ff..67988ea3460 100644 --- a/lib/gitlab/github_import/client.rb +++ b/lib/gitlab/github_import/client.rb @@ -7,12 +7,19 @@ module Gitlab @client = ::OAuth2::Client.new( config.app_id, config.app_secret, - github_options + github_options.merge(ssl: { verify: config['verify_ssl'] }) ) if access_token ::Octokit.auto_paginate = true - @api = ::Octokit::Client.new(access_token: access_token) + + @api = ::Octokit::Client.new( + access_token: access_token, + api_endpoint: github_options[:site], + connection_options: { + ssl: { verify: config['verify_ssl'] } + } + ) end end @@ -42,11 +49,11 @@ module Gitlab private def config - Gitlab.config.omniauth.providers.find{|provider| provider.name == "github"} + Gitlab.config.omniauth.providers.find { |provider| provider.name == "github" } end def github_options - OmniAuth::Strategies::GitHub.default_options[:client_options].to_h.symbolize_keys + config["args"]["client_options"].deep_symbolize_keys end end end diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb index bbf8adef534..bcc713dce2a 100644 --- a/spec/controllers/import/github_controller_spec.rb +++ b/spec/controllers/import/github_controller_spec.rb @@ -22,6 +22,8 @@ describe Import::GithubController do token = "asdasd12345" allow_any_instance_of(Gitlab::GithubImport::Client). to receive(:get_token).and_return(token) + allow_any_instance_of(Gitlab::GithubImport::Client). + to receive(:github_options).and_return({}) stub_omniauth_provider('github') get :callback diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb index 49d8cdf4314..7c21cbe96d9 100644 --- a/spec/lib/gitlab/github_import/client_spec.rb +++ b/spec/lib/gitlab/github_import/client_spec.rb @@ -2,15 +2,49 @@ require 'spec_helper' describe Gitlab::GithubImport::Client, lib: true do let(:token) { '123456' } - let(:client) { Gitlab::GithubImport::Client.new(token) } + let(:github_provider) { Settingslogic.new('app_id' => 'asd123', 'app_secret' => 'asd123', 'name' => 'github', 'args' => { 'client_options' => {} }) } + + subject(:client) { described_class.new(token) } before do - Gitlab.config.omniauth.providers << OpenStruct.new(app_id: "asd123", app_secret: "asd123", name: "github") + allow(Gitlab.config.omniauth).to receive(:providers).and_return([github_provider]) end - it 'all OAuth2 client options are symbols' do + it 'convert OAuth2 client options to symbols' do client.client.options.keys.each do |key| expect(key).to be_kind_of(Symbol) end end + + it 'does not crash (e.g. Settingslogic::MissingSetting) when verify_ssl config is not present' do + expect { client.api }.not_to raise_error + end + + context 'allow SSL verification to be configurable on API' do + before do + github_provider['verify_ssl'] = false + end + + it 'uses supplied value' do + expect(client.client.options[:connection_opts][:ssl]).to eq({ verify: false }) + expect(client.api.connection_options[:ssl]).to eq({ verify: false }) + end + end + + context 'when provider does not specity an API endpoint' do + it 'uses GitHub root API endpoint' do + expect(client.api.api_endpoint).to eq 'https://api.github.com/' + end + end + + context 'when provider specify a custom API endpoint' do + before do + github_provider['args']['client_options']['site'] = 'https://github.company.com/' + end + + it 'uses the custom API endpoint' do + expect(OmniAuth::Strategies::GitHub).not_to receive(:default_options) + expect(client.api.api_endpoint).to eq 'https://github.company.com/' + end + end end diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb index 32bf3acf483..7f2dcdab960 100644 --- a/spec/services/projects/import_service_spec.rb +++ b/spec/services/projects/import_service_spec.rb @@ -112,9 +112,16 @@ describe Projects::ImportService, services: true do def stub_github_omniauth_provider provider = OpenStruct.new( - name: 'github', - app_id: 'asd123', - app_secret: 'asd123' + 'name' => 'github', + 'app_id' => 'asd123', + 'app_secret' => 'asd123', + 'args' => { + 'client_options' => { + 'site' => 'https://github.com/api/v3', + 'authorize_url' => 'https://github.com/login/oauth/authorize', + 'token_url' => 'https://github.com/login/oauth/access_token' + } + } ) Gitlab.config.omniauth.providers << provider -- cgit v1.2.1 From c47183d78723a30733dc465f72e37299d8628363 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 26 Apr 2016 21:02:24 -0700 Subject: Fixes for review of GitHub Enterprise backport changes --- config/initializers/1_settings.rb | 6 +++--- doc/integration/github.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 39641655181..6eb144d043b 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -143,7 +143,7 @@ Settings.omniauth.session_tickets['cas3'] = 'ticket' # Fill out omniauth-gitlab settings. It is needed for easy set up GHE or GH by just specifying url. github_default_url = "https://github.com" -github_settings = Settings.omniauth['providers'].find { |provider| provider["name"] == "github"} +github_settings = Settings.omniauth['providers'].find { |provider| provider["name"] == "github" } if github_settings # For compatibility with old config files (before 7.8) @@ -158,9 +158,9 @@ if github_settings github_settings["args"]["client_options"] = OmniAuth::Strategies::GitHub.default_options[:client_options] else github_settings["args"]["client_options"] = { - "site" => File.join(github_settings["url"], "api/v3"), + "site" => File.join(github_settings["url"], "api/v3"), "authorize_url" => File.join(github_settings["url"], "login/oauth/authorize"), - "token_url" => File.join(github_settings["url"], "login/oauth/access_token") + "token_url" => File.join(github_settings["url"], "login/oauth/access_token") } end end diff --git a/doc/integration/github.md b/doc/integration/github.md index ac17e2069f0..e1f9242fd0e 100644 --- a/doc/integration/github.md +++ b/doc/integration/github.md @@ -78,7 +78,7 @@ GitHub will generate an application ID and secret key for you to use. args: { scope: 'user:email' } } ``` - __Replace `https://github.example.com/` with your GitHub URL__ + __Replace `https://github.example.com/` with your GitHub URL.__ 1. Change 'YOUR_APP_ID' to the client ID from the GitHub application page from step 7. -- cgit v1.2.1 From 420b95bd4dcffbe87938251bf497382b6437b155 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 27 Apr 2016 09:11:11 +0100 Subject: Changed settings icon color variable --- app/assets/stylesheets/framework/variables.scss | 1 - app/assets/stylesheets/pages/settings.scss | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 300f941bda6..ad54e3ff5ad 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -71,7 +71,6 @@ $gl-avatar-size: 40px; $error-exclamation-point: #e62958; $border-radius-default: 2px; $btn-transparent-color: #8f8f8f; -$settings-icon-color: #8f8f8f; $settings-icon-size: 18px; $provider-btn-group-border: #e5e5e5; $provider-btn-not-active-color: #4688f1; diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss index 67dbeca7bbd..3fb70085713 100644 --- a/app/assets/stylesheets/pages/settings.scss +++ b/app/assets/stylesheets/pages/settings.scss @@ -1,5 +1,5 @@ .settings-list-icon { - color: $settings-icon-color; + color: $gl-placeholder-color; font-size: $settings-icon-size; line-height: 42px; } -- cgit v1.2.1 From 6b2489f2007e3ffe890f707d824a915f97ed7e61 Mon Sep 17 00:00:00 2001 From: Karlo Soriano Date: Wed, 27 Apr 2016 17:45:50 +0800 Subject: Fix typo in user steps feature [ci skip] --- features/steps/user.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/user.rb b/features/steps/user.rb index 3230234cb6d..39bbb59343b 100644 --- a/features/steps/user.rb +++ b/features/steps/user.rb @@ -12,7 +12,7 @@ class Spinach::Features::User < Spinach::FeatureSteps user = User.find_by(name: 'John Doe') project = contributed_project - # Issue controbution + # Issue contribution issue_params = { title: 'Bug in old browser' } Issues::CreateService.new(project, user, issue_params).execute -- cgit v1.2.1 From c8187738a217166cbf03c26adc4a09fcf43a3b94 Mon Sep 17 00:00:00 2001 From: Karlo Soriano Date: Wed, 27 Apr 2016 19:36:04 +0800 Subject: Remove unused .contributed-projects class While working on #13401 and trying to add a new tab to the user profile page, I came across this. I noticed that the `contributed-projects` class was only being used in order to select the div in the tests. For consistency with the other tabs, I decided to remove this class and use the div's id for the selector. --- app/views/users/show.html.haml | 2 +- features/steps/user.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 3028491e5b6..5554f736e98 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -98,7 +98,7 @@ #groups.tab-pane - # This tab is always loaded via AJAX - #contributed.contributed-projects.tab-pane + #contributed.tab-pane - # This tab is always loaded via AJAX #projects.tab-pane diff --git a/features/steps/user.rb b/features/steps/user.rb index 3230234cb6d..18fd8e5c618 100644 --- a/features/steps/user.rb +++ b/features/steps/user.rb @@ -28,7 +28,7 @@ class Spinach::Features::User < Spinach::FeatureSteps end step 'I should see contributed projects' do - page.within '.contributed-projects' do + page.within '#contributed' do expect(page).to have_content(@contributed_project.name) end end -- cgit v1.2.1 From bdb86ea6cfe16cd3c1e8197744fa3328ba93ecf2 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 18 Apr 2016 09:44:22 +0200 Subject: Render canceled status if any of the jobs canceled This status will be returned only when there are no failed jobs that are not allowed to fail. --- app/models/concerns/statuseable.rb | 2 +- spec/models/concerns/statuseable_spec.rb | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/app/models/concerns/statuseable.rb b/app/models/concerns/statuseable.rb index 8a293b7b76e..3ef91caad47 100644 --- a/app/models/concerns/statuseable.rb +++ b/app/models/concerns/statuseable.rb @@ -18,7 +18,7 @@ module Statuseable WHEN (#{builds})=0 THEN NULL WHEN (#{builds})=(#{success})+(#{ignored}) THEN 'success' WHEN (#{builds})=(#{pending}) THEN 'pending' - WHEN (#{builds})=(#{canceled}) THEN 'canceled' + WHEN (#{builds})=(#{canceled})+(#{success})+(#{ignored}) THEN 'canceled' WHEN (#{builds})=(#{skipped}) THEN 'skipped' WHEN (#{running})+(#{pending})>0 THEN 'running' ELSE 'failed' diff --git a/spec/models/concerns/statuseable_spec.rb b/spec/models/concerns/statuseable_spec.rb index dacbd3034c0..8e0a2a2cbde 100644 --- a/spec/models/concerns/statuseable_spec.rb +++ b/spec/models/concerns/statuseable_spec.rb @@ -61,9 +61,35 @@ describe Statuseable do let(:statuses) do [create(type, status: :success), create(type, status: :canceled)] end + + it { is_expected.to eq 'canceled' } + end + + context 'one failed and one canceled' do + let(:statuses) do + [create(type, status: :failed), create(type, status: :canceled)] + end + it { is_expected.to eq 'failed' } end + context 'one failed but allowed to fail and one canceled' do + let(:statuses) do + [create(type, status: :failed, allow_failure: true), + create(type, status: :canceled)] + end + + it { is_expected.to eq 'canceled' } + end + + context 'one running one canceled' do + let(:statuses) do + [create(type, status: :running), create(type, status: :canceled)] + end + + it { is_expected.to eq 'running' } + end + context 'all canceled' do let(:statuses) do [create(type, status: :canceled), create(type, status: :canceled)] -- cgit v1.2.1 From 1cf8723d2ff22b096799c74b7ec0eb6b72c33f0b Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 27 Apr 2016 14:04:59 +0100 Subject: Updated triggers UI Closes #14090 --- .../framework/tw_bootstrap_variables.scss | 2 +- app/views/projects/triggers/_trigger.html.haml | 8 +- app/views/projects/triggers/index.html.haml | 119 ++++++++++----------- 3 files changed, 63 insertions(+), 66 deletions(-) diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss index c72af5dad0a..d91e35911d8 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss @@ -153,7 +153,7 @@ $nav-link-padding: 13px $gl-padding; //== Code // //## -$pre-bg: #f8fafc !default; +$pre-bg: #f4f7fd !default; $pre-color: $gl-gray !default; $pre-border-color: #e7e9ed; diff --git a/app/views/projects/triggers/_trigger.html.haml b/app/views/projects/triggers/_trigger.html.haml index 48b3b5c9920..112b51712ef 100644 --- a/app/views/projects/triggers/_trigger.html.haml +++ b/app/views/projects/triggers/_trigger.html.haml @@ -1,7 +1,6 @@ %tr %td - .clearfix - %span.monospace= trigger.token + %span.monospace= trigger.token %td - if trigger.last_trigger_request @@ -9,6 +8,5 @@ - else Never - %td - .pull-right - = link_to 'Revoke', namespace_project_trigger_path(@project.namespace, @project, trigger), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-danger btn-sm btn-grouped" + %td.text-right + = link_to 'Revoke', namespace_project_trigger_path(@project.namespace, @project, trigger), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-warning btn-sm" diff --git a/app/views/projects/triggers/index.html.haml b/app/views/projects/triggers/index.html.haml index bd346c4b8e6..f91885b216d 100644 --- a/app/views/projects/triggers/index.html.haml +++ b/app/views/projects/triggers/index.html.haml @@ -1,71 +1,70 @@ - page_title "Triggers" -%h3.page-title - Triggers -%p.light - Triggers can be used to force a rebuild of a specific branch or tag with an API call. +.row.prepend-top-default.append-bottom-default + .col-lg-3 + %h4.prepend-top-0 + = page_title + %p + Triggers can be used to force a rebuild of a specific branch or tag with an API call. + .col-lg-9 + %h5.prepend-top-0 + Your triggers + - if @triggers.any? + .table-responsive + %table.table + %thead + %th Token + %th Last used + %th + = render partial: 'trigger', collection: @triggers, as: :trigger + - else + %p.profile-settings-message.text-center.append-bottom-default + There are no triggers to use, add one by the button below. -%hr.clearfix + = form_for @trigger, url: url_for(controller: 'projects/triggers', action: 'create') do |f| + = f.submit "Add Trigger", class: 'btn btn-success' --if @triggers.any? - .table-holder - %table.table - %thead - %th Token - %th Last used - %th - = render partial: 'trigger', collection: @triggers, as: :trigger -- else - %h4 No triggers + %h5.prepend-top-default + Use CURL -= form_for @trigger, url: url_for(controller: 'projects/triggers', action: 'create'), html: { class: 'form-horizontal' } do |f| - .clearfix - = f.submit "Add Trigger", class: 'btn btn-success pull-right' + %p.light + Copy the token above and set your branch or tag name. This is the reference that will be rebuild. -%hr.clearfix --if @triggers.any? - %h3 - Use CURL + %pre + :plain + curl -X POST \ + -F token=TOKEN \ + -F ref=REF_NAME \ + #{builds_trigger_url(@project.id)} + %h5.prepend-top-default + Use .gitlab-ci.yml - %p.light - Copy the token above and set your branch or tag name. This is the reference that will be rebuild. + %p.light + Copy the snippet to + %i .gitlab-ci.yml + of dependent project. + At the end of your build it will trigger this project to rebuilt. + %pre + :plain + trigger: + type: deploy + script: + - "curl -X POST -F token=TOKEN -F ref=REF_NAME #{builds_trigger_url(@project.id)}" + %h5.prepend-top-default + Pass build variables - %pre - :plain - curl -X POST \ - -F token=TOKEN \ - -F ref=REF_NAME \ - #{builds_trigger_url(@project.id)} - %h3 - Use .gitlab-ci.yml + %p.light + Add + %strong variables[VARIABLE]=VALUE + to API request. + The value of variable could then be used to distinguish triggered build from normal one. - %p.light - Copy the snippet to - %i .gitlab-ci.yml - of dependent project. - At the end of your build it will trigger this project to rebuilt. - - %pre - :plain - trigger: - type: deploy - script: - - "curl -X POST -F token=TOKEN -F ref=REF_NAME #{builds_trigger_url(@project.id)}" - %h3 - Pass build variables - - %p.light - Add - %strong variables[VARIABLE]=VALUE - to API request. - The value of variable could then be used to distinguish triggered build from normal one. - - %pre - :plain - curl -X POST \ - -F token=TOKEN \ - -F "ref=REF_NAME" \ - -F "variables[RUN_NIGHTLY_BUILD]=true" \ - #{builds_trigger_url(@project.id)} + %pre.append-bottom-0 + :plain + curl -X POST \ + -F token=TOKEN \ + -F "ref=REF_NAME" \ + -F "variables[RUN_NIGHTLY_BUILD]=true" \ + #{builds_trigger_url(@project.id)} -- cgit v1.2.1 From 1d6fdcea95accde7502ace3dc94f79435edfd5c7 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 25 Apr 2016 17:08:10 -0700 Subject: Disable Rack Attack if admin disables it in config file Grack::Auth already checks this variable. These holdouts were not disabled, leading to confusion when debugging a customer issue. --- config/initializers/rack_attack.rb.example | 3 ++- config/initializers/rack_attack_git_basic_auth.rb | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/config/initializers/rack_attack.rb.example b/config/initializers/rack_attack.rb.example index b1bbcca1d61..30d05f16153 100644 --- a/config/initializers/rack_attack.rb.example +++ b/config/initializers/rack_attack.rb.example @@ -17,8 +17,9 @@ paths_to_be_protected = [ # Create one big regular expression that matches strings starting with any of # the paths_to_be_protected. paths_regex = Regexp.union(paths_to_be_protected.map { |path| /\A#{Regexp.escape(path)}/ }) +rack_attack_enabled = Gitlab.config.rack_attack.git_basic_auth['enabled'] -unless Rails.env.test? +unless Rails.env.test? || !rack_attack_enabled Rack::Attack.throttle('protected paths', limit: 10, period: 60.seconds) do |req| if req.post? && req.path =~ paths_regex req.ip diff --git a/config/initializers/rack_attack_git_basic_auth.rb b/config/initializers/rack_attack_git_basic_auth.rb index bbbfed68329..6a721826170 100644 --- a/config/initializers/rack_attack_git_basic_auth.rb +++ b/config/initializers/rack_attack_git_basic_auth.rb @@ -1,4 +1,6 @@ -unless Rails.env.test? +rack_attack_enabled = Gitlab.config.rack_attack.git_basic_auth['enabled'] + +unless Rails.env.test? || !rack_attack_enabled # Tell the Rack::Attack Rack middleware to maintain an IP blacklist. We will # update the blacklist from Grack::Auth#authenticate_user. Rack::Attack.blacklist('Git HTTP Basic Auth') do |req| -- cgit v1.2.1 From 7c9233856e9f14f48811dc5678e98a036f2fa0de Mon Sep 17 00:00:00 2001 From: David de Boer Date: Wed, 27 Apr 2016 16:41:37 +0200 Subject: Add API doc example with query string for triggering build --- doc/ci/triggers/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/ci/triggers/README.md b/doc/ci/triggers/README.md index 9f7c1bfe6a0..79ed512aabb 100644 --- a/doc/ci/triggers/README.md +++ b/doc/ci/triggers/README.md @@ -85,6 +85,12 @@ curl -X POST \ In this case, the project with ID `9` will get rebuilt on `master` branch. +Alternatively, you can pass the `token` and `ref` arguments in the query string: + +```bash +curl -X POST \ + "https://gitlab.example.com/api/v3/projects/9/trigger/builds?token=TOKEN&ref=master" +``` ### Triggering a build within `.gitlab-ci.yml` -- cgit v1.2.1 From 129c6fbc2d4ce72db8f4dc1ded9b92ce3fcbde50 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Wed, 27 Apr 2016 09:52:20 -0500 Subject: Add Safari search box bug fix to changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index e52e52691c2..ca5b6b4081f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ v 8.7.1 (unreleased) - Use the `can?` helper instead of `current_user.can?`. !3882 - Prevent users from deleting Webhooks via API they do not own - Fix Error 500 due to stale cache when projects are renamed or transferred + - Update width of search box to fix Safari bug. !3900 (Jedidiah) v 8.7.0 - Gitlab::GitAccess and Gitlab::GitAccessWiki are now instrumented -- cgit v1.2.1 From d2f898e7eadc2b4b3d2afb839818c5bc886ce62f Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Wed, 27 Apr 2016 14:50:24 -0500 Subject: Fix Todos test --- spec/features/todos/todos_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb index 248e004ba6e..3354f529295 100644 --- a/spec/features/todos/todos_spec.rb +++ b/spec/features/todos/todos_spec.rb @@ -68,12 +68,12 @@ describe 'Dashboard Todos', feature: true do describe 'completing last todo from last page', js: true do it 'redirects to the previous page' do visit dashboard_todos_path(page: 2) - expect(page).to have_content(Todo.first.body) + expect(page).to have_css("#todo_#{Todo.last.id}") click_link('Done') expect(current_path).to eq dashboard_todos_path - expect(page).to have_content(Todo.last.body) + expect(page).to have_css("#todo_#{Todo.first.id}") end end end -- cgit v1.2.1 From b677b0e33a04ead7edaad5ee528c915980b1c283 Mon Sep 17 00:00:00 2001 From: mike Date: Wed, 27 Apr 2016 16:03:20 -0600 Subject: Add explicit --with statement for postgres and mysql gem groups as necessary. When I followed these instructions, the first command did not install the postgres group and it had to be made explicit. --- doc/update/patch_versions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md index f446ed0a35b..bca570b28b9 100644 --- a/doc/update/patch_versions.md +++ b/doc/update/patch_versions.md @@ -57,10 +57,10 @@ sudo -u git -H make cd /home/git/gitlab # PostgreSQL -sudo -u git -H bundle install --without development test mysql --deployment +sudo -u git -H bundle install --without development test mysql --with postgres --deployment # MySQL -sudo -u git -H bundle install --without development test postgres --deployment +sudo -u git -H bundle install --without development test postgres --with mysql --deployment # Optional: clean up old gems sudo -u git -H bundle clean -- cgit v1.2.1 From 267dd23311fe6ad6e9c9af15d683dc1a1bf608fe Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Wed, 27 Apr 2016 18:05:57 -0600 Subject: Enable LstripRstrip cop This requires no code changes since it doesn't actually change anything in the codebase, just preventative. --- .rubocop.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 83ed6c38678..9f179efa3ce 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -953,10 +953,9 @@ Performance/DoubleStartEndWith: Performance/EndWith: Enabled: false -# TODO: Enable LstripRstrip Cop. # Use `strip` instead of `lstrip.rstrip`. Performance/LstripRstrip: - Enabled: false + Enabled: true # TODO: Enable RangeInclude Cop. # Use `Range#cover?` instead of `Range#include?`. -- cgit v1.2.1 From e99cf05875af4627e532fee77bd22574dde240d7 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 27 Apr 2016 22:04:40 -0700 Subject: Use ActionDispatch Remote IP for Akismet checking Previously all remote IPs appeared at 127.0.0.1, which made Akismet not very useful. Using the ActionDispatch Remote IP (http://api.rubyonrails.org/classes/ActionDispatch/RemoteIp.html) should provide more reliable results. Closes #16629 --- CHANGELOG | 1 + lib/api/issues.rb | 4 ++-- lib/gitlab/akismet_helper.rb | 12 ++++++++++-- spec/lib/gitlab/akismet_helper_spec.rb | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e52e52691c2..6f931eb92f8 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.8.0 (unreleased) - Remove future dates from contribution calendar graph. + - Use ActionDispatch Remote IP for Akismet checking - Fix error when visiting commit builds page before build was updated - Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project - Updated search UI diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 8aa08fd5acc..40928749481 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -24,8 +24,8 @@ module API def create_spam_log(project, current_user, attrs) params = attrs.merge({ - source_ip: env['REMOTE_ADDR'], - user_agent: env['HTTP_USER_AGENT'], + source_ip: client_ip(env), + user_agent: user_agent(env), noteable_type: 'Issue', via_api: true }) diff --git a/lib/gitlab/akismet_helper.rb b/lib/gitlab/akismet_helper.rb index b366c89889e..04676fdb748 100644 --- a/lib/gitlab/akismet_helper.rb +++ b/lib/gitlab/akismet_helper.rb @@ -9,14 +9,22 @@ module Gitlab Gitlab.config.gitlab.url) end + def client_ip(env) + env['action_dispatch.remote_ip'].to_s + end + + def user_agent(env) + env['HTTP_USER_AGENT'] + end + def check_for_spam?(project, user) akismet_enabled? && !project.team.member?(user) end def is_spam?(environment, user, text) client = akismet_client - ip_address = environment['REMOTE_ADDR'] - user_agent = environment['HTTP_USER_AGENT'] + ip_address = client_ip(environment) + user_agent = user_agent(environment) params = { type: 'comment', diff --git a/spec/lib/gitlab/akismet_helper_spec.rb b/spec/lib/gitlab/akismet_helper_spec.rb index 9858935180a..53f5d6c5c80 100644 --- a/spec/lib/gitlab/akismet_helper_spec.rb +++ b/spec/lib/gitlab/akismet_helper_spec.rb @@ -24,7 +24,7 @@ describe Gitlab::AkismetHelper, type: :helper do describe '#is_spam?' do it 'returns true for spam' do environment = { - 'REMOTE_ADDR' => '127.0.0.1', + 'action_dispatch.remote_ip' => '127.0.0.1', 'HTTP_USER_AGENT' => 'Test User Agent' } -- cgit v1.2.1 From 8b817f594015ad730f426bf6bbf69dab6cc7e563 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Sat, 23 Jan 2016 11:03:16 +0100 Subject: Users can use the feature proposal label inside the issue [ci skip] --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 24cd5864530..39b3048899d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -135,8 +135,9 @@ For feature proposals for EE, open an issue on the In order to help track the feature proposals, we have created a [`feature proposal`][fpl] label. For the time being, users that are not members -of the project cannot add labels. You can instead ask one of the [core team][core-team] -members to add the label `feature proposal` to the issue. +of the project cannot add labels. You can instead ask one of the [core team][] +members to add the label `feature proposal` to the issue or add the following +code snippet right after your description in a new line: `~"feature proposal"`. Please keep feature proposals as small and simple as possible, complex ones might be edited to make them small and simple. -- cgit v1.2.1 From 8b09dafb16726168ab78ff425c7c3d7c668ac5a5 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 28 Apr 2016 13:04:53 +0300 Subject: Copyedit `using_docker_build.md` and fix links --- doc/ci/docker/using_docker_build.md | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md index bb2a6d1137d..5fb086b1dd9 100644 --- a/doc/ci/docker/using_docker_build.md +++ b/doc/ci/docker/using_docker_build.md @@ -75,15 +75,19 @@ For more information please checkout [On Docker security: `docker` group conside ## 2. Use docker-in-docker executor -Second approach is to use special Docker image with all tools installed (`docker` and `docker-compose`) and run build script in context of that image in privileged mode. +The second approach is to use the special Docker image with all tools installed +(`docker` and `docker-compose`) and run the build script in context of that +image in privileged mode. + In order to do that follow the steps: 1. Install [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/#installation). -1. Register GitLab Runner from command line to use `docker` and `privileged` mode: +1. Register GitLab Runner from the command line to use `docker` and `privileged` + mode: ```bash - $ sudo gitlab-runner register -n \ + sudo gitlab-runner register -n \ --url https://gitlab.com/ci \ --token RUNNER_TOKEN \ --executor docker \ @@ -92,10 +96,11 @@ In order to do that follow the steps: --docker-privileged ``` - The above command will register a new Runner to use special `docker:latest` image which is provided by Docker - creators. **Notice that it's using the `privileged` mode to start build and service containers.** If you want to use - [docker-in-docker](https://blog.docker.com/2013/09/docker-can-now-run-within-docker/) mode, you always have to use - `privileged = true` in your docker containers. + The above command will register a new Runner to use the special + `docker:latest` image which is provided by Docker. **Notice that it's using + the `privileged` mode to start the build and service containers.** If you + want to use [docker-in-docker] mode, you always have to use `privileged = true` + in your Docker containers. The above command will create a `config.toml` entry similar to this: @@ -114,8 +119,9 @@ In order to do that follow the steps: Insecure = false ``` - If you want to use Shared Runners available on your GitLab CE/EE installation, to build docker images, then - make sure that your Shared Runners configuration have `privileged` mode set to `true`. + If you want to use the Shared Runners available on your GitLab CE/EE + installation in order to build Docker images, then make sure that your + Shared Runners configuration has the `privileged` mode set to `true`. 1. You can now use `docker` from build script: @@ -126,7 +132,7 @@ In order to do that follow the steps: - docker:dind before_script: - - docker info + - docker info build: stage: build @@ -135,9 +141,14 @@ In order to do that follow the steps: - docker run my-docker-image /script/to/run/tests ``` -1. However, by enabling `--docker-privileged` you are effectively disables all security mechanisms of containers and - exposing your host to privilege escalation which can lead to container breakout. +1. However, by enabling `--docker-privileged` you are effectively disabling all + the security mechanisms of containers and exposing your host to privilege + escalation which can lead to container breakout. - For more information, check out [Runtime privilege](https://docs.docker.com/reference/run/#runtime-privilege-linux-capabilities-and-lxc-configuration). + For more information, check out the official Docker documentation on + [Runtime privilege and Linux capabilities][docker-cap]. An example project using this approach can be found here: https://gitlab.com/gitlab-examples/docker. + +[docker-in-docker]: https://blog.docker.com/2013/09/docker-can-now-run-within-docker/ +[docker-cap]: https://docs.docker.com/reference/run/#runtime-privilege-and-linux-capabilities -- cgit v1.2.1 From 8a6776caa9f45c4c16347ad662bd83519032687d Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 28 Apr 2016 12:11:08 +0200 Subject: Use 'exec' in Unicorn and Sidekiq launch scripts When running Unicorn or Sidekiq in the foreground this change removes an intermediate /bin/sh process. This makes process supervision in the GitLab Development Kit more reliable. This change does not affect Omnibus-GitLab (because there we do not use these launch scripts). Installations from source do use the launch scripts but for the standard GitLab init script this change will not make a difference. Custom installations using Upstart or Systemd may be affected however, because under certain configurations these systems count exactly how many forks happen during process startup, and we are reducing that number by one here. --- bin/background_jobs | 2 +- bin/web | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/background_jobs b/bin/background_jobs index 1f67d732949..25a578a1c49 100755 --- a/bin/background_jobs +++ b/bin/background_jobs @@ -37,7 +37,7 @@ start_no_deamonize() start_sidekiq() { - bundle exec sidekiq -q post_receive -q mailers -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q default -e $RAILS_ENV -P $sidekiq_pidfile "$@" + exec bundle exec sidekiq -q post_receive -q mailers -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q default -e $RAILS_ENV -P $sidekiq_pidfile "$@" } load_ok() diff --git a/bin/web b/bin/web index 03fe7a6354b..ecd0bbd10b0 100755 --- a/bin/web +++ b/bin/web @@ -19,12 +19,12 @@ get_unicorn_pid() start() { - $unicorn_cmd -D + exec $unicorn_cmd -D } start_foreground() { - $unicorn_cmd + exec $unicorn_cmd } stop() -- cgit v1.2.1 From 4fcf2fb9e779cbc8ce872a15c5c7657471d1ddba Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 28 Apr 2016 11:35:46 +0100 Subject: Updated spacing between notification label and button Closes #16552 --- app/views/profiles/emails/index.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml index 57527361eb6..6f7fefdb46d 100644 --- a/app/views/profiles/emails/index.html.haml +++ b/app/views/profiles/emails/index.html.haml @@ -45,4 +45,4 @@ %span.label.label-info Public Email - if email.email === current_user.notification_email %span.label.label-info Notification Email - = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-remove pull-right' + = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-warning prepend-left-10' -- cgit v1.2.1 From 7518330aa197930282121ac489a01987c20b6e00 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 19 Apr 2016 12:36:57 +0200 Subject: Refactor ci commit specs by adding context blocks --- spec/models/ci/commit_spec.rb | 162 ++++++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 77 deletions(-) diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb index 82c18aaa01a..0bc7722ce6e 100644 --- a/spec/models/ci/commit_spec.rb +++ b/spec/models/ci/commit_spec.rb @@ -158,97 +158,105 @@ describe Ci::Commit, models: true do stub_ci_commit_yaml_file(YAML.dump(yaml)) end - it 'properly creates builds' do - expect(create_builds).to be_truthy - expect(commit.builds.pluck(:name)).to contain_exactly('build') - expect(commit.builds.pluck(:status)).to contain_exactly('pending') - commit.builds.running_or_pending.each(&:success) - - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test') - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending') - commit.builds.running_or_pending.each(&:success) - - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending') - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy') - commit.builds.running_or_pending.each(&:success) - - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup') - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'pending') - commit.builds.running_or_pending.each(&:success) - - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'success') - commit.reload - expect(commit.status).to eq('success') + context 'when builds are successful' do + it 'properly creates builds' do + expect(create_builds).to be_truthy + expect(commit.builds.pluck(:name)).to contain_exactly('build') + expect(commit.builds.pluck(:status)).to contain_exactly('pending') + commit.builds.running_or_pending.each(&:success) + + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending') + commit.builds.running_or_pending.each(&:success) + + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending') + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy') + commit.builds.running_or_pending.each(&:success) + + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'pending') + commit.builds.running_or_pending.each(&:success) + + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'success') + commit.reload + expect(commit.status).to eq('success') + end end - it 'properly creates builds when test fails' do - expect(create_builds).to be_truthy - expect(commit.builds.pluck(:name)).to contain_exactly('build') - expect(commit.builds.pluck(:status)).to contain_exactly('pending') - commit.builds.running_or_pending.each(&:success) + context 'when test job fails' do + it 'properly creates builds' do + expect(create_builds).to be_truthy + expect(commit.builds.pluck(:name)).to contain_exactly('build') + expect(commit.builds.pluck(:status)).to contain_exactly('pending') + commit.builds.running_or_pending.each(&:success) - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test') - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending') - commit.builds.running_or_pending.each(&:drop) + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending') + commit.builds.running_or_pending.each(&:drop) - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure') - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending') - commit.builds.running_or_pending.each(&:success) + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending') + commit.builds.running_or_pending.each(&:success) - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup') - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'pending') - commit.builds.running_or_pending.each(&:success) + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'pending') + commit.builds.running_or_pending.each(&:success) - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'success') - commit.reload - expect(commit.status).to eq('failed') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'success') + commit.reload + expect(commit.status).to eq('failed') + end end - it 'properly creates builds when test and test_failure fails' do - expect(create_builds).to be_truthy - expect(commit.builds.pluck(:name)).to contain_exactly('build') - expect(commit.builds.pluck(:status)).to contain_exactly('pending') - commit.builds.running_or_pending.each(&:success) - - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test') - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending') - commit.builds.running_or_pending.each(&:drop) - - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure') - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending') - commit.builds.running_or_pending.each(&:drop) - - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup') - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'pending') - commit.builds.running_or_pending.each(&:success) - - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup') - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'success') - commit.reload - expect(commit.status).to eq('failed') + context 'when test and test_failure jobs fail' do + it 'properly creates builds' do + expect(create_builds).to be_truthy + expect(commit.builds.pluck(:name)).to contain_exactly('build') + expect(commit.builds.pluck(:status)).to contain_exactly('pending') + commit.builds.running_or_pending.each(&:success) + + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending') + commit.builds.running_or_pending.each(&:drop) + + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending') + commit.builds.running_or_pending.each(&:drop) + + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'pending') + commit.builds.running_or_pending.each(&:success) + + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'success') + commit.reload + expect(commit.status).to eq('failed') + end end - it 'properly creates builds when deploy fails' do - expect(create_builds).to be_truthy - expect(commit.builds.pluck(:name)).to contain_exactly('build') - expect(commit.builds.pluck(:status)).to contain_exactly('pending') - commit.builds.running_or_pending.each(&:success) + context 'when deploy job fails' do + it 'properly creates builds' do + expect(create_builds).to be_truthy + expect(commit.builds.pluck(:name)).to contain_exactly('build') + expect(commit.builds.pluck(:status)).to contain_exactly('pending') + commit.builds.running_or_pending.each(&:success) - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test') - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending') - commit.builds.running_or_pending.each(&:success) + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending') + commit.builds.running_or_pending.each(&:success) - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy') - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending') - commit.builds.running_or_pending.each(&:drop) + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending') + commit.builds.running_or_pending.each(&:drop) - expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup') - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'pending') - commit.builds.running_or_pending.each(&:success) + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'pending') + commit.builds.running_or_pending.each(&:success) - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'success') - commit.reload - expect(commit.status).to eq('failed') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'success') + commit.reload + expect(commit.status).to eq('failed') + end end end end -- cgit v1.2.1 From 60492caa98d7da6d1dd04710c9bc3f762bdceebd Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 19 Apr 2016 12:47:34 +0200 Subject: Add tests exercising builds scheduler after cancel --- spec/models/ci/commit_spec.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb index 0bc7722ce6e..6055c142e21 100644 --- a/spec/models/ci/commit_spec.rb +++ b/spec/models/ci/commit_spec.rb @@ -258,6 +258,24 @@ describe Ci::Commit, models: true do expect(commit.status).to eq('failed') end end + + context 'when build is canceled in the second stage' do + it 'does not schedule builds after build has been canceled' do + expect(create_builds).to be_truthy + expect(commit.builds.pluck(:name)).to contain_exactly('build') + expect(commit.builds.pluck(:status)).to contain_exactly('pending') + commit.builds.running_or_pending.each(&:success) + + expect(commit.builds.running_or_pending).to_not be_empty + + expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending') + commit.builds.running_or_pending.each(&:cancel) + + expect(commit.builds.running_or_pending).to be_empty + expect(commit.reload.status).to eq('canceled') + end + end end end -- cgit v1.2.1 From 83883f426e5d00d56db086bceb4d570ee7a3ebe6 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 19 Apr 2016 13:19:20 +0200 Subject: Add Changelog entry for build status canceled fix --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index e52e52691c2..ba40707a588 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.8.0 (unreleased) + - Make build status canceled if any of the jobs was canceled and none failed - Remove future dates from contribution calendar graph. - Fix error when visiting commit builds page before build was updated - Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project -- cgit v1.2.1 From da4aaaacd785789cc787d6df481de80d4edd58e6 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 28 Apr 2016 14:06:28 +0300 Subject: Fix links to core team page [ci skip] --- CONTRIBUTING.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 39b3048899d..084c2d616a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,7 +38,7 @@ source edition, and GitLab Enterprise Edition (EE) which is our commercial edition. Throughout this guide you will see references to CE and EE for abbreviation. -If you have read this guide and want to know how the GitLab [core team][core-team] +If you have read this guide and want to know how the GitLab [core team] operates please see [the GitLab contributing process](PROCESS.md). ## Contributor license agreement @@ -135,7 +135,7 @@ For feature proposals for EE, open an issue on the In order to help track the feature proposals, we have created a [`feature proposal`][fpl] label. For the time being, users that are not members -of the project cannot add labels. You can instead ask one of the [core team][] +of the project cannot add labels. You can instead ask one of the [core team] members to add the label `feature proposal` to the issue or add the following code snippet right after your description in a new line: `~"feature proposal"`. @@ -345,8 +345,7 @@ is it will be merged (quickly). After that you can send more MRs to enhance it. For examples of feedback on merge requests please look at already [closed merge requests][closed-merge-requests]. If you would like quick feedback on your merge request feel free to mention one of the Merge Marshalls in the -[core team][core-team] or one of the -[Merge request coaches](https://about.gitlab.com/team/). +[core team] or one of the [Merge request coaches](https://about.gitlab.com/team/). Please ensure that your merge request meets the contribution acceptance criteria. When having your code reviewed and when reviewing merge requests please take the @@ -498,7 +497,7 @@ reported by emailing `contact@gitlab.com`. This Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant], version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/). -[core-team]: https://about.gitlab.com/core-team/ +[core team]: https://about.gitlab.com/core-team/ [getting-help]: https://about.gitlab.com/getting-help/ [codetriage]: http://www.codetriage.com/gitlabhq/gitlabhq [up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up-for-grabs -- cgit v1.2.1 From adc296e9369632fe14785afe3824bb0790283643 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Apr 2016 14:13:37 +0200 Subject: Make application header light gray Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/header.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index c303380764b..d14317f9c40 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -26,7 +26,7 @@ header { z-index: 100; margin-bottom: 0; min-height: $header-height; - background-color: #fff; + background-color: $gray-light; border: none; border-bottom: 1px solid #eee; @@ -47,7 +47,7 @@ header { text-align: center; &:hover, &:focus, &:active { - background-color: #fff; + background-color: $gray-light; } } -- cgit v1.2.1 From 52a6b976a77d9ede9f1b50d55e33824ed05acb5f Mon Sep 17 00:00:00 2001 From: Job van der Voort Date: Thu, 28 Apr 2016 14:13:39 +0200 Subject: feature proposal issue template in contributing guide --- CONTRIBUTING.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 24cd5864530..a1ded9b9848 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -141,6 +141,16 @@ members to add the label `feature proposal` to the issue. Please keep feature proposals as small and simple as possible, complex ones 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 + +## Proposal + +## Links / references +``` + For changes in the interface, it can be helpful to create a mockup first. If you want to create something yourself, consider opening an issue first to discuss whether it is interesting to include this in GitLab. -- cgit v1.2.1 From 4a3f3bc7029a12d66bbbbf1c29279b3030d761ef Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Apr 2016 14:23:25 +0200 Subject: Make layout navigation gray and fluid Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/nav.scss | 19 +++++++++++++++++++ app/views/layouts/_page.html.haml | 8 ++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index 192d53b048a..38bea9d462e 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -185,3 +185,22 @@ } } } + +.layout-nav { + background: $gray-light; + border-bottom: 1px solid $border-color; + + .controls { + float: right; + position: relative; + top: 10px; + + .dropdown { + margin-left: 7px; + } + } + + .nav-links { + border-bottom: none; + } +} diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index ca9c2a0bf2e..ad8a2e1e6c7 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -22,13 +22,13 @@ = image_tag avatar_icon(current_user, 60), alt: 'Profile', class: 'avatar avatar s36' .username = current_user.username + - if defined?(nav) && nav + .layout-nav + .container-fluid + = render "layouts/nav/#{nav}" .content-wrapper = render "layouts/flash" = yield :flash_message - - if defined?(nav) && nav - .layout-nav - %div{ class: container_class } - = render "layouts/nav/#{nav}" %div{ class: (container_class unless @no_container) } .content .clearfix -- cgit v1.2.1 From 40a25732e9c36b50ee7682b4b0ab4e323343ea65 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 28 Apr 2016 15:15:59 +0200 Subject: Reorder asserts is ci commits specs for consistency --- spec/models/ci/commit_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb index 6055c142e21..a747aa08447 100644 --- a/spec/models/ci/commit_spec.rb +++ b/spec/models/ci/commit_spec.rb @@ -169,8 +169,8 @@ describe Ci::Commit, models: true do expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending') commit.builds.running_or_pending.each(&:success) - expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending') expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy') + expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending') commit.builds.running_or_pending.each(&:success) expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup') -- cgit v1.2.1 From c73bf28143a8fb6adf7322bb301e28b20fb6bee2 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Wed, 20 Jan 2016 10:57:12 +0100 Subject: Replace gitlab-workhorse with GitLab Workhorse where appropriate --- lib/support/init.d/gitlab | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab index d95e7023d2e..31b00ff128a 100755 --- a/lib/support/init.d/gitlab +++ b/lib/support/init.d/gitlab @@ -173,7 +173,7 @@ check_stale_pids(){ fi fi if [ "$hpid" != "0" ] && [ "$gitlab_workhorse_status" != "0" ]; then - echo "Removing stale gitlab-workhorse pid. This is most likely caused by gitlab-workhorse crashing the last time it ran." + echo "Removing stale GitLab Workhorse pid. This is most likely caused by GitLab Workhorse crashing the last time it ran." if ! rm "$gitlab_workhorse_pid_path"; then echo "Unable to remove stale pid, exiting" exit 1 @@ -208,7 +208,7 @@ start_gitlab() { echo "Starting GitLab Sidekiq" fi if [ "$gitlab_workhorse_status" != "0" ]; then - echo "Starting gitlab-workhorse" + echo "Starting GitLab Workhorse" fi if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" != "0" ]; then echo "Starting GitLab MailRoom" @@ -232,7 +232,7 @@ start_gitlab() { fi if [ "$gitlab_workhorse_status" = "0" ]; then - echo "The gitlab-workhorse is already running with pid $spid, not restarting" + echo "The GitLab Workhorse is already running with pid $spid, not restarting" else # No need to remove a socket, gitlab-workhorse does this itself. # Because gitlab-workhorse has multiple executables we need to fix @@ -271,7 +271,7 @@ stop_gitlab() { RAILS_ENV=$RAILS_ENV bin/background_jobs stop fi if [ "$gitlab_workhorse_status" = "0" ]; then - echo "Shutting down gitlab-workhorse" + echo "Shutting down GitLab Workhorse" kill -- $(cat $gitlab_workhorse_pid_path) fi if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; then @@ -320,9 +320,9 @@ print_status() { printf "The GitLab Sidekiq job dispatcher is \033[31mnot running\033[0m.\n" fi if [ "$gitlab_workhorse_status" = "0" ]; then - echo "The gitlab-workhorse with pid $hpid is running." + echo "The GitLab Workhorse with pid $hpid is running." else - printf "The gitlab-workhorse is \033[31mnot running\033[0m.\n" + printf "The GitLab Workhorse is \033[31mnot running\033[0m.\n" fi if [ "$mail_room_enabled" = true ]; then if [ "$mail_room_status" = "0" ]; then -- cgit v1.2.1 From 435b1c043e8722c0f42d2b248283b950dbd5a357 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Apr 2016 17:03:03 +0200 Subject: Reuse more popular colors Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/header.scss | 6 +++--- app/assets/stylesheets/framework/nav.scss | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index d14317f9c40..5fa10d29a87 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -26,9 +26,9 @@ header { z-index: 100; margin-bottom: 0; min-height: $header-height; - background-color: $gray-light; + background-color: $background-color; border: none; - border-bottom: 1px solid #eee; + border-bottom: 1px solid $border-color; .container-fluid { width: 100% !important; @@ -47,7 +47,7 @@ header { text-align: center; &:hover, &:focus, &:active { - background-color: $gray-light; + background-color: $background-color; } } diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index 38bea9d462e..5fe687dcec3 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -187,7 +187,7 @@ } .layout-nav { - background: $gray-light; + background: $background-color; border-bottom: 1px solid $border-color; .controls { -- cgit v1.2.1 From a94b71c301c8fa0741ba7b4958c30d04f7f10341 Mon Sep 17 00:00:00 2001 From: connorshea Date: Sun, 10 Apr 2016 14:47:01 -0600 Subject: Upgrade Doorkeeper from 2.2.2 to 3.1.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I’d rather upgrade one major version at a time, so Doorkeeper needs to be upgraded to 3.x before it can be upgraded to 4.x (which includes Rails 5 support). Changelog: https://github.com/doorkeeper-gem/doorkeeper/blob/master/NEWS.md#310 --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 7882e467f8d..25c13fda575 100644 --- a/Gemfile +++ b/Gemfile @@ -19,7 +19,7 @@ gem "pg", '~> 0.18.2', group: :postgres # Authentication libraries gem 'devise', '~> 3.5.4' -gem 'doorkeeper', '~> 2.2.0' +gem 'doorkeeper', '~> 3.1' gem 'omniauth', '~> 1.3.1' gem 'omniauth-auth0', '~> 1.4.1' gem 'omniauth-azure-oauth2', '~> 0.0.6' diff --git a/Gemfile.lock b/Gemfile.lock index 91d89b4875a..9c97426cb5d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -173,7 +173,7 @@ GEM diff-lcs (1.2.5) diffy (3.0.7) docile (1.1.5) - doorkeeper (2.2.2) + doorkeeper (3.1.0) railties (>= 3.2) dropzonejs-rails (0.7.2) rails (> 3.1) @@ -922,7 +922,7 @@ DEPENDENCIES devise (~> 3.5.4) devise-two-factor (~> 2.0.0) diffy (~> 3.0.3) - doorkeeper (~> 2.2.0) + doorkeeper (~> 3.1) dropzonejs-rails (~> 0.7.1) email_reply_parser (~> 0.5.8) email_spec (~> 1.6.0) -- cgit v1.2.1 From ad99404d2588e182a115d89b0b457d957e8ca7b6 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Thu, 14 Apr 2016 12:44:35 +0200 Subject: Properly handle bigger files --- CHANGELOG | 1 + app/helpers/blob_helper.rb | 4 ++-- app/models/blob.rb | 8 ++++++++ app/models/snippet.rb | 4 ++++ app/views/projects/blob/_text.html.haml | 25 +++++++++++++++++-------- app/views/shared/_file_highlight.html.haml | 5 +++-- lib/gitlab/highlight.rb | 13 +++++++++---- 7 files changed, 44 insertions(+), 16 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index dccf218dc98..38e440a72cb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,7 @@ v 8.8.0 (unreleased) - Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea) - Added button to toggle whitespaces changes on diff view - Backport GitLab Enterprise support from EE + - Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718 v 8.7.1 (unreleased) - Throttle the update of `project.last_activity_at` to 1 minute. !3848 diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index a4d7c425d0f..474c6f27374 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -3,8 +3,8 @@ module BlobHelper Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap) end - def highlight(blob_name, blob_content, nowrap: false) - Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap) + def highlight(blob_name, blob_content, nowrap: false, plain: false) + Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap, plain: plain) end def no_highlight_files diff --git a/app/models/blob.rb b/app/models/blob.rb index 72e6c5fa3fd..0fea6b7f576 100644 --- a/app/models/blob.rb +++ b/app/models/blob.rb @@ -19,6 +19,14 @@ class Blob < SimpleDelegator new(blob) end + def no_highlighting? + size && size > 1.megabyte + end + + def only_display_raw? + size && size > 5.megabytes + end + def svg? text? && language && language.name == 'SVG' end diff --git a/app/models/snippet.rb b/app/models/snippet.rb index b96e3937281..0fd08061925 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -112,6 +112,10 @@ class Snippet < ActiveRecord::Base visibility_level end + def no_highlighting? + content.lines.count > 1000 + end + class << self # Searches for snippets with a matching title or file name. # diff --git a/app/views/projects/blob/_text.html.haml b/app/views/projects/blob/_text.html.haml index d09cd73558c..b1769759dce 100644 --- a/app/views/projects/blob/_text.html.haml +++ b/app/views/projects/blob/_text.html.haml @@ -1,10 +1,19 @@ -- blob.load_all_data!(@repository) -- if markup?(blob.name) - .file-content.wiki - = render_markup(blob.name, blob.data) +- if blob.only_display_raw? + .file-content.code + .nothing-here-block + File too large, you can + = succeed '.' do + = link_to 'view the raw file', namespace_project_raw_path(@project.namespace, @project, @id), target: '_blank' + - else - - unless blob.empty? - = render 'shared/file_highlight', blob: blob + - blob.load_all_data!(@repository) + + - if markup?(blob.name) + .file-content.wiki + = render_markup(blob.name, blob.data) - else - .file-content.code - .nothing-here-block Empty file + - if blob.empty? + .file-content.code + .nothing-here-block Empty file + - else + = render 'shared/file_highlight', blob: blob diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml index 57856031d6e..37dcf39c062 100644 --- a/app/views/shared/_file_highlight.html.haml +++ b/app/views/shared/_file_highlight.html.haml @@ -1,12 +1,13 @@ .file-content.code.js-syntax-highlight .line-numbers - if blob.data.present? + - link_icon = icon('link') - blob.data.each_line.each_with_index do |_, index| - offset = defined?(first_line_number) ? first_line_number : 1 - i = index + offset -# We're not using `link_to` because it is too slow once we get to thousands of lines. %a.diff-line-num{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i} - %i.fa.fa-link + = link_icon = i .blob-content{data: {blob_id: blob.id}} - = highlight(blob.name, blob.data) + = highlight(blob.name, blob.data, plain: blob.no_highlighting?) diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index cac76442321..280120b0f9e 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -1,7 +1,8 @@ module Gitlab class Highlight - def self.highlight(blob_name, blob_content, nowrap: true) - new(blob_name, blob_content, nowrap: nowrap).highlight(blob_content, continue: false) + def self.highlight(blob_name, blob_content, nowrap: true, plain: false) + new(blob_name, blob_content, nowrap: nowrap). + highlight(blob_content, continue: false, plain: plain) end def self.highlight_lines(repository, ref, file_name) @@ -17,8 +18,12 @@ module Gitlab @lexer = Rouge::Lexer.guess(filename: blob_name, source: blob_content).new rescue Rouge::Lexers::PlainText end - def highlight(text, continue: true) - @formatter.format(@lexer.lex(text, continue: continue)).html_safe + def highlight(text, continue: true, plain: false) + if plain + @formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe + else + @formatter.format(@lexer.lex(text, continue: continue)).html_safe + end rescue @formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe end -- cgit v1.2.1 From 0426647069397d57d46c66de41c8fa4fad65e0bb Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 21 Apr 2016 16:34:00 +0200 Subject: Load the "New Branch" button asynchronously This button depends on Issue#can_be_worked_on? which in turn depends on Issue#related_branches. By rendering this button asynchronously we can finally remove all usages of Issue#related_branches and Issue#referenced_merge_requests from the issues "show" page. --- CHANGELOG | 2 ++ app/assets/javascripts/issue.js.coffee | 23 +++++++++++++++++++++++ app/assets/stylesheets/framework/buttons.scss | 4 ++++ app/controllers/projects/issues_controller.rb | 16 ++++++++++++++-- app/views/projects/issues/_new_branch.html.haml | 16 ++++++++++++---- config/routes.rb | 1 + spec/features/issues/new_branch_button_spec.rb | 11 ++++++----- 7 files changed, 62 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index dccf218dc98..b41ddc8e570 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -20,6 +20,8 @@ v 8.7.1 (unreleased) - Prevent users from deleting Webhooks via API they do not own - Fix Error 500 due to stale cache when projects are renamed or transferred - Update width of search box to fix Safari bug. !3900 (Jedidiah) + - The "New Branch" button is now loaded asynchronously + - Use the `can?` helper instead of `current_user.can?` v 8.7.0 - Gitlab::GitAccess and Gitlab::GitAccessWiki are now instrumented diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee index c7d74a12f99..157361404e0 100644 --- a/app/assets/javascripts/issue.js.coffee +++ b/app/assets/javascripts/issue.js.coffee @@ -12,6 +12,7 @@ class @Issue @initMergeRequests() @initRelatedBranches() + @initCanCreateBranch() initTaskList: -> $('.detail-page-description .js-task-list-container').taskList('enable') @@ -92,3 +93,25 @@ class @Issue .success (data) -> if 'html' of data $container.html(data.html) + + initCanCreateBranch: -> + $container = $('div#new-branch') + + # If the user doesn't have the required permissions the container isn't + # rendered at all. + return unless $container + + $.getJSON($container.data('path')) + .error -> + $container.find('.checking').hide() + $container.find('.unavailable').show() + + new Flash('Failed to check if a new branch can be created.', 'alert') + .success (data) -> + if data.can_create_branch + $container.find('.checking').hide() + $container.find('.available').show() + $container.find('a').attr('disabled', false) + else + $container.find('.checking').hide() + $container.find('.unavailable').show() diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index 18a74fe21a0..062da397b6b 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -139,6 +139,10 @@ pointer-events: auto !important; } + &[disabled] { + pointer-events: none !important; + } + .caret { margin-left: 5px; } diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 7d4fc361ce2..9face235baa 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -3,8 +3,8 @@ class Projects::IssuesController < Projects::ApplicationController include IssuableActions before_action :module_enabled - before_action :issue, - only: [:edit, :update, :show, :referenced_merge_requests, :related_branches] + before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests, + :related_branches, :can_create_branch] # Allow read any issue before_action :authorize_read_issue!, only: [:show] @@ -139,6 +139,18 @@ class Projects::IssuesController < Projects::ApplicationController end end + def can_create_branch + can_create = current_user && + can?(current_user, :push_code, @project) && + @issue.can_be_worked_on?(current_user) + + respond_to do |format| + format.json do + render json: { can_create_branch: can_create } + end + end + end + def bulk_update result = Issues::BulkUpdateService.new(project, current_user, bulk_update_params).execute redirect_back_or_default(default: { action: 'index' }, options: { notice: "#{result[:count]} issues updated" }) diff --git a/app/views/projects/issues/_new_branch.html.haml b/app/views/projects/issues/_new_branch.html.haml index 6da8e4f33a9..469429ccf3c 100644 --- a/app/views/projects/issues/_new_branch.html.haml +++ b/app/views/projects/issues/_new_branch.html.haml @@ -1,5 +1,13 @@ -- if current_user && can?(current_user, :push_code, @project) && @issue.can_be_worked_on?(current_user) +- if can?(current_user, :push_code, @project) .pull-right - = link_to namespace_project_branches_path(@project.namespace, @project, branch_name: @issue.to_branch_name, issue_iid: @issue.iid), method: :post, class: 'btn has-tooltip', title: @issue.to_branch_name do - = icon('code-fork') - New Branch + #new-branch{'data-path' => can_create_branch_namespace_project_issue_path(@project.namespace, @project, @issue)} + = link_to namespace_project_branches_path(@project.namespace, @project, branch_name: @issue.to_branch_name, issue_iid: @issue.iid), method: :post, class: 'btn has-tooltip', title: @issue.to_branch_name, disabled: 'disabled' do + .checking + %i.fa.fa-spinner.fa-spin + Checking branches + .available(style="display: none") + %i.fa.fa-code-fork + New branch + .unavailable(style="display: none") + %i.fa.fa-exclamation-triangle + New branch unavailable diff --git a/config/routes.rb b/config/routes.rb index d664434e1a6..5ce1f49ec6a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -710,6 +710,7 @@ Rails.application.routes.draw do post :toggle_subscription get :referenced_merge_requests get :related_branches + get :can_create_branch end collection do post :bulk_update diff --git a/spec/features/issues/new_branch_button_spec.rb b/spec/features/issues/new_branch_button_spec.rb index 9219b767547..16e188d2a8a 100644 --- a/spec/features/issues/new_branch_button_spec.rb +++ b/spec/features/issues/new_branch_button_spec.rb @@ -11,10 +11,10 @@ feature 'Start new branch from an issue', feature: true do login_as(user) end - it 'shown the new branch button', js: false do + it 'shows the new branch button', js: true do visit namespace_project_issue_path(project.namespace, project, issue) - expect(page).to have_link "New Branch" + expect(page).to have_css('#new-branch .available') end context "when there is a referenced merge request" do @@ -34,16 +34,17 @@ feature 'Start new branch from an issue', feature: true do end it "hides the new branch button", js: true do - expect(page).not_to have_link "New Branch" + expect(page).not_to have_css('#new-branch .available') expect(page).to have_content /1 Related Merge Request/ end end end context "for visiters" do - it 'no button is shown', js: false do + it 'no button is shown', js: true do visit namespace_project_issue_path(project.namespace, project, issue) - expect(page).not_to have_link "New Branch" + + expect(page).not_to have_css('#new-branch') end end end -- cgit v1.2.1 From 9ef18c6c8bdcdf859845da66d7246872f90fef35 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Apr 2016 22:58:38 +0200 Subject: Replace outdated bluish colors with default bg color --- app/assets/stylesheets/framework/blocks.scss | 2 +- app/assets/stylesheets/framework/tw_bootstrap_variables.scss | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 62b2af0dbf7..e72e4aa47ef 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -1,5 +1,5 @@ .light-well { - background-color: #f8fafc; + background-color: $background-color; padding: 15px; } diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss index d91e35911d8..371c1bf17e1 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss @@ -153,8 +153,8 @@ $nav-link-padding: 13px $gl-padding; //== Code // //## -$pre-bg: #f4f7fd !default; +$pre-bg: $background-color !default; $pre-color: $gl-gray !default; -$pre-border-color: #e7e9ed; +$pre-border-color: $border-color; $table-bg-accent: $background-color; -- cgit v1.2.1 From 519a791ef9a90541a1bb3825790bd46fd57756f9 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Thu, 28 Apr 2016 15:08:23 -0600 Subject: Prevent Rails filtered parameters from leaking to Sentry. As described in their Docs: https://docs.getsentry.com/on-premise/clients/ruby/integrations/rails/ --- config/initializers/sentry.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/initializers/sentry.rb b/config/initializers/sentry.rb index e87899b2d5c..74fef7cadfe 100644 --- a/config/initializers/sentry.rb +++ b/config/initializers/sentry.rb @@ -15,6 +15,9 @@ if Rails.env.production? Raven.configure do |config| config.dsn = current_application_settings.sentry_dsn config.release = Gitlab::REVISION + + # Sanitize fields based on those sanitized from Rails. + config.sanitize_fields = Rails.application.config.filter_parameters.map(&:to_s) end end end -- cgit v1.2.1 From c50ce3ba2905ab9f3431467c0118d3cf16fbfea2 Mon Sep 17 00:00:00 2001 From: Alex Jordan Date: Thu, 28 Apr 2016 21:13:21 -0700 Subject: Fix the GitHub Omniauth instructions --- doc/integration/github.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/integration/github.md b/doc/integration/github.md index e1f9242fd0e..e7497e475c9 100644 --- a/doc/integration/github.md +++ b/doc/integration/github.md @@ -9,7 +9,9 @@ GitHub will generate an application ID and secret key for you to use. 1. Navigate to your individual user settings or an organization's settings, depending on how you want the application registered. It does not matter if the application is registered as an individual or an organization - that is entirely up to you. -1. Select "Applications" in the left menu. +1. Select "OAuth applications" in the left menu. + +1. If you already have applications listed, switch to the "Developer applications" tab. 1. Select "Register new application". -- cgit v1.2.1 From c4b9bd041321df25764ad1de90f89b1f0dda9f33 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Fri, 22 Apr 2016 14:07:25 +0200 Subject: API support for the 'since' and 'until' operators on commit requests - Parameter validation as ISO8601 format --- CHANGELOG | 1 + Gemfile.lock | 2 +- app/controllers/projects/commits_controller.rb | 2 +- app/controllers/projects/graphs_controller.rb | 4 +-- app/models/repository.rb | 6 +++-- doc/api/commits.md | 2 ++ lib/api/commits.rb | 8 +++++- lib/api/helpers.rb | 16 ++++++++++++ lib/gitlab/push_data_builder.rb | 2 +- spec/models/repository_spec.rb | 2 +- spec/requests/api/commits_spec.rb | 35 ++++++++++++++++++++++++++ 11 files changed, 71 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e52e52691c2..c9215954378 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ v 8.8.0 (unreleased) - Replace Devise Async with Devise ActiveJob integration. !3902 (Connor Shea) - Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea) - Added button to toggle whitespaces changes on diff view + - API support for the 'since' and 'until' operators on commit requests (Paco Guzman) v 8.7.1 (unreleased) - Throttle the update of `project.last_activity_at` to 1 minute. !3848 diff --git a/Gemfile.lock b/Gemfile.lock index 91d89b4875a..02ccbdd8fc3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -351,7 +351,7 @@ GEM posix-spawn (~> 0.3) gitlab_emoji (0.3.1) gemojione (~> 2.2, >= 2.2.1) - gitlab_git (10.0.0) + gitlab_git (10.0.2) activesupport (~> 4.0) charlock_holmes (~> 0.7.3) github-linguist (~> 4.7.0) diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb index 1420b96840c..a52c614b259 100644 --- a/app/controllers/projects/commits_controller.rb +++ b/app/controllers/projects/commits_controller.rb @@ -15,7 +15,7 @@ class Projects::CommitsController < Projects::ApplicationController if search.present? @repository.find_commits_by_message(search, @ref, @path, @limit, @offset).compact else - @repository.commits(@ref, @path, @limit, @offset) + @repository.commits(@ref, path: @path, limit: @limit, offset: @offset) end @note_counts = project.notes.where(commit_id: @commits.map(&:id)). diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb index d13ea9f34b6..092ef32e6e3 100644 --- a/app/controllers/projects/graphs_controller.rb +++ b/app/controllers/projects/graphs_controller.rb @@ -17,7 +17,7 @@ class Projects::GraphsController < Projects::ApplicationController end def commits - @commits = @project.repository.commits(@ref, nil, 2000, 0, true) + @commits = @project.repository.commits(@ref, limit: 2000, skip_merges: true) @commits_graph = Gitlab::Graphs::Commits.new(@commits) @commits_per_week_days = @commits_graph.commits_per_week_days @commits_per_time = @commits_graph.commits_per_time @@ -55,7 +55,7 @@ class Projects::GraphsController < Projects::ApplicationController private def fetch_graph - @commits = @project.repository.commits(@ref, nil, 6000, 0, true) + @commits = @project.repository.commits(@ref, limit: 6000, skip_merges: true) @log = [] @commits.each do |commit| diff --git a/app/models/repository.rb b/app/models/repository.rb index d495c8d18f5..292acf9044f 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -87,13 +87,15 @@ class Repository nil end - def commits(ref, path = nil, limit = nil, offset = nil, skip_merges = false) + def commits(ref, path: nil, limit: nil, offset: nil, skip_merges: false, after: nil, before: nil) options = { repo: raw_repository, ref: ref, path: path, limit: limit, offset: offset, + after: after, + before: before, # --follow doesn't play well with --skip. See: # https://gitlab.com/gitlab-org/gitlab-ce/issues/3574#note_3040520 follow: false, @@ -575,7 +577,7 @@ class Repository end def contributors - commits = self.commits(nil, nil, 2000, 0, true) + commits = self.commits(nil, limit: 2000, offset: 0, skip_merges: true) commits.group_by(&:author_email).map do |email, commits| contributor = Gitlab::Contributor.new diff --git a/doc/api/commits.md b/doc/api/commits.md index 6341440c58b..57c2e1d9b87 100644 --- a/doc/api/commits.md +++ b/doc/api/commits.md @@ -12,6 +12,8 @@ GET /projects/:id/repository/commits | --------- | ---- | -------- | ----------- | | `id` | integer | yes | The ID of a project | | `ref_name` | string | no | The name of a repository branch or tag or if not given the default branch | +| `since` | string | no | Only commits after or in this date will be returned in ISO 8601 format YYYY-MM-DDTHH:MM:SSZ | +| `until` | string | no | Only commits before or in this date will be returned in ISO 8601 format YYYY-MM-DDTHH:MM:SSZ | ```bash curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/repository/commits" diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 4544a41b1e3..93a3a5ce089 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -12,14 +12,20 @@ module API # Parameters: # id (required) - The ID of a project # ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used + # since (optional) - Only commits after or in this date will be returned + # until (optional) - Only commits before or in this date will be returned # Example Request: # GET /projects/:id/repository/commits get ":id/repository/commits" do + datetime_attributes! :since, :until + page = (params[:page] || 0).to_i per_page = (params[:per_page] || 20).to_i ref = params[:ref_name] || user_project.try(:default_branch) || 'master' + after = params[:since] + before = params[:until] - commits = user_project.repository.commits(ref, nil, per_page, page * per_page) + commits = user_project.repository.commits(ref, limit: per_page, offset: page * per_page, after: after, before: before) present commits, with: Entities::RepoCommit end diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 5bbf721321d..40c967453fb 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -183,6 +183,22 @@ module API Gitlab::Access.options_with_owner.values.include? level.to_i end + # Checks the occurrences of datetime attributes, each attribute if present in the params hash must be in ISO 8601 + # format (YYYY-MM-DDTHH:MM:SSZ) or a Bad Request error is invoked. + # + # Parameters: + # keys (required) - An array consisting of elements that must be parseable as dates from the params hash + def datetime_attributes!(*keys) + keys.each do |key| + begin + params[key] = Time.xmlschema(params[key]) if params[key].present? + rescue ArgumentError + message = "\"" + key.to_s + "\" must be a timestamp in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ" + render_api_error!(message, 400) + end + end + end + def issuable_order_by if params["order_by"] == 'updated_at' 'updated_at' diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb index 67622f321a6..c8f12577112 100644 --- a/lib/gitlab/push_data_builder.rb +++ b/lib/gitlab/push_data_builder.rb @@ -66,7 +66,7 @@ module Gitlab # This method provide a sample data generated with # existing project and commits to test webhooks def build_sample(project, user) - commits = project.repository.commits(project.default_branch, nil, 3) + commits = project.repository.commits(project.default_branch, limit: 3) ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{project.default_branch}" build(project, user, commits.last.id, commits.first.id, ref, commits) end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index a306cc4aef8..802b4e579e1 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -561,7 +561,7 @@ describe Repository, models: true do end describe :skip_merged_commit do - subject { repository.commits(Gitlab::Git::BRANCH_REF_PREFIX + "'test'", nil, 100, 0, true).map{ |k| k.id } } + subject { repository.commits(Gitlab::Git::BRANCH_REF_PREFIX + "'test'", limit: 100, skip_merges: true).map{ |k| k.id } } it { is_expected.not_to include('e56497bb5f03a90a51293fc6d516788730953899') } end diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index e28998d51b5..cb82ca7802d 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -32,6 +32,41 @@ describe API::API, api: true do expect(response.status).to eq(401) end end + + context "since optional parameter" do + it "should return project commits since provided parameter" do + commits = project.repository.commits("master") + since = commits.second.created_at + + get api("/projects/#{project.id}/repository/commits?since=#{since.utc.iso8601}", user) + + expect(json_response.size).to eq 2 + expect(json_response.first["id"]).to eq(commits.first.id) + expect(json_response.second["id"]).to eq(commits.second.id) + end + end + + context "until optional parameter" do + it "should return project commits until provided parameter" do + commits = project.repository.commits("master") + before = commits.second.created_at + + get api("/projects/#{project.id}/repository/commits?until=#{before.utc.iso8601}", user) + + expect(json_response.size).to eq(commits.size - 1) + expect(json_response.first["id"]).to eq(commits.second.id) + expect(json_response.second["id"]).to eq(commits.third.id) + end + end + + context "invalid xmlschema date parameters" do + it "should return an invalid parameter error message" do + get api("/projects/#{project.id}/repository/commits?since=invalid-date", user) + + expect(response.status).to eq(400) + expect(json_response['message']).to include "\"since\" must be a timestamp in ISO 8601 format" + end + end end describe "GET /projects:id/repository/commits/:sha" do -- cgit v1.2.1 From ded3b02f3353708386d6960c5c146bf2a2de86db Mon Sep 17 00:00:00 2001 From: Arinde Eniola Date: Tue, 26 Apr 2016 12:22:52 +0100 Subject: Use a better message when milestone is newly created make some changes for the checks to determine when the messages should be displayed add item to changelog and also integration test make some changes to the test make some changes --- CHANGELOG | 1 + app/models/concerns/milestoneish.rb | 2 +- app/views/projects/milestones/show.html.haml | 7 ++++-- spec/features/milestone_spec.rb | 35 ++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 spec/features/milestone_spec.rb diff --git a/CHANGELOG b/CHANGELOG index d453ae19e77..bba09415730 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,7 @@ v 8.8.0 (unreleased) - Fix error when visiting commit builds page before build was updated - Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project - Updated search UI + - Display informative message when new milestone is created - Replace Devise Async with Devise ActiveJob integration. !3902 (Connor Shea) - Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea) - Added button to toggle whitespaces changes on diff view diff --git a/app/models/concerns/milestoneish.rb b/app/models/concerns/milestoneish.rb index 5b8e3f654ea..7bcc78247ba 100644 --- a/app/models/concerns/milestoneish.rb +++ b/app/models/concerns/milestoneish.rb @@ -8,7 +8,7 @@ module Milestoneish end def complete?(user = nil) - total_items_count(user) == closed_items_count(user) + total_items_count(user) > 0 && total_items_count(user) == closed_items_count(user) end def percent_complete(user = nil) diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index be63875ab34..56543ccd062 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -42,9 +42,12 @@ = preserve do = markdown @milestone.description -- if @milestone.complete?(current_user) && @milestone.active? +- if @milestone.total_items_count(current_user).zero? .alert.alert-success.prepend-top-default - %span All issues for this milestone are closed. You may close milestone now. + %span Assign some issues to this milestone. +- elsif @milestone.complete?(current_user) && @milestone.active? + .alert.alert-success.prepend-top-default + %span All issues for this milestone are closed. You may close this milestone now. = render 'shared/milestones/summary', milestone: @milestone, project: @project = render 'shared/milestones/tabs', milestone: @milestone diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb new file mode 100644 index 00000000000..c2c7acff3e8 --- /dev/null +++ b/spec/features/milestone_spec.rb @@ -0,0 +1,35 @@ +require 'rails_helper' + +feature 'Milestone', feature: true do + include WaitForAjax + + let(:project) { create(:project, :public) } + let(:user) { create(:user) } + let(:milestone) { create(:milestone, project: project, title: 8.7) } + + before do + project.team << [user, :master] + login_as(user) + end + + feature 'Create a milestone' do + scenario 'should show an informative message for a new issue' do + visit new_namespace_project_milestone_path(project.namespace, project) + page.within '.milestone-form' do + fill_in "milestone_title", with: '8.7' + end + find('input[name="commit"]').click + + expect(find('.alert-success')).to have_content('Assign some issues to this milestone.') + end + end + + feature 'Open a milestone with closed issues' do + scenario 'should show an informative message' do + create(:issue, title: "Bugfix1", project: project, milestone: milestone, state: "closed") + visit namespace_project_milestone_path(project.namespace, project, milestone) + + expect(find('.alert-success')).to have_content('All issues for this milestone are closed. You may close this milestone now.') + end + end +end -- cgit v1.2.1 From 0ea9e477229830c7fb82bd6beaaf8fcdd9d0129e Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 29 Apr 2016 12:21:20 +0200 Subject: Remove deprecated CI badge helper Closes #13446 --- app/helpers/ci_badge_helper.rb | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 app/helpers/ci_badge_helper.rb diff --git a/app/helpers/ci_badge_helper.rb b/app/helpers/ci_badge_helper.rb deleted file mode 100644 index 27386133e36..00000000000 --- a/app/helpers/ci_badge_helper.rb +++ /dev/null @@ -1,13 +0,0 @@ -module CiBadgeHelper - def markdown_badge_code(project, ref) - url = status_ci_project_url(project, ref: ref, format: 'png') - link = namespace_project_commits_path(project.namespace, project, ref) - "[![build status](#{url})](#{link})" - end - - def html_badge_code(project, ref) - url = status_ci_project_url(project, ref: ref, format: 'png') - link = namespace_project_commits_path(project.namespace, project, ref) - "" - end -end -- cgit v1.2.1 From 39ed7c18e9881416a7ca8b689a3e1fdde91f12c2 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 29 Apr 2016 12:44:23 +0200 Subject: Fixed CHANGELOG for 8.7.1/8.7.2 [ci skip] --- CHANGELOG | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d453ae19e77..569185fa2a1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,7 +13,10 @@ v 8.8.0 (unreleased) - Backport GitLab Enterprise support from EE - Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718 -v 8.7.1 (unreleased) +v 8.7.2 + - The "New Branch" button is now loaded asynchronously + +v 8.7.1 - Throttle the update of `project.last_activity_at` to 1 minute. !3848 - Fix .gitlab-ci.yml parsing issue when hidde job is a template without script definition. !3849 - Fix license detection to detect all license files, not only known licenses. !3878 @@ -21,7 +24,6 @@ v 8.7.1 (unreleased) - Prevent users from deleting Webhooks via API they do not own - Fix Error 500 due to stale cache when projects are renamed or transferred - Update width of search box to fix Safari bug. !3900 (Jedidiah) - - The "New Branch" button is now loaded asynchronously - Use the `can?` helper instead of `current_user.can?` v 8.7.0 -- cgit v1.2.1 From 28dcdb27795de79337df7aeff1107114cdffc2f9 Mon Sep 17 00:00:00 2001 From: Matt Oakes Date: Mon, 14 Mar 2016 23:33:00 +0000 Subject: Support supressing text file diffs on the default branch with .gitattributes This is a combination of 3 commits. - Update the bare repositories info/attributes if the default branch is updated - Check the diff attributes of a file before showing a diff - Update CHANGELOG --- CHANGELOG | 1 + Gemfile.lock | 6 +++--- app/models/project.rb | 1 + app/models/repository.rb | 10 ++++++++++ app/services/git_push_service.rb | 9 +++++++++ app/views/projects/diffs/_file.html.haml | 26 +++++++++++++------------- spec/models/repository_spec.rb | 10 ++++++++++ spec/services/git_push_service_spec.rb | 30 ++++++++++++++++++++++++++++++ 8 files changed, 77 insertions(+), 16 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d453ae19e77..370b2856b43 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ v 8.8.0 (unreleased) - Added button to toggle whitespaces changes on diff view - Backport GitLab Enterprise support from EE - Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718 + - Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes) v 8.7.1 (unreleased) - Throttle the update of `project.last_activity_at` to 1 minute. !3848 diff --git a/Gemfile.lock b/Gemfile.lock index 91d89b4875a..1dcda0daff6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -184,7 +184,7 @@ GEM encryptor (1.3.0) equalizer (0.0.11) erubis (2.7.0) - escape_utils (1.1.0) + escape_utils (1.1.1) eventmachine (1.0.8) excon (0.45.4) execjs (2.6.0) @@ -334,7 +334,7 @@ GEM json get_process_mem (0.2.0) gherkin-ruby (0.3.2) - github-linguist (4.7.5) + github-linguist (4.7.6) charlock_holmes (~> 0.7.3) escape_utils (~> 1.1.0) mime-types (>= 1.19) @@ -351,7 +351,7 @@ GEM posix-spawn (~> 0.3) gitlab_emoji (0.3.1) gemojione (~> 2.2, >= 2.2.1) - gitlab_git (10.0.0) + gitlab_git (10.0.1) activesupport (~> 4.0) charlock_holmes (~> 0.7.3) github-linguist (~> 4.7.0) diff --git a/app/models/project.rb b/app/models/project.rb index 0420c6a61ae..5c6c36e6b31 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -901,6 +901,7 @@ class Project < ActiveRecord::Base repository.rugged.references.create('HEAD', "refs/heads/#{branch}", force: true) + repository.copy_gitattributes(branch) reload_default_branch end diff --git a/app/models/repository.rb b/app/models/repository.rb index d495c8d18f5..b4319297e43 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -938,6 +938,16 @@ class Repository raw_repository.ls_files(actual_ref) end + def copy_gitattributes(ref) + actual_ref = ref || root_ref + begin + raw_repository.copy_gitattributes(actual_ref) + true + rescue Gitlab::Git::Repository::InvalidRef + false + end + end + def main_language return if empty? || rugged.head_unborn? diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 1e1be8cd04b..b7af80055bf 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -42,7 +42,12 @@ class GitPushService < BaseService # Collect data for this git push @push_commits = @project.repository.commits_between(params[:oldrev], params[:newrev]) process_commit_messages + + # Update the bare repositories info/attributes file using the contents of the default branches + # .gitattributes file + update_gitattributes if is_default_branch? end + # Update merge requests that may be affected by this push. A new branch # could cause the last commit of a merge request to change. update_merge_requests @@ -54,6 +59,10 @@ class GitPushService < BaseService perform_housekeeping end + def update_gitattributes + @project.repository.copy_gitattributes(params[:ref]) + end + def update_main_language # Performance can be bad so for now only check main_language once # See https://gitlab.com/gitlab-org/gitlab-ce/issues/14937 diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml index 83a8d7ae9bf..0f04fc5d33c 100644 --- a/app/views/projects/diffs/_file.html.haml +++ b/app/views/projects/diffs/_file.html.haml @@ -40,19 +40,19 @@ = view_file_btn(diff_commit.id, diff_file, project) .diff-content.diff-wrap-lines - -# Skipp all non non-supported blobs + - # 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. - - else - - if blob_text_viewable?(blob) - - 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 - - elsif blob.image? - - old_file = project.repository.prev_blob_for_diff(diff_commit, diff_file) - = render "projects/diffs/image", diff_file: diff_file, old_file: old_file, file: blob, index: i, diff_refs: diff_refs + .nothing-here-block This diff could not be displayed because it is too large. + - elsif blob_text_viewable?(blob) && !project.repository.diffable?(blob) + .nothing-here-block This diff was suppressed by a .gitattributes entry. + - elsif blob_text_viewable?(blob) + - if diff_view == 'parallel' + = render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob, index: i - else - .nothing-here-block No preview for this file type + = render "projects/diffs/text_file", diff_file: diff_file, index: i + - elsif blob.image? + - old_file = project.repository.prev_blob_for_diff(diff_commit, diff_file) + = render "projects/diffs/image", diff_file: diff_file, old_file: old_file, file: blob, index: i, diff_refs: diff_refs + - else + .nothing-here-block No preview for this file type diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index a306cc4aef8..397bb5a8028 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -795,6 +795,16 @@ describe Repository, models: true do end + describe "#copy_gitattributes" do + it 'returns true with a valid ref' do + expect(repository.copy_gitattributes('master')).to be_truthy + end + + it 'returns false with an invalid ref' do + expect(repository.copy_gitattributes('invalid')).to be_falsey + end + end + describe "#main_language" do it 'shows the main language of the project' do expect(repository.main_language).to eq("Ruby") diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index b40a5c1c818..eeab540c2fd 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -201,6 +201,36 @@ describe GitPushService, services: true do end + describe "Updates git attributes" do + context "for default branch" do + it "calls the copy attributes method for the first push to the default branch" do + expect(project.repository).to receive(:copy_gitattributes).with('master') + + execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master') + end + + it "calls the copy attributes method for changes to the default branch" do + expect(project.repository).to receive(:copy_gitattributes).with('refs/heads/master') + + execute_service(project, user, 'oldrev', 'newrev', 'refs/heads/master') + end + end + + context "for non-default branch" do + before do + # Make sure the "default" branch is different + allow(project).to receive(:default_branch).and_return('not-master') + end + + it "does not call copy attributes method" do + expect(project.repository).not_to receive(:copy_gitattributes) + + execute_service(project, user, @oldrev, @newrev, @ref) + end + end + end + + describe "Webhooks" do context "execute webhooks" do it "when pushing a branch for the first time" do -- cgit v1.2.1 From 3811eb0ba1e8c0f318060696853b1cab7f99dfa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 26 Apr 2016 12:54:49 +0200 Subject: Fix error when trying to create a wiki page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #15527. Signed-off-by: Rémy Coutable --- CHANGELOG | 3 +- app/controllers/projects/wikis_controller.rb | 4 +- app/services/wiki_pages/create_service.rb | 3 +- .../projects/wiki/user_creates_wiki_page_spec.rb | 87 ++++++++++++++++++++++ .../projects/wiki/user_updates_wiki_page_spec.rb | 46 ++++++++++++ 5 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 spec/features/projects/wiki/user_creates_wiki_page_spec.rb create mode 100644 spec/features/projects/wiki/user_updates_wiki_page_spec.rb diff --git a/CHANGELOG b/CHANGELOG index ed151df9e25..bcbcdfc3fc6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,8 +15,9 @@ v 8.8.0 (unreleased) - Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718 - Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes) -v 8.7.2 +v 8.7.2 (unreleased) - The "New Branch" button is now loaded asynchronously + - Fix error 500 when trying to create a wiki page v 8.7.1 - Throttle the update of `project.last_activity_at` to 1 minute. !3848 diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb index c02bc28acef..0d6c32fabd2 100644 --- a/app/controllers/projects/wikis_controller.rb +++ b/app/controllers/projects/wikis_controller.rb @@ -40,10 +40,10 @@ class Projects::WikisController < Projects::ApplicationController end def update - @page = @project_wiki.find_page(params[:id]) - return render('empty') unless can?(current_user, :create_wiki, @project) + @page = @project_wiki.find_page(params[:id]) + if @page = WikiPages::UpdateService.new(@project, current_user, wiki_params).execute(@page) redirect_to( namespace_project_wiki_path(@project.namespace, @project, @page), diff --git a/app/services/wiki_pages/create_service.rb b/app/services/wiki_pages/create_service.rb index 988c663b9d0..24a817c06c9 100644 --- a/app/services/wiki_pages/create_service.rb +++ b/app/services/wiki_pages/create_service.rb @@ -1,7 +1,8 @@ module WikiPages class CreateService < WikiPages::BaseService def execute - page = WikiPage.new(@project.wiki) + project_wiki = ProjectWiki.new(@project, current_user) + page = WikiPage.new(project_wiki) if page.create(@params) execute_hooks(page, 'create') diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb new file mode 100644 index 00000000000..d709fe8046f --- /dev/null +++ b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb @@ -0,0 +1,87 @@ +require 'spec_helper' + +feature 'Projects > Wiki > User creates wiki page', feature: true do + let(:user) { create(:user) } + + background do + project.team << [user, :master] + login_as(user) + + visit namespace_project_path(project.namespace, project) + click_link 'Wiki' + end + + context 'wiki project is in the user namespace' do + let(:project) { create(:project, namespace: user.namespace) } + + context 'when wiki is empty' do + scenario 'user can create a new wiki page from the wiki home page' do + expect(page).to have_content('Home · Edit Page') + + fill_in :wiki_content, with: 'My awesome wiki!' + click_button 'Create page' + + expect(page).to have_content("Home · last edited by #{user.name}") + expect(page).to have_content('My awesome wiki!') + end + end + + context 'when wiki is not empty' do + before do + WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute + end + + scenario 'user can create a new wiki page', js: true do + click_link 'New Page' + + fill_in :new_wiki_path, with: 'foo' + click_button 'Create Page' + + expect(page).to have_content('Foo · Edit Page') + + fill_in :wiki_content, with: 'My awesome wiki!' + click_button 'Create page' + + expect(page).to have_content("Foo · last edited by #{user.name}") + expect(page).to have_content('My awesome wiki!') + end + end + end + + context 'wiki project is in the user namespace' do + let(:project) { create(:project, namespace: create(:group, :public)) } + + context 'when wiki is empty' do + scenario 'user can create a new wiki page from the wiki home page' do + expect(page).to have_content('Home · Edit Page') + + fill_in :wiki_content, with: 'My awesome wiki!' + click_button 'Create page' + + expect(page).to have_content("Home · last edited by #{user.name}") + expect(page).to have_content('My awesome wiki!') + end + end + + context 'when wiki is not empty' do + before do + WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute + end + + scenario 'user can create a new wiki page', js: true do + click_link 'New Page' + + fill_in :new_wiki_path, with: 'foo' + click_button 'Create Page' + + expect(page).to have_content('Foo · Edit Page') + + fill_in :wiki_content, with: 'My awesome wiki!' + click_button 'Create page' + + expect(page).to have_content("Foo · last edited by #{user.name}") + expect(page).to have_content('My awesome wiki!') + end + end + end +end diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb new file mode 100644 index 00000000000..b69d6b46ac8 --- /dev/null +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +feature 'Projects > Wiki > User updates wiki page', feature: true do + let(:user) { create(:user) } + + background do + project.team << [user, :master] + login_as(user) + + visit namespace_project_path(project.namespace, project) + WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute + click_link 'Wiki' + end + + context 'wiki project is in the user namespace' do + let(:project) { create(:project, namespace: user.namespace) } + + scenario 'user can update the wiki home page' do + click_link 'Edit' + + expect(page).to have_content('Home · Edit Page') + + fill_in :wiki_content, with: 'My awesome wiki!' + click_button 'Save changes' + + expect(page).to have_content("Home · last edited by #{user.name}") + expect(page).to have_content('My awesome wiki!') + end + end + + context 'wiki project is in the user namespace' do + let(:project) { create(:project, namespace: create(:group, :public)) } + + scenario 'user can update the wiki home page' do + click_link 'Edit' + + expect(page).to have_content('Home · Edit Page') + + fill_in :wiki_content, with: 'My awesome wiki!' + click_button 'Save changes' + + expect(page).to have_content("Home · last edited by #{user.name}") + expect(page).to have_content('My awesome wiki!') + end + end +end -- cgit v1.2.1 From b2ec176539dd7caf8ae463776175e00c80199470 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 28 Apr 2016 10:32:32 +0100 Subject: Removes duplicates from the label dropdown It concats the duplicate labels into a single label in the dropdown with the color being a gradient of the differnet colors being concatted. Closes #16555 --- app/assets/javascripts/labels_select.js.coffee | 40 ++++++++++++++++++++++++-- spec/features/dashboard/label_filter_spec.rb | 29 +++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 spec/features/dashboard/label_filter_spec.rb diff --git a/app/assets/javascripts/labels_select.js.coffee b/app/assets/javascripts/labels_select.js.coffee index 7d61cd9bf73..995fd768603 100644 --- a/app/assets/javascripts/labels_select.js.coffee +++ b/app/assets/javascripts/labels_select.js.coffee @@ -163,6 +163,21 @@ class @LabelsSelect $.ajax( url: labelUrl ).done (data) -> + data = _.chain data + .groupBy (label) -> + label.title + .map (label) -> + color = _.map label, (dup) -> + dup.color + + return { + id: label[0].id + title: label[0].title + color: color + duplicate: color.length > 1 + } + .value() + if $dropdown.hasClass 'js-extra-options' if showNo data.unshift( @@ -178,6 +193,7 @@ class @LabelsSelect if data.length > 2 data.splice 2, 0, 'divider' + callback data renderRow: (label) -> @@ -192,11 +208,31 @@ class @LabelsSelect if $dropdown.hasClass('js-multiselect') and removesAll selectedClass.push 'dropdown-clear-active' - color = if label.color? then "" else "" + if label.duplicate + spacing = 100 / label.color.length + + # Reduce the colors to 4 + label.color = label.color.filter (color, i) -> + i < 4 + + color = _.map(label.color, (color, i) -> + percentFirst = Math.floor(spacing * i) + percentSecond = Math.floor(spacing * (i + 1)) + "#{color} #{percentFirst}%,#{color} #{percentSecond}% " + ).join(',') + color = "linear-gradient(#{color})" + else + if label.color? + color = label.color[0] + + if color + colorEl = "" + else + colorEl = '' "
              • - #{color} + #{colorEl} #{_.escape(label.title)}
              • " diff --git a/spec/features/dashboard/label_filter_spec.rb b/spec/features/dashboard/label_filter_spec.rb new file mode 100644 index 00000000000..24e83d44010 --- /dev/null +++ b/spec/features/dashboard/label_filter_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe 'Dashboard > label filter', feature: true, js: true do + let(:user) { create(:user) } + let(:project) { create(:project, name: 'test', namespace: user.namespace) } + let(:project2) { create(:project, name: 'test2', path: 'test2', namespace: user.namespace) } + let(:label) { create(:label, title: 'bug', color: '#ff0000') } + let(:label2) { create(:label, title: 'bug') } + + before do + project.labels << label + project2.labels << label2 + + login_as(user) + visit issues_dashboard_path + end + + context 'duplicate labels' do + it 'should remove duplicate labels' do + page.within('.labels-filter') do + click_button 'Label' + end + + page.within('.dropdown-menu-labels') do + expect(page).to have_selector('.dropdown-content a', text: 'bug', count: 1) + end + end + end +end -- cgit v1.2.1 From 6e5f0fbad47c28d3cf33fd52296e278ed4625d5a Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Fri, 29 Apr 2016 12:08:53 -0400 Subject: Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index ed151df9e25..5bd897126b2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ v 8.8.0 (unreleased) - Backport GitLab Enterprise support from EE - Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718 - Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes) + - Added multiple colors for labels in dropdowns when dups happen. v 8.7.2 - The "New Branch" button is now loaded asynchronously -- cgit v1.2.1 From f3f820d0bd579bdaba19cf6043aa5fadd4216b98 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 29 Apr 2016 19:02:30 +0200 Subject: Move modal css to separate file and fix danger text for confirmation modal Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework.scss | 1 + app/assets/stylesheets/framework/modal.scss | 22 ++++++++++++++++++++++ app/assets/stylesheets/pages/help.scss | 19 ------------------- app/views/shared/_confirm_modal.html.haml | 2 +- 4 files changed, 24 insertions(+), 20 deletions(-) create mode 100644 app/assets/stylesheets/framework/modal.scss diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss index c85ab9148d0..560de9fc0bd 100644 --- a/app/assets/stylesheets/framework.scss +++ b/app/assets/stylesheets/framework.scss @@ -25,6 +25,7 @@ @import "framework/lists.scss"; @import "framework/markdown_area.scss"; @import "framework/mobile.scss"; +@import "framework/modal.scss"; @import "framework/nav.scss"; @import "framework/pagination.scss"; @import "framework/progress.scss"; diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss new file mode 100644 index 00000000000..26ad2870aa0 --- /dev/null +++ b/app/assets/stylesheets/framework/modal.scss @@ -0,0 +1,22 @@ +.modal-body { + position: relative; + overflow-y: auto; + padding: 15px; + + .form-actions { + margin: -$gl-padding+1; + margin-top: 15px; + } + + .text-danger { + font-weight: bold; + } +} + +body.modal-open { + overflow: hidden; +} + +.modal .modal-dialog { + width: 860px; +} diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss index ee95bdf488e..4a95b7b852e 100644 --- a/app/assets/stylesheets/pages/help.scss +++ b/app/assets/stylesheets/pages/help.scss @@ -55,25 +55,6 @@ } } -.modal-body { - position: relative; - overflow-y: auto; - padding: 15px; - - .form-actions { - margin: -$gl-padding+1; - margin-top: 15px; - } -} - -body.modal-open { - overflow: hidden; -} - -.modal .modal-dialog { - width: 860px; -} - .documentation { padding: 7px; } diff --git a/app/views/shared/_confirm_modal.html.haml b/app/views/shared/_confirm_modal.html.haml index 34241cd8aad..b0fc60573f7 100644 --- a/app/views/shared/_confirm_modal.html.haml +++ b/app/views/shared/_confirm_modal.html.haml @@ -7,7 +7,7 @@ Confirmation required .modal-body - %p.cred.lead.js-confirm-text + %p.text-danger.js-confirm-text %p This action can lead to data loss. -- cgit v1.2.1 From f49d86cd5c680ba233e4cb46c51748d83e2f562e Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Fri, 29 Apr 2016 13:11:23 -0600 Subject: Fix some broken links in the documentation [ci skip] --- doc/monitoring/performance/gitlab_configuration.md | 2 +- doc/monitoring/performance/influxdb_configuration.md | 2 +- doc/monitoring/performance/influxdb_schema.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/monitoring/performance/gitlab_configuration.md b/doc/monitoring/performance/gitlab_configuration.md index 90e99302210..771584268d9 100644 --- a/doc/monitoring/performance/gitlab_configuration.md +++ b/doc/monitoring/performance/gitlab_configuration.md @@ -37,4 +37,4 @@ Read more on: - [Introduction to GitLab Performance Monitoring](introduction.md) - [InfluxDB Configuration](influxdb_configuration.md) - [InfluxDB Schema](influxdb_schema.md) -- [Grafana Install/Configuration](grafana_configuration.md +- [Grafana Install/Configuration](grafana_configuration.md) diff --git a/doc/monitoring/performance/influxdb_configuration.md b/doc/monitoring/performance/influxdb_configuration.md index 63aa03985ef..c30cd2950d8 100644 --- a/doc/monitoring/performance/influxdb_configuration.md +++ b/doc/monitoring/performance/influxdb_configuration.md @@ -181,7 +181,7 @@ Read more on: - [Introduction to GitLab Performance Monitoring](introduction.md) - [GitLab Configuration](gitlab_configuration.md) - [InfluxDB Schema](influxdb_schema.md) -- [Grafana Install/Configuration](grafana_configuration.md +- [Grafana Install/Configuration](grafana_configuration.md) [influxdb-retention]: https://docs.influxdata.com/influxdb/v0.9/query_language/database_management/#retention-policy-management [influxdb documentation]: https://docs.influxdata.com/influxdb/v0.9/ diff --git a/doc/monitoring/performance/influxdb_schema.md b/doc/monitoring/performance/influxdb_schema.md index d31b3788f36..41861860b6d 100644 --- a/doc/monitoring/performance/influxdb_schema.md +++ b/doc/monitoring/performance/influxdb_schema.md @@ -85,4 +85,4 @@ Read more on: - [Introduction to GitLab Performance Monitoring](introduction.md) - [GitLab Configuration](gitlab_configuration.md) - [InfluxDB Configuration](influxdb_configuration.md) -- [Grafana Install/Configuration](grafana_configuration.md +- [Grafana Install/Configuration](grafana_configuration.md) -- cgit v1.2.1 From e28d1fa3cc2e8c2f696f6740c8a8441100542470 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 29 Apr 2016 22:21:06 +0200 Subject: Use a query in Project#protected_branch? This changes Project#protected_branch? to use a query to check if a branch is protected, instead of loading all ProtectedBranch records into memory just to check if the list of names includes a given branch name. --- app/models/project.rb | 2 +- spec/models/project_spec.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index 5c6c36e6b31..bbc929e9bd4 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -764,7 +764,7 @@ class Project < ActiveRecord::Base # Check if current branch name is marked as protected in the system def protected_branch?(branch_name) - protected_branches_names.include?(branch_name) + protected_branches.where(name: branch_name).any? end def developers_can_push_to_protected_branch?(branch_name) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index e33c7d62ff4..5b1cf71337e 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -798,4 +798,18 @@ describe Project, models: true do end end end + + describe '#protected_branch?' do + let(:project) { create(:empty_project) } + + it 'returns true when a branch is a protected branch' do + project.protected_branches.create!(name: 'foo') + + expect(project.protected_branch?('foo')).to eq(true) + end + + it 'returns false when a branch is not a protected branch' do + expect(project.protected_branch?('foo')).to eq(false) + end + end end -- cgit v1.2.1 From b6a18f1093c88e82d2320d4d3f3c15c549b861be Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 29 Apr 2016 22:33:56 +0200 Subject: Tweak checking branches in Project#open_branches This changes 4 things: 1. Project#protected_branches_names has been renamed to Project#protected_branch_names. 2. Project#open_branches uses a Set for the branch names as checking values in a Set is faster than checking values in a (large) Array. 3. Some redundant code in Project#open_branches has been removed. 4. Project#protected_branch_names now uses #pluck instead of #map, removing the need for loading entire DB records into memory. --- CHANGELOG | 1 + app/models/project.rb | 16 +++++++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5bd897126b2..121b03be320 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.8.0 (unreleased) + - Project#open_branches has been cleaned up and no longer loads entire records into memory. - Make build status canceled if any of the jobs was canceled and none failed - Remove future dates from contribution calendar graph. - Use ActionDispatch Remote IP for Akismet checking diff --git a/app/models/project.rb b/app/models/project.rb index bbc929e9bd4..af62e8ecd90 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -735,19 +735,17 @@ class Project < ActiveRecord::Base end def open_branches - all_branches = repository.branches + # We're using a Set here as checking values in a large Set is faster than + # checking values in a large Array. + protected_set = Set.new(protected_branch_names) - if protected_branches.present? - all_branches.reject! do |branch| - protected_branches_names.include?(branch.name) - end + repository.branches.reject do |branch| + protected_set.include?(branch.name) end - - all_branches end - def protected_branches_names - @protected_branches_names ||= protected_branches.map(&:name) + def protected_branch_names + @protected_branch_names ||= protected_branches.pluck(:name) end def root_ref?(branch) -- cgit v1.2.1 From b47a84b4be5781c91bf1072dcfa765b6782f0a35 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 28 Apr 2016 21:44:21 +0200 Subject: Added performance guidelines Fixes gitlab-org/gitlab-ce#15254 gitlab-org/gitlab-ce#14277 [ci skip] --- doc/development/README.md | 1 + doc/development/performance.md | 258 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+) create mode 100644 doc/development/performance.md diff --git a/doc/development/README.md b/doc/development/README.md index 3f3ef068f96..aa7d54c01d0 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -8,6 +8,7 @@ - [How to dump production data to staging](db_dump.md) - [Instrumentation](instrumentation.md) - [Migration Style Guide](migration_style_guide.md) for creating safe migrations +- [Performance guidelines](performance.md) - [Rake tasks](rake_tasks.md) for development - [Shell commands](shell_commands.md) in the GitLab codebase - [Sidekiq debugging](sidekiq_debugging.md) diff --git a/doc/development/performance.md b/doc/development/performance.md new file mode 100644 index 00000000000..c74198650e5 --- /dev/null +++ b/doc/development/performance.md @@ -0,0 +1,258 @@ +# Performance Guidelines + +This document describes various guidelines to follow to ensure good and +consistent performance of GitLab. + +## Workflow + +The process of solving performance problems is roughly as follows: + +1. Make sure there's an issue open somewhere (e.g. on the GitLab CE issue + tracker), create one if there isn't. See [#15607][#15607] for an example. +2. Measure the performance of the code in a production environment such as + GitLab.com (see the [Tooling](#tooling) section below). Performance should be + measured over a period of _at least_ 24 hours. +3. Add your findings based on the measurement period (screenshots of graphs, + timings, etc) to the issue mentioned in step 1. +4. Solve the problem. +5. Create a merge request, assign the "performance" label and ping the right + people (e.g. [@yorickpeterse][@yorickpeterse] and [@joshfng][@joshfng]). +6. Once a change has been deployed make sure to _again_ measure for at least 24 + hours to see if your changes have any impact on the production environment. +7. Repeat until you're done. + +When providing timings make sure to provide: + +* The 95th percentile +* The 99th percentile +* The mean + +When providing screenshots of graphs make sure that both the X and Y axes and +the legend are clearly visible. If you happen to have access to GitLab.com's own +monitoring tools you should also provide a link to any relevant +graphs/dashboards. + +## Tooling + +GitLab provides two built-in tools to aid the process of improving performance: + +* [Sherlock](doc/development/profiling.md#sherlock) +* [GitLab Performance Monitoring](doc/monitoring/performance) + +GitLab employees can use GitLab.com's performance monitoring systems located at +, this requires you to log in using your +`@gitlab.com` Email address. Non-GitLab employees are advised to set up their +own InfluxDB + Grafana stack. + +## Benchmarks + +Benchmarks are almost always useless. Benchmarks usually only test small bits of +code in isolation and often only measure the best case scenario. On top of that, +benchmarks for libraries (e.g. a Gem) tend to be biased in favour of the +library. After all there's little benefit to an author publishing a benchmark +that shows they perform worse than their competitors. + +Benchmarks are only really useful when you need a rough (emphasis on "rough") +understanding of the impact of your changes. For example, if a certain method is +slow a benchmark can be used to see if the changes you're making have any impact +on the method's performance. However, even when a benchmark shows your changes +improve performance there's no guarantee the performance also improves in a +production environment. + +When writing benchmarks you should almost always use +[benchmark-ips](https://github.com/evanphx/benchmark-ips). Ruby's `Benchmark` +module that comes with the standard library is rarely useful as it runs either a +single iteration (when using `Benchmark.bm`) or two iterations (when using +`Benchmark.bmbm`). Running this few iterations means external factors (e.g. a +video streaming in the background) can very easily skew the benchmark +statistics. + +Another problem with the `Benchmark` module is that it displays timings, not +iterations. This means that if a piece of code completes in a very short period +of time it can be very difficult to compare the timings before and after a +certain change. This in turn leads to patterns such as the following: + +```ruby +Benchmark.bmbm(10) do |bench| + bench.report 'do something' do + 100.times do + ... work here ... + end + end +end +``` + +This however leads to the question: how many iterations should we run to get +meaningful statistics? + +The benchmark-ips Gem basically takes care of all this and much more, and as a +result of this should be used instead of the `Benchmark` module. + +In short: + +1. Don't trust benchmarks you find on the internet. +2. Never make claims based on just benchmarks, always measure in production to + confirm your findings. +3. X being N times faster than Y is meaningless if you don't know what impact it + will actually have on your production environment. +4. A production environment is the _only_ benchmark that always tells the truth + (unless your performance monitoring systems are not set up correctly). +5. If you must write a benchmark use the benchmark-ips Gem instead of Ruby's + `Benchmark` module. + +## Importance of Changes + +When working on performance improvements it's important to always ask yourself +the question "How important is it to improve the performance of this piece of +code?". Not every piece of code is equally important and it would be a waste to +spend a week trying to improve something that only impacts a tiny fraction of +our users. For example, spending a week trying to squeeze 10 milliseconds out of +a method is a waste of time when you could have spent a week squeezing out 10 +seconds elsewhere. + +There is no clear set of steps that you can follow to determine if a certain +piece of code is worth optimizing. The only two things you can do are: + +1. Think about what the code does, how it's used, how many times it's called and + how much time is spent in it relative to the total execution time (e.g. the + total time spent in a web request). +2. Ask others (preferably in the form of an issue). + +Some examples of changes that aren't really important/worth the effort: + +* Replacing double quotes with single quotes. +* Replacing usage of Array with Set when the list of values is very small. +* Replacing library A with library B when both only take up 0.1% of the total + execution time. +* Calling `freeze` on every string (see [String Freezing](#string-freezing)). + +## Slow Operations & Sidekiq + +Slow operations (e.g. merging branches) or operations that are prone to errors +(using external APIs) should be performed in a Sidekiq worker instead of +directly in a web request as much as possible. This has numerous benefits such +as: + +1. An error won't prevent the request from completing. +2. The process being slow won't affect the loading time of a page. +3. In case of a failure it's easy to re-try the process (Sidekiq takes care of + this automatically). +4. By isolating the code from a web request it will hopefully be easier to test + and maintain. + +It's especially important to use Sidekiq as much as possible when dealing with +Git operations as these operations can take quite some time to complete +depending on the performance of the underlying storage system. + +## Git Operations + +Care should be taken to not run unnecessary Git operations. For example, +retrieving the list of branch names using `Repository#branch_names` can be done +without an explicit check if a repository exists or not. In other words, instead +of this: + +```ruby +if repository.exists? + repository.branch_names.each do |name| + ... + end +end +``` + +You can instead just write: + +```ruby +repository.branch_names.each do |name| + ... +end +``` + +## Caching + +Operations that will often return the same result should be cached using Redis, +in particular Git operations. When caching data in Redis make sure the cache is +flushed whenever needed. For example, a cache for the list of tags should be +flushed whenever a new tag is pushed or a tag is removed. + +When adding cache expiration code for repositories this code should be placed in +one of the before/after hooks residing in the Repository class. For example, if +a cache should be flushed after importing a repository this code should be added +to `Repository#after_import`. This ensures the cache logic stays within the +Repository class instead of leaking into other classes. + +When caching data make sure to also memoize the result in an instance variable. +While retrieving data from Redis is much faster than raw Git operations it still +has overhead. By caching the result in an instance variable repeated calls to +the same method won't end up retrieving data from Redis upon every call. When +memoizing cached data in an instance variable make sure to also reset the +instance variable when flushing the cache. An example: + + +```ruby +def first_branch + @first_branch ||= cache.fetch(:first_branch) { branches.first } +end + +def expire_first_branch_cache + cache.expire(:first_branch) + @first_branch = nil +end +``` + +## Anti-Patterns + +This is a collection of [anti-patterns][anti-pattern] that should be avoided +unless these changes have a measurable, significant and positive impact on +production environments. + +### String Freezing + +In recent Ruby versions calling `freeze` on a String leads to it being allocated +only once and re-used. For example, on Ruby 2.3 this will only allocate the +"foo" String once: + +```ruby +10.times do + 'foo'.freeze +end +``` + +Blindly adding a `.freeze` call to every String is an anti-pattern that should +be avoided unless one can prove (using production data) the call actually has a +positive impact on performance. + +This feature of Ruby wasn't really meant to make things faster directly, instead +it was meant to reduce the number of allocations. Depending on the size of the +String and how frequently it would be allocated (before the `.freeze` call was +added) this _may_ make things faster, but there's no guarantee it will. + +Another common flavour of this is to not only freeze a String but also assign it +to a constant, for example: + +```ruby +SOME_CONSTANT = 'foo'.freeze + +9000.times do + SOME_CONSTANT +end +``` + +The only reason you should be doing this is to prevent somebody from mutating +the global String. However, since you can just re-assign constants in Ruby +there's nothing stopping somebody from doing this elsewhere in the code: + +```ruby +SOME_CONSTANT = 'bar' +``` + +### Moving Allocations to Constants + +Storing an object as a constant so you only allocate it once _may_ improve +performance but there's no guarantee this will. Looking up constants has an +impact on runtime performance and as such using a constant instead of +referencing an object directly may even slow code down. + +[#15607]: https://gitlab.com/gitlab-org/gitlab-ce/issues/15607 +[@yorickpeterse]: https://gitlab.com/u/yorickpeterse +[@joshfng]: https://gitlab.com/u/joshfng +[anti-pattern]: https://en.wikipedia.org/wiki/Anti-pattern -- cgit v1.2.1 From 8d3debe4cc964d830a2f21a7e950f143cc9008ca Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Thu, 28 Apr 2016 12:12:03 -0600 Subject: Add more parameters to the filter_parameters config. Adds Sentry DSN, Webhooks, Deploy Keys, etc. Alphabetized the parameters and included line breaks between each parameter. Easier to merge into EE if there are any differences. This also seems to be the more popular syntax for adding new parameters, from what I can find. --- config/application.rb | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/config/application.rb b/config/application.rb index 2e2ed48db07..b602e2b6168 100644 --- a/config/application.rb +++ b/config/application.rb @@ -32,7 +32,30 @@ module Gitlab config.encoding = "utf-8" # Configure sensitive parameters which will be filtered from the log file. - config.filter_parameters.push(:password, :password_confirmation, :private_token, :otp_attempt, :variables, :import_url) + # + # Parameters filtered: + # - Password (:password, :password_confirmation) + # - Private tokens (:private_token) + # - Two-factor tokens (:otp_attempt) + # - Repo/Project Import URLs (:import_url) + # - Build variables (:variables) + # - GitLab Pages SSL cert/key info (:certificate, :encrypted_key) + # - Webhook URLs (:hook) + # - Sentry DSN (:sentry_dsn) + # - Deploy keys (:key) + config.filter_parameters += %i( + certificate + encrypted_key + hook + import_url + key + otp_attempt + password + password_confirmation + private_token + sentry_dsn + variables + ) # Enable escaping HTML in JSON. config.active_support.escape_html_entities_in_json = true -- cgit v1.2.1 From 0cd5edf35cfaca74344dd389aadd65f0f179d395 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Wed, 27 Apr 2016 04:24:49 -0300 Subject: Backported minimal safewebhook implementation to GitLab CE --- app/models/hooks/project_hook.rb | 1 + app/models/hooks/service_hook.rb | 1 + app/models/hooks/system_hook.rb | 1 + app/models/hooks/web_hook.rb | 24 ++++++----- .../20160413115152_add_token_to_web_hooks.rb | 5 +++ db/schema.rb | 1 + spec/factories/project_hooks.rb | 4 ++ spec/models/hooks/web_hook_spec.rb | 46 ++++++++++++++-------- 8 files changed, 58 insertions(+), 25 deletions(-) create mode 100644 db/migrate/20160413115152_add_token_to_web_hooks.rb diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb index bc6e0f98c3c..d149511b868 100644 --- a/app/models/hooks/project_hook.rb +++ b/app/models/hooks/project_hook.rb @@ -16,6 +16,7 @@ # note_events :boolean default(FALSE), not null # enable_ssl_verification :boolean default(TRUE) # build_events :boolean default(FALSE), not null +# token :string # class ProjectHook < WebHook diff --git a/app/models/hooks/service_hook.rb b/app/models/hooks/service_hook.rb index 80962264ba2..f45145eeb3a 100644 --- a/app/models/hooks/service_hook.rb +++ b/app/models/hooks/service_hook.rb @@ -16,6 +16,7 @@ # note_events :boolean default(FALSE), not null # enable_ssl_verification :boolean default(TRUE) # build_events :boolean default(FALSE), not null +# token :string # class ServiceHook < WebHook diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb index 15dddcc2447..012cc8ec005 100644 --- a/app/models/hooks/system_hook.rb +++ b/app/models/hooks/system_hook.rb @@ -16,6 +16,7 @@ # note_events :boolean default(FALSE), not null # enable_ssl_verification :boolean default(TRUE) # build_events :boolean default(FALSE), not null +# token :string # class SystemHook < WebHook diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index 3a2e4f546f7..1e3b4815596 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -16,6 +16,7 @@ # note_events :boolean default(FALSE), not null # enable_ssl_verification :boolean default(TRUE) # build_events :boolean default(FALSE), not null +# token :string # class WebHook < ActiveRecord::Base @@ -43,23 +44,17 @@ class WebHook < ActiveRecord::Base if parsed_url.userinfo.blank? response = WebHook.post(url, body: data.to_json, - headers: { - "Content-Type" => "application/json", - "X-Gitlab-Event" => hook_name.singularize.titleize - }, + headers: build_headers(hook_name), verify: enable_ssl_verification) else - post_url = url.gsub("#{parsed_url.userinfo}@", "") + post_url = url.gsub("#{parsed_url.userinfo}@", '') auth = { username: CGI.unescape(parsed_url.user), password: CGI.unescape(parsed_url.password), } response = WebHook.post(post_url, body: data.to_json, - headers: { - "Content-Type" => "application/json", - "X-Gitlab-Event" => hook_name.singularize.titleize - }, + headers: build_headers(hook_name), verify: enable_ssl_verification, basic_auth: auth) end @@ -73,4 +68,15 @@ class WebHook < ActiveRecord::Base def async_execute(data, hook_name) Sidekiq::Client.enqueue(ProjectWebHookWorker, id, data, hook_name) end + + private + + def build_headers(hook_name) + headers = { + 'Content-Type' => 'application/json', + 'X-Gitlab-Event' => hook_name.singularize.titleize + } + headers['X-Gitlab-Token'] = token if token.present? + headers + end end diff --git a/db/migrate/20160413115152_add_token_to_web_hooks.rb b/db/migrate/20160413115152_add_token_to_web_hooks.rb new file mode 100644 index 00000000000..f04225068cd --- /dev/null +++ b/db/migrate/20160413115152_add_token_to_web_hooks.rb @@ -0,0 +1,5 @@ +class AddTokenToWebHooks < ActiveRecord::Migration + def change + add_column :web_hooks, :token, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 42457d92353..04aee737e4c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1025,6 +1025,7 @@ ActiveRecord::Schema.define(version: 20160421130527) do t.boolean "enable_ssl_verification", default: true t.boolean "build_events", default: false, null: false t.boolean "wiki_page_events", default: false, null: false + t.string "token" end add_index "web_hooks", ["created_at", "id"], name: "index_web_hooks_on_created_at_and_id", using: :btree diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb index 94dd935a039..3195fb3ddcc 100644 --- a/spec/factories/project_hooks.rb +++ b/spec/factories/project_hooks.rb @@ -1,5 +1,9 @@ FactoryGirl.define do factory :project_hook do url { FFaker::Internet.uri('http') } + + trait :token do + token { SecureRandom.hex(10) } + end end end diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index 04bc2dcfb16..37a27d73aab 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -43,51 +43,65 @@ describe WebHook, models: true do end describe "execute" do + let(:project) { create(:project) } + let(:project_hook) { create(:project_hook) } + before(:each) do - @project_hook = create(:project_hook) - @project = create(:project) - @project.hooks << [@project_hook] + project.hooks << [project_hook] @data = { before: 'oldrev', after: 'newrev', ref: 'ref' } - WebMock.stub_request(:post, @project_hook.url) + WebMock.stub_request(:post, project_hook.url) + end + + context 'when token is defined' do + let(:project_hook) { create(:project_hook, :token) } + + it 'POSTs to the webhook URL' do + project_hook.execute(@data, 'push_hooks') + expect(WebMock).to have_requested(:post, project_hook.url).with( + headers: { 'Content-Type' => 'application/json', + 'X-Gitlab-Event' => 'Push Hook', + 'X-Gitlab-Token' => project_hook.token } + ).once + end end it "POSTs to the webhook URL" do - @project_hook.execute(@data, 'push_hooks') - expect(WebMock).to have_requested(:post, @project_hook.url).with( - headers: { 'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Push Hook' } + project_hook.execute(@data, 'push_hooks') + expect(WebMock).to have_requested(:post, project_hook.url).with( + headers: { 'Content-Type' => 'application/json', 'X-Gitlab-Event' => 'Push Hook' } ).once end it "POSTs the data as JSON" do - @project_hook.execute(@data, 'push_hooks') - expect(WebMock).to have_requested(:post, @project_hook.url).with( - headers: { 'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Push Hook' } + project_hook.execute(@data, 'push_hooks') + expect(WebMock).to have_requested(:post, project_hook.url).with( + headers: { 'Content-Type' => 'application/json', 'X-Gitlab-Event' => 'Push Hook' } ).once end it "catches exceptions" do expect(WebHook).to receive(:post).and_raise("Some HTTP Post error") - expect { @project_hook.execute(@data, 'push_hooks') }.to raise_error(RuntimeError) + expect { project_hook.execute(@data, 'push_hooks') }.to raise_error(RuntimeError) end it "handles SSL exceptions" do expect(WebHook).to receive(:post).and_raise(OpenSSL::SSL::SSLError.new('SSL error')) - expect(@project_hook.execute(@data, 'push_hooks')).to eq([false, 'SSL error']) + expect(project_hook.execute(@data, 'push_hooks')).to eq([false, 'SSL error']) end it "handles 200 status code" do - WebMock.stub_request(:post, @project_hook.url).to_return(status: 200, body: "Success") + WebMock.stub_request(:post, project_hook.url).to_return(status: 200, body: "Success") - expect(@project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success']) + expect(project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success']) end it "handles 2xx status codes" do - WebMock.stub_request(:post, @project_hook.url).to_return(status: 201, body: "Success") + WebMock.stub_request(:post, project_hook.url).to_return(status: 201, body: "Success") - expect(@project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success']) + expect(project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success']) end end end -- cgit v1.2.1 From c9577711cee5f9eec699711d39196480f400a746 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Sat, 30 Apr 2016 21:14:40 +0200 Subject: Handle issue move access instead of raising error Closes #15533 --- app/controllers/projects/issues_controller.rb | 2 ++ .../controllers/projects/issues_controller_spec.rb | 39 ++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 9face235baa..016f5dd0005 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -96,6 +96,8 @@ class Projects::IssuesController < Projects::ApplicationController if params[:move_to_project_id].to_i > 0 new_project = Project.find(params[:move_to_project_id]) + return render_404 unless issue.can_move?(current_user, new_project) + move_service = Issues::MoveService.new(project, current_user) @issue = move_service.execute(@issue, new_project) end diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index d6e4cd71ce6..2b2ad3b9412 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -40,6 +40,45 @@ describe Projects::IssuesController do end end + describe 'PUT #update' do + context 'when moving issue to another private project' do + let(:another_project) { create(:project, :private) } + + before do + sign_in(user) + project.team << [user, :developer] + end + + context 'when user has access to move issue' do + before { another_project.team << [user, :reporter] } + + it 'moves issue to another project' do + move_issue + + expect(response).to have_http_status :found + expect(another_project.issues).to_not be_empty + end + end + + context 'when user does not have access to move issue' do + it 'responds with 404' do + move_issue + + expect(response).to have_http_status :not_found + end + end + + def move_issue + put :update, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + id: issue.iid, + issue: { title: 'New title' }, + move_to_project_id: another_project.id + end + end + end + describe 'Confidential Issues' do let(:project) { create(:project_empty_repo, :public) } let(:assignee) { create(:assignee) } -- cgit v1.2.1 From 41df76b028aa663711b8126b2aabd7f36f254153 Mon Sep 17 00:00:00 2001 From: Karlo Soriano Date: Sun, 1 May 2016 14:43:52 +0800 Subject: Remove unnecessary method call in events view Since `User#to_param` already returns `User#username`, we don't need to pass in the user's username. Changing this also helps us obey LoD. --- app/views/events/_event.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index 5d622582088..e4629bae0e6 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -5,7 +5,7 @@ = cache [event, current_application_settings, "v2.2"] do - if event.author - = link_to user_path(event.author.username) do + = link_to user_path(event.author) do = image_tag avatar_icon(event.author_email, 40), class: "avatar s40", alt:'' - else = image_tag avatar_icon(event.author_email, 40), class: "avatar s40", alt:'' -- cgit v1.2.1 From 66d7acfe4ddec5d5f16bc6a7d758343ff8573fd9 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Sun, 1 May 2016 13:44:50 -0600 Subject: Update rspec-rails from 3.3.3 to 3.4.2. This allows the removal of the monkey patch from this commit: 47ff1c56089b3df9c36b77c02f0f3db54fea1d54 It'll also make it slightly easier to upgrade to 3.5.0 later. Changelog: https://github.com/rspec/rspec-rails/blob/master/Changelog.md#340--2015-11-11 --- Gemfile | 2 +- Gemfile.lock | 36 ++++++++++++++++++------------------ spec/spec_helper.rb | 6 ------ 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/Gemfile b/Gemfile index 25c13fda575..c10fe0a1c7c 100644 --- a/Gemfile +++ b/Gemfile @@ -269,7 +269,7 @@ group :development, :test do gem 'database_cleaner', '~> 1.4.0' gem 'factory_girl_rails', '~> 4.6.0' - gem 'rspec-rails', '~> 3.3.0' + gem 'rspec-rails', '~> 3.4.0' gem 'rspec-retry' gem 'spinach-rails', '~> 0.2.1' gem 'spinach-rerun-reporter', '~> 0.0.2' diff --git a/Gemfile.lock b/Gemfile.lock index b1e954e0884..b19dc5b6d20 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -662,29 +662,29 @@ GEM chunky_png rqrcode-rails3 (0.1.7) rqrcode (>= 0.4.2) - rspec (3.3.0) - rspec-core (~> 3.3.0) - rspec-expectations (~> 3.3.0) - rspec-mocks (~> 3.3.0) - rspec-core (3.3.2) - rspec-support (~> 3.3.0) - rspec-expectations (3.3.1) + rspec (3.4.0) + rspec-core (~> 3.4.0) + rspec-expectations (~> 3.4.0) + rspec-mocks (~> 3.4.0) + rspec-core (3.4.4) + rspec-support (~> 3.4.0) + rspec-expectations (3.4.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.3.0) - rspec-mocks (3.3.2) + rspec-support (~> 3.4.0) + rspec-mocks (3.4.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.3.0) - rspec-rails (3.3.3) + rspec-support (~> 3.4.0) + rspec-rails (3.4.2) actionpack (>= 3.0, < 4.3) activesupport (>= 3.0, < 4.3) railties (>= 3.0, < 4.3) - rspec-core (~> 3.3.0) - rspec-expectations (~> 3.3.0) - rspec-mocks (~> 3.3.0) - rspec-support (~> 3.3.0) + rspec-core (~> 3.4.0) + rspec-expectations (~> 3.4.0) + rspec-mocks (~> 3.4.0) + rspec-support (~> 3.4.0) rspec-retry (0.4.5) rspec-core - rspec-support (3.3.0) + rspec-support (3.4.1) rubocop (0.38.0) parser (>= 2.3.0.6, < 3.0) powerpack (~> 0.1) @@ -1011,7 +1011,7 @@ DEPENDENCIES responders (~> 2.0) rouge (~> 1.10.1) rqrcode-rails3 (~> 0.1.7) - rspec-rails (~> 3.3.0) + rspec-rails (~> 3.4.0) rspec-retry rubocop (~> 0.38.0) ruby-fogbugz (~> 0.2.1) @@ -1058,4 +1058,4 @@ DEPENDENCIES wikicloth (= 0.8.1) BUNDLED WITH - 1.11.2 + 1.12.1 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 596d607f2a1..576d16e7ea3 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -51,10 +51,4 @@ FactoryGirl::SyntaxRunner.class_eval do include RSpec::Mocks::ExampleMethods end -# Work around a Rails 4.2.5.1 issue -# See https://github.com/rspec/rspec-rails/issues/1532 -RSpec::Rails::ViewRendering::EmptyTemplatePathSetDecorator.class_eval do - alias_method :find_all_anywhere, :find_all -end - ActiveRecord::Migration.maintain_test_schema! -- cgit v1.2.1 From 00ced598ea65f1b957c43576bc1564ed3f67d749 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Sat, 30 Apr 2016 05:34:31 -0300 Subject: Added UI to define secret_token for webhook and systemhook Codestyle changes to easy EE merge --- app/controllers/admin/hooks_controller.rb | 8 +++++++- app/controllers/projects/hooks_controller.rb | 14 +++++++++++--- app/views/admin/hooks/index.html.haml | 10 ++++++++-- app/views/projects/hooks/index.html.haml | 5 +++++ 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb index 93c4894ea0f..4e85b6b4cf2 100644 --- a/app/controllers/admin/hooks_controller.rb +++ b/app/controllers/admin/hooks_controller.rb @@ -39,6 +39,12 @@ class Admin::HooksController < Admin::ApplicationController end def hook_params - params.require(:hook).permit(:url, :enable_ssl_verification, :push_events, :tag_push_events) + params.require(:hook).permit( + :enable_ssl_verification, + :push_events, + :tag_push_events, + :token, + :url + ) end end diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb index 5fd4f855dec..dfa9bd259e8 100644 --- a/app/controllers/projects/hooks_controller.rb +++ b/app/controllers/projects/hooks_controller.rb @@ -52,8 +52,16 @@ class Projects::HooksController < Projects::ApplicationController end def hook_params - params.require(:hook).permit(:url, :push_events, :issues_events, - :merge_requests_events, :tag_push_events, :note_events, - :build_events, :enable_ssl_verification) + params.require(:hook).permit( + :build_events, + :enable_ssl_verification, + :issues_events, + :merge_requests_events, + :note_events, + :push_events, + :tag_push_events, + :token, + :url + ) end end diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml index 67d23c80233..7b388cf7862 100644 --- a/app/views/admin/hooks/index.html.haml +++ b/app/views/admin/hooks/index.html.haml @@ -13,9 +13,15 @@ = form_errors(@hook) .form-group - = f.label :url, "URL:", class: 'control-label' + = f.label :url, 'URL', class: 'control-label' .col-sm-10 - = f.text_field :url, class: "form-control" + = f.text_field :url, class: 'form-control' + .form-group + = f.label :token, 'Secret Token', class: 'control-label' + .col-sm-10 + = f.text_field :token, class: 'form-control' + %p.help-block + Use this token to validate received payloads .form-group = f.label :url, "Trigger", class: 'control-label' .col-sm-10.prepend-top-10 diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml index 6f1ee209430..36c1d69f060 100644 --- a/app/views/projects/hooks/index.html.haml +++ b/app/views/projects/hooks/index.html.haml @@ -15,6 +15,11 @@ .form-group = f.label :url, "URL", class: "label-light" = f.text_field :url, class: "form-control", placeholder: "http://example.com/trigger-ci.json" + .form-group + = f.label :token, "Secret Token", class: 'label-light' + = f.text_field :token, class: "form-control", placeholder: '' + %p.help-block + Use this token to validate received payloads .form-group = f.label :url, "Trigger", class: "label-light" %div -- cgit v1.2.1 From 1dfd051ec58e5c1a324d3b5493552289a44f1aa0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 2 May 2016 14:32:26 +0000 Subject: Remove duplicate entry in the CHANGELOG --- CHANGELOG | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 121b03be320..f1f93a3cb0a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -140,7 +140,6 @@ v 8.7.0 - Import GitHub labels - Add option to filter by "Owned projects" on dashboard page - Import GitHub milestones - - Fix emoji catgories in the emoji picker - Execute system web hooks on push to the project - Allow enable/disable push events for system hooks - Fix GitHub project's link in the import page when provider has a custom URL -- cgit v1.2.1 From dc0ff9a17472c71d2e2f5510797976f9ce7cea23 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 2 May 2016 17:22:03 +0200 Subject: Fix "remember me" sign in option --- config/initializers/session_store.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index 88cb859871c..599dabb9e50 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -22,7 +22,7 @@ else key: '_gitlab_session', secure: Gitlab.config.gitlab.https, httponly: true, - expire_after: Settings.gitlab['session_expire_delay'] * 60, + expires_in: Settings.gitlab['session_expire_delay'] * 60, path: (Rails.application.config.relative_url_root.nil?) ? '/' : Gitlab::Application.config.relative_url_root ) end -- cgit v1.2.1 From f1e74de47cd9fcf334617023aaa737c83c98a7f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 2 May 2016 17:49:51 +0200 Subject: Simplify specs by not over-expecting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- CHANGELOG | 2 +- .../projects/wiki/user_creates_wiki_page_spec.rb | 32 ++++++++++------------ .../projects/wiki/user_updates_wiki_page_spec.rb | 18 ++++++------ 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index bcbcdfc3fc6..efaa5f43d58 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,7 +15,7 @@ v 8.8.0 (unreleased) - Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718 - Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes) -v 8.7.2 (unreleased) +v 8.7.2 - The "New Branch" button is now loaded asynchronously - Fix error 500 when trying to create a wiki page diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb index d709fe8046f..7e6eef65873 100644 --- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb @@ -11,17 +11,16 @@ feature 'Projects > Wiki > User creates wiki page', feature: true do click_link 'Wiki' end - context 'wiki project is in the user namespace' do + context 'in the user namespace' do let(:project) { create(:project, namespace: user.namespace) } context 'when wiki is empty' do - scenario 'user can create a new wiki page from the wiki home page' do - expect(page).to have_content('Home · Edit Page') - + scenario 'directly from the wiki home page' do fill_in :wiki_content, with: 'My awesome wiki!' click_button 'Create page' - expect(page).to have_content("Home · last edited by #{user.name}") + expect(page).to have_content('Home') + expect(page).to have_content("last edited by #{user.name}") expect(page).to have_content('My awesome wiki!') end end @@ -31,34 +30,32 @@ feature 'Projects > Wiki > User creates wiki page', feature: true do WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute end - scenario 'user can create a new wiki page', js: true do + scenario 'via the "new wiki page" page', js: true do click_link 'New Page' fill_in :new_wiki_path, with: 'foo' click_button 'Create Page' - expect(page).to have_content('Foo · Edit Page') - fill_in :wiki_content, with: 'My awesome wiki!' click_button 'Create page' - expect(page).to have_content("Foo · last edited by #{user.name}") + expect(page).to have_content('Foo') + expect(page).to have_content("last edited by #{user.name}") expect(page).to have_content('My awesome wiki!') end end end - context 'wiki project is in the user namespace' do + context 'in a group namespace' do let(:project) { create(:project, namespace: create(:group, :public)) } context 'when wiki is empty' do - scenario 'user can create a new wiki page from the wiki home page' do - expect(page).to have_content('Home · Edit Page') - + scenario 'directly from the wiki home page' do fill_in :wiki_content, with: 'My awesome wiki!' click_button 'Create page' - expect(page).to have_content("Home · last edited by #{user.name}") + expect(page).to have_content('Home') + expect(page).to have_content("last edited by #{user.name}") expect(page).to have_content('My awesome wiki!') end end @@ -68,18 +65,17 @@ feature 'Projects > Wiki > User creates wiki page', feature: true do WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute end - scenario 'user can create a new wiki page', js: true do + scenario 'via the "new wiki page" page', js: true do click_link 'New Page' fill_in :new_wiki_path, with: 'foo' click_button 'Create Page' - expect(page).to have_content('Foo · Edit Page') - fill_in :wiki_content, with: 'My awesome wiki!' click_button 'Create page' - expect(page).to have_content("Foo · last edited by #{user.name}") + expect(page).to have_content('Foo') + expect(page).to have_content("last edited by #{user.name}") expect(page).to have_content('My awesome wiki!') end end diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb index b69d6b46ac8..ef82d2375dd 100644 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -12,34 +12,32 @@ feature 'Projects > Wiki > User updates wiki page', feature: true do click_link 'Wiki' end - context 'wiki project is in the user namespace' do + context 'in the user namespace' do let(:project) { create(:project, namespace: user.namespace) } - scenario 'user can update the wiki home page' do + scenario 'the home page' do click_link 'Edit' - expect(page).to have_content('Home · Edit Page') - fill_in :wiki_content, with: 'My awesome wiki!' click_button 'Save changes' - expect(page).to have_content("Home · last edited by #{user.name}") + expect(page).to have_content('Home') + expect(page).to have_content("last edited by #{user.name}") expect(page).to have_content('My awesome wiki!') end end - context 'wiki project is in the user namespace' do + context 'in a group namespace' do let(:project) { create(:project, namespace: create(:group, :public)) } - scenario 'user can update the wiki home page' do + scenario 'the home page' do click_link 'Edit' - expect(page).to have_content('Home · Edit Page') - fill_in :wiki_content, with: 'My awesome wiki!' click_button 'Save changes' - expect(page).to have_content("Home · last edited by #{user.name}") + expect(page).to have_content('Home') + expect(page).to have_content("last edited by #{user.name}") expect(page).to have_content('My awesome wiki!') end end -- cgit v1.2.1 From e31b471efc7e9e21011b80a0bce9433a3d899eda Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 2 May 2016 19:22:48 +0200 Subject: Make files list more compact by reducing row height from 47px to 44px Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/pages/tree.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 25b5e95583e..a84fc2e0318 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -16,7 +16,7 @@ tr { > td, > th { - line-height: 26px; + line-height: 23px; } &:hover { -- cgit v1.2.1 From b0cfd2a9c55e134711079a64a50c00d6fcdd766a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 2 May 2016 19:37:22 +0200 Subject: Use correct border color between table rows Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/tables.scss | 2 +- app/assets/stylesheets/framework/variables.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss index 75b770ae5a2..4765a3de515 100644 --- a/app/assets/stylesheets/framework/tables.scss +++ b/app/assets/stylesheets/framework/tables.scss @@ -37,8 +37,8 @@ table { } td { + border-bottom: 1px solid; border-color: $table-border-color; - border-bottom: 1px solid $border-color; } } } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index b8ed7e8a74c..92ecfe50488 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -12,7 +12,7 @@ $gutter_inner_width: 258px; */ $border-color: #e5e5e5; $focus-border-color: #3aabf0; -$table-border-color: #eef0f2; +$table-border-color: #ececec; $background-color: #fafafa; /* -- cgit v1.2.1 From 606e09c141d39ccc3bcfe47ac200eef6df3861a0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 2 May 2016 19:52:46 +0200 Subject: Fix table borders Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/tables.scss | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss index 4765a3de515..b42075c98d0 100644 --- a/app/assets/stylesheets/framework/tables.scss +++ b/app/assets/stylesheets/framework/tables.scss @@ -32,12 +32,10 @@ table { th { background-color: $background-color; font-weight: normal; - font-size: 15px; - border-bottom: 1px solid $border-color; + border-bottom: none; } td { - border-bottom: 1px solid; border-color: $table-border-color; } } -- cgit v1.2.1 From f64b82e1da47e0f0b4e0f6e91746ed95a98105dd Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 29 Apr 2016 16:02:28 -0700 Subject: Support e-mail notifications for comments on project snippets Closes #2334 --- CHANGELOG | 1 + app/mailers/emails/notes.rb | 8 ++++ app/models/project_snippet.rb | 2 + app/views/notify/note_snippet_email.html.haml | 1 + app/views/notify/note_snippet_email.text.erb | 8 ++++ spec/services/notification_service_spec.rb | 65 ++++++++++++++++++++------- 6 files changed, 69 insertions(+), 16 deletions(-) create mode 100644 app/views/notify/note_snippet_email.html.haml create mode 100644 app/views/notify/note_snippet_email.text.erb diff --git a/CHANGELOG b/CHANGELOG index 87aafb939e3..3dfa074eae3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ v 8.8.0 (unreleased) - Project#open_branches has been cleaned up and no longer loads entire records into memory. - Make build status canceled if any of the jobs was canceled and none failed - Remove future dates from contribution calendar graph. + - Support e-mail notifications for comments on project snippets - Use ActionDispatch Remote IP for Akismet checking - Fix error when visiting commit builds page before build was updated - Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb index cdc40b81ee1..96116e916dd 100644 --- a/app/mailers/emails/notes.rb +++ b/app/mailers/emails/notes.rb @@ -28,6 +28,14 @@ module Emails mail_answer_thread(@merge_request, note_thread_options(recipient_id)) end + def note_snippet_email(recipient_id, note_id) + setup_note_mail(note_id, recipient_id) + + @snippet = @note.noteable + @target_url = namespace_project_snippet_url(*note_target_url_options) + mail_answer_thread(@snippet, note_thread_options(recipient_id)) + end + private def note_target_url_options diff --git a/app/models/project_snippet.rb b/app/models/project_snippet.rb index 1f7d85a5f3d..d48f0546159 100644 --- a/app/models/project_snippet.rb +++ b/app/models/project_snippet.rb @@ -22,4 +22,6 @@ class ProjectSnippet < Snippet # Scopes scope :fresh, -> { order("created_at DESC") } + + participant :author, :notes end diff --git a/app/views/notify/note_snippet_email.html.haml b/app/views/notify/note_snippet_email.html.haml new file mode 100644 index 00000000000..2fa2f784661 --- /dev/null +++ b/app/views/notify/note_snippet_email.html.haml @@ -0,0 +1 @@ += render 'note_message' diff --git a/app/views/notify/note_snippet_email.text.erb b/app/views/notify/note_snippet_email.text.erb new file mode 100644 index 00000000000..4d5a406f4b0 --- /dev/null +++ b/app/views/notify/note_snippet_email.text.erb @@ -0,0 +1,8 @@ +New comment for Snippet <%= @snippet.id %> + +<%= url_for(namespace_project_snippet_url(@snippet.project.namespace, @snippet.project, @snippet, anchor: "note_#{@note.id}")) %> + + +Author: <%= @note.author_name %> + +<%= @note.note %> diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index d7c72dc0811..4bbc4ddc3ab 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -10,7 +10,7 @@ describe NotificationService, services: true do end describe 'Keys' do - describe :new_key do + describe '#new_key' do let!(:key) { create(:personal_key) } it { expect(notification.new_key(key)).to be_truthy } @@ -22,7 +22,7 @@ describe NotificationService, services: true do end describe 'Email' do - describe :new_email do + describe '#new_email' do let!(:email) { create(:email) } it { expect(notification.new_email(email)).to be_truthy } @@ -147,8 +147,8 @@ describe NotificationService, services: true do ActionMailer::Base.deliveries.clear end - describe :new_note do - it do + describe '#new_note' do + it 'notifies the team members' do notification.new_note(note) # Notify all team members @@ -177,6 +177,39 @@ describe NotificationService, services: true do end end + context 'project snippet note' do + let(:project) { create(:empty_project, :public) } + let(:snippet) { create(:project_snippet, project: project, author: create(:user)) } + let(:note) { create(:note_on_project_snippet, noteable: snippet, project_id: snippet.project.id, note: '@all mentioned') } + + before do + build_team(note.project) + note.project.team << [note.author, :master] + ActionMailer::Base.deliveries.clear + end + + describe '#new_note' do + it 'notifies the team members' do + notification.new_note(note) + + # Notify all team members + note.project.team.members.each do |member| + # User with disabled notification should not be notified + next if member.id == @u_disabled.id + # Author should not be notified + next if member.id == note.author.id + should_email(member) + end + + should_email(note.noteable.author) + should_not_email(note.author) + should_email(@u_mentioned) + should_not_email(@u_disabled) + should_email(@u_not_mentioned) + end + end + end + context 'commit note' do let(:project) { create(:project, :public) } let(:note) { create(:note_on_commit, project: project) } @@ -187,7 +220,7 @@ describe NotificationService, services: true do allow_any_instance_of(Commit).to receive(:author).and_return(@u_committer) end - describe :new_note, :perform_enqueued_jobs do + describe '#new_note, #perform_enqueued_jobs' do it do notification.new_note(note) @@ -230,7 +263,7 @@ describe NotificationService, services: true do ActionMailer::Base.deliveries.clear end - describe :new_issue do + describe '#new_issue' do it do notification.new_issue(issue, @u_disabled) @@ -289,7 +322,7 @@ describe NotificationService, services: true do end end - describe :reassigned_issue do + describe '#reassigned_issue' do it 'emails new assignee' do notification.reassigned_issue(issue, @u_disabled) @@ -419,7 +452,7 @@ describe NotificationService, services: true do end end - describe :close_issue do + describe '#close_issue' do it 'should sent email to issue assignee and issue author' do notification.close_issue(issue, @u_disabled) @@ -435,7 +468,7 @@ describe NotificationService, services: true do end end - describe :reopen_issue do + describe '#reopen_issue' do it 'should send email to issue assignee and issue author' do notification.reopen_issue(issue, @u_disabled) @@ -461,7 +494,7 @@ describe NotificationService, services: true do ActionMailer::Base.deliveries.clear end - describe :new_merge_request do + describe '#new_merge_request' do it do notification.new_merge_request(merge_request, @u_disabled) @@ -483,7 +516,7 @@ describe NotificationService, services: true do end end - describe :reassigned_merge_request do + describe '#reassigned_merge_request' do it do notification.reassigned_merge_request(merge_request, merge_request.author) @@ -498,7 +531,7 @@ describe NotificationService, services: true do end end - describe :relabel_merge_request do + describe '#relabel_merge_request' do let(:label) { create(:label, merge_requests: [merge_request]) } let(:label2) { create(:label) } let!(:subscriber_to_label) { create(:user).tap { |u| label.toggle_subscription(u) } } @@ -527,7 +560,7 @@ describe NotificationService, services: true do end end - describe :closed_merge_request do + describe '#closed_merge_request' do it do notification.close_mr(merge_request, @u_disabled) @@ -542,7 +575,7 @@ describe NotificationService, services: true do end end - describe :merged_merge_request do + describe '#merged_merge_request' do it do notification.merge_mr(merge_request, @u_disabled) @@ -557,7 +590,7 @@ describe NotificationService, services: true do end end - describe :reopen_merge_request do + describe '#reopen_merge_request' do it do notification.reopen_mr(merge_request, @u_disabled) @@ -581,7 +614,7 @@ describe NotificationService, services: true do ActionMailer::Base.deliveries.clear end - describe :project_was_moved do + describe '#project_was_moved' do it do notification.project_was_moved(project, "gitlab/gitlab") -- cgit v1.2.1 From f0c4f727359a5848d12e2097bad6a6a3190943ef Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 2 May 2016 21:47:11 -0400 Subject: Update CHANGELOG for 8.6.8, 8.5.12, et al. [ci skip] --- CHANGELOG | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 3dfa074eae3..b6527780bbf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,7 +18,7 @@ v 8.8.0 (unreleased) - Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes) - Added multiple colors for labels in dropdowns when dups happen. -v 8.7.2 +v 8.7.2 (unreleased) - The "New Branch" button is now loaded asynchronously - Fix error 500 when trying to create a wiki page @@ -148,6 +148,19 @@ v 8.7.0 - Add RAW build trace output and button on build page - Add incremental build trace update into CI API +v 8.6.8 + - Prevent privilege escalation via "impersonate" feature + - Prevent privilege escalation via notes API + - Prevent privilege escalation via project webhook API + - Prevent XSS via Git branch and tag names + - Prevent XSS via custom issue tracker URL + - Prevent XSS via `window.opener` + - Prevent XSS via label drop-down + - Prevent information disclosure via milestone API + - Prevent information disclosure via snippet API + - Prevent information disclosure via project labels + - Prevent information disclosure via new merge request page + v 8.6.7 - Fix persistent XSS vulnerability in `commit_person_link` helper - Fix persistent XSS vulnerability in Label and Milestone dropdowns @@ -289,6 +302,17 @@ v 8.6.0 - Trigger a todo for mentions on commits page - Let project owners and admins soft delete issues and merge requests +v 8.5.12 + - Prevent privilege escalation via "impersonate" feature + - Prevent privilege escalation via notes API + - Prevent privilege escalation via project webhook API + - Prevent XSS via Git branch and tag names + - Prevent XSS via custom issue tracker URL + - Prevent XSS via `window.opener` + - Prevent information disclosure via snippet API + - Prevent information disclosure via project labels + - Prevent information disclosure via new merge request page + v 8.5.11 - Fix persistent XSS vulnerability in `commit_person_link` helper @@ -439,6 +463,17 @@ v 8.5.0 - Show label row when filtering issues or merge requests by label (Nuttanart Pornprasitsakul) - Add Todos +v 8.4.10 + - Prevent privilege escalation via "impersonate" feature + - Prevent privilege escalation via notes API + - Prevent privilege escalation via project webhook API + - Prevent XSS via Git branch and tag names + - Prevent XSS via custom issue tracker URL + - Prevent XSS via `window.opener` + - Prevent information disclosure via snippet API + - Prevent information disclosure via project labels + - Prevent information disclosure via new merge request page + v 8.4.9 - Fix persistent XSS vulnerability in `commit_person_link` helper @@ -564,6 +599,15 @@ v 8.4.0 - Add IP check against DNSBLs at account sign-up - Added cache:key to .gitlab-ci.yml allowing to fine tune the caching +v 8.3.9 + - Prevent privilege escalation via "impersonate" feature + - Prevent privilege escalation via notes API + - Prevent privilege escalation via project webhook API + - Prevent XSS via custom issue tracker URL + - Prevent XSS via `window.opener` + - Prevent information disclosure via project labels + - Prevent information disclosure via new merge request page + v 8.3.8 - Fix persistent XSS vulnerability in `commit_person_link` helper @@ -673,6 +717,17 @@ v 8.3.0 - Expose Git's version in the admin area - Show "New Merge Request" buttons on canonical repos when you have a fork (Josh Frye) +v 8.2.5 + - Prevent privilege escalation via "impersonate" feature + - Prevent privilege escalation via notes API + - Prevent privilege escalation via project webhook API + - Prevent XSS via `window.opener` + - Prevent information disclosure via project labels + - Prevent information disclosure via new merge request page + +v 8.2.4 + - Bump Git version requirement to 2.7.4 + v 8.2.3 - Fix application settings cache not expiring after changes (Stan Hu) - Fix Error 500s when creating global milestones with Unicode characters (Stan Hu) -- cgit v1.2.1 From 268868bcf0e1d09448c2212fb5275d1264d21b1b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 3 May 2016 13:21:09 +0200 Subject: Improve milestone page UI Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/pages/milestone.scss | 4 ++-- app/views/projects/milestones/show.html.haml | 10 +++++----- app/views/shared/milestones/_top.html.haml | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss index d0e72a4422c..b94f524b513 100644 --- a/app/assets/stylesheets/pages/milestone.scss +++ b/app/assets/stylesheets/pages/milestone.scss @@ -28,7 +28,7 @@ li.milestone { // Issue title span a { - color: rgba(0,0,0,0.64); + color: $gl-text-color; } } } @@ -51,7 +51,7 @@ li.milestone { margin-top: 7px; .issuable-number { - color: rgba(0,0,0,0.44); + color: $gl-placeholder-color; margin-right: 5px; } .avatar { diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index 56543ccd062..6ec84660157 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -24,15 +24,15 @@ - else = link_to 'Reopen Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-nr btn-grouped" - = link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-nr" do - = icon('trash-o') - Delete - = link_to edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-grouped btn-nr" do = icon('pencil-square-o') Edit -.detail-page-description.milestone-detail.second-block + = link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-danger" do + = icon('trash-o') + Delete + +.detail-page-description.milestone-detail %h2.title = markdown escape_once(@milestone.title), pipeline: :single_line %div diff --git a/app/views/shared/milestones/_top.html.haml b/app/views/shared/milestones/_top.html.haml index cab8743a077..7ff947a51db 100644 --- a/app/views/shared/milestones/_top.html.haml +++ b/app/views/shared/milestones/_top.html.haml @@ -24,7 +24,7 @@ - else = link_to 'Reopen Milestone', group_milestone_path(group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen" -.detail-page-description.gray-content-block.second-block +.detail-page-description.milestone-detail %h2.title = markdown escape_once(milestone.title), pipeline: :single_line -- cgit v1.2.1 From 1fddfa8f2a7b6bd6e71f7e997f152a2f8baa15d4 Mon Sep 17 00:00:00 2001 From: Karlo Soriano Date: Tue, 3 May 2016 21:17:39 +0800 Subject: Link to gitlab code review guide in contributing guidelines I noticed that the contributing guidelines still link to the thoughtbot code review guidelines even though we already have our own. [ci skip] --- CONTRIBUTING.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 24cd5864530..783d6947edb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -349,7 +349,7 @@ on your merge request feel free to mention one of the Merge Marshalls in the Please ensure that your merge request meets the contribution acceptance criteria. When having your code reviewed and when reviewing merge requests please take the -[Thoughtbot code review guide] into account. +[code review guidelines](doc/development/code_review.md) into account. ### Merge request description format @@ -523,4 +523,3 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor [gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design [free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12 [`gitlab1.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/gitlab1.atype/ -[Thoughtbot code review guide]: https://github.com/thoughtbot/guides/tree/master/code-review -- cgit v1.2.1 From 94df8d5fc87a6a3a43a23b8f484de9e24af837d1 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 3 May 2016 16:39:08 +0200 Subject: Updated CHANGELOG for 8.7.2 [ci skip] --- CHANGELOG | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index b6527780bbf..11b1768c8eb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,9 +18,10 @@ v 8.8.0 (unreleased) - Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes) - Added multiple colors for labels in dropdowns when dups happen. -v 8.7.2 (unreleased) +v 8.7.2 - The "New Branch" button is now loaded asynchronously - Fix error 500 when trying to create a wiki page + - Updated spacing between notification label and button v 8.7.1 - Throttle the update of `project.last_activity_at` to 1 minute. !3848 -- cgit v1.2.1 From b7641dbb51102b24e692efa5ba01d52a88bce855 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 3 May 2016 11:24:30 -0400 Subject: Update link to release docs in README [ci skip] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index afa60116ebb..36f4bb12df0 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ There are a lot of [third-party applications integrating with GitLab](https://ab ## GitLab release cycle -For more information about the release process see the [release documentation](http://doc.gitlab.com/ce/release/). +For more information about the release process see the [release documentation](https://gitlab.com/gitlab-org/release-tools/blob/master/README.md). ## Upgrading -- cgit v1.2.1 From 8bd793c9c58c701882447fba055cd93e55f34af5 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 3 May 2016 20:46:14 +0300 Subject: Copyedit performance document [ci skip] --- doc/development/performance.md | 44 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/doc/development/performance.md b/doc/development/performance.md index c74198650e5..41f415812a0 100644 --- a/doc/development/performance.md +++ b/doc/development/performance.md @@ -7,7 +7,7 @@ consistent performance of GitLab. The process of solving performance problems is roughly as follows: -1. Make sure there's an issue open somewhere (e.g. on the GitLab CE issue +1. Make sure there's an issue open somewhere (e.g., on the GitLab CE issue tracker), create one if there isn't. See [#15607][#15607] for an example. 2. Measure the performance of the code in a production environment such as GitLab.com (see the [Tooling](#tooling) section below). Performance should be @@ -27,7 +27,7 @@ When providing timings make sure to provide: * The 99th percentile * The mean -When providing screenshots of graphs make sure that both the X and Y axes and +When providing screenshots of graphs, make sure that both the X and Y axes and the legend are clearly visible. If you happen to have access to GitLab.com's own monitoring tools you should also provide a link to any relevant graphs/dashboards. @@ -37,7 +37,7 @@ graphs/dashboards. GitLab provides two built-in tools to aid the process of improving performance: * [Sherlock](doc/development/profiling.md#sherlock) -* [GitLab Performance Monitoring](doc/monitoring/performance) +* [GitLab Performance Monitoring](doc/monitoring/performance/monitoring.md) GitLab employees can use GitLab.com's performance monitoring systems located at , this requires you to log in using your @@ -48,7 +48,7 @@ own InfluxDB + Grafana stack. Benchmarks are almost always useless. Benchmarks usually only test small bits of code in isolation and often only measure the best case scenario. On top of that, -benchmarks for libraries (e.g. a Gem) tend to be biased in favour of the +benchmarks for libraries (e.g., a Gem) tend to be biased in favour of the library. After all there's little benefit to an author publishing a benchmark that shows they perform worse than their competitors. @@ -102,7 +102,7 @@ In short: ## Importance of Changes -When working on performance improvements it's important to always ask yourself +When working on performance improvements, it's important to always ask yourself the question "How important is it to improve the performance of this piece of code?". Not every piece of code is equally important and it would be a waste to spend a week trying to improve something that only impacts a tiny fraction of @@ -114,7 +114,7 @@ There is no clear set of steps that you can follow to determine if a certain piece of code is worth optimizing. The only two things you can do are: 1. Think about what the code does, how it's used, how many times it's called and - how much time is spent in it relative to the total execution time (e.g. the + how much time is spent in it relative to the total execution time (e.g., the total time spent in a web request). 2. Ask others (preferably in the form of an issue). @@ -159,7 +159,7 @@ if repository.exists? end ``` -You can instead just write: +You can just write: ```ruby repository.branch_names.each do |name| @@ -170,21 +170,21 @@ end ## Caching Operations that will often return the same result should be cached using Redis, -in particular Git operations. When caching data in Redis make sure the cache is +in particular Git operations. When caching data in Redis, make sure the cache is flushed whenever needed. For example, a cache for the list of tags should be flushed whenever a new tag is pushed or a tag is removed. -When adding cache expiration code for repositories this code should be placed in -one of the before/after hooks residing in the Repository class. For example, if -a cache should be flushed after importing a repository this code should be added -to `Repository#after_import`. This ensures the cache logic stays within the -Repository class instead of leaking into other classes. +When adding cache expiration code for repositories, this code should be placed +in one of the before/after hooks residing in the Repository class. For example, +if a cache should be flushed after importing a repository this code should be +added to `Repository#after_import`. This ensures the cache logic stays within +the Repository class instead of leaking into other classes. -When caching data make sure to also memoize the result in an instance variable. -While retrieving data from Redis is much faster than raw Git operations it still -has overhead. By caching the result in an instance variable repeated calls to +When caching data, make sure to also memoize the result in an instance variable. +While retrieving data from Redis is much faster than raw Git operations, it still +has overhead. By caching the result in an instance variable, repeated calls to the same method won't end up retrieving data from Redis upon every call. When -memoizing cached data in an instance variable make sure to also reset the +memoizing cached data in an instance variable, make sure to also reset the instance variable when flushing the cache. An example: @@ -224,10 +224,10 @@ positive impact on performance. This feature of Ruby wasn't really meant to make things faster directly, instead it was meant to reduce the number of allocations. Depending on the size of the String and how frequently it would be allocated (before the `.freeze` call was -added) this _may_ make things faster, but there's no guarantee it will. +added), this _may_ make things faster, but there's no guarantee it will. -Another common flavour of this is to not only freeze a String but also assign it -to a constant, for example: +Another common flavour of this is to not only freeze a String, but also assign +it to a constant, for example: ```ruby SOME_CONSTANT = 'foo'.freeze @@ -248,8 +248,8 @@ SOME_CONSTANT = 'bar' ### Moving Allocations to Constants Storing an object as a constant so you only allocate it once _may_ improve -performance but there's no guarantee this will. Looking up constants has an -impact on runtime performance and as such using a constant instead of +performance, but there's no guarantee this will. Looking up constants has an +impact on runtime performance, and as such, using a constant instead of referencing an object directly may even slow code down. [#15607]: https://gitlab.com/gitlab-org/gitlab-ce/issues/15607 -- cgit v1.2.1 From 473e653e2408e818d0d61732332aeba53e5ca499 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 3 May 2016 21:53:54 +0300 Subject: Add clear instructions on installing the pg_trgm extension [ci skip] --- doc/install/installation.md | 56 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index e721e70a596..e3af3022262 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -157,22 +157,64 @@ Create a `git` user for GitLab: ## 5. Database -We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](database_mysql.md). *Note*: because we need to make use of extensions you need at least pgsql 9.1. +We recommend using a PostgreSQL database. For MySQL check the +[MySQL setup guide](database_mysql.md). - # Install the database packages - sudo apt-get install -y postgresql postgresql-client libpq-dev +> **Note**: because we need to make use of extensions you need at least pgsql 9.1. - # Create a user for GitLab +1. Install the database packages: + + ```bash + sudo apt-get install -y postgresql postgresql-client libpq-dev postgresql-contrib + ``` + +1. Create a database user for GitLab: + + ```bash sudo -u postgres psql -d template1 -c "CREATE USER git CREATEDB;" + ``` + +1. Create the GitLab production database and grant all privileges on database: - # Create the GitLab production database & grant all privileges on database + ```bash sudo -u postgres psql -d template1 -c "CREATE DATABASE gitlabhq_production OWNER git;" + ``` + +1. Create the `pg_trgm` extension (required for GitLab 8.6+): + + ```bash + sudo -u postgres psql -d template1 -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;" + ``` + +1. Try connecting to the new database with the new user: - # Try connecting to the new database with the new user + ```bash sudo -u git -H psql -d gitlabhq_production + ``` + +1. Check if the `pg_trgm` extension is enabled: + + ```bash + SELECT true AS enabled + FROM pg_available_extensions + WHERE name = 'pg_trgm' + AND installed_version IS NOT NULL; + ``` + + If the extension is enabled this will produce the following output: - # Quit the database session + ``` + enabled + --------- + t + (1 row) + ``` + +1. Quit the database session: + + ```bash gitlabhq_production> \q + ``` ## 6. Redis -- cgit v1.2.1 From b898810c8d94b51514a7b5582921ab9ace4e40fb Mon Sep 17 00:00:00 2001 From: connorshea Date: Thu, 31 Mar 2016 19:54:03 -0600 Subject: Improve the Two-factor Authentication sign-in text [ci skip] Resolves #14543. --- CHANGELOG | 1 + app/views/devise/sessions/two_factor.html.haml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 11b1768c8eb..4c68c836080 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,7 @@ v 8.8.0 (unreleased) - Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718 - Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes) - Added multiple colors for labels in dropdowns when dups happen. + - Improve description for the Two-factor Authentication sign-in screen. (Connor Shea) v 8.7.2 - The "New Branch" button is now loaded asynchronously diff --git a/app/views/devise/sessions/two_factor.html.haml b/app/views/devise/sessions/two_factor.html.haml index 22b2c1a186b..c9d1e454a5e 100644 --- a/app/views/devise/sessions/two_factor.html.haml +++ b/app/views/devise/sessions/two_factor.html.haml @@ -4,7 +4,7 @@ %h3 Two-factor Authentication .login-body = form_for(resource, as: resource_name, url: session_path(resource_name), method: :post) do |f| - = f.text_field :otp_attempt, class: 'form-control', placeholder: 'Two-factor authentication code', required: true, autofocus: true - %p.help-block.hint If you've lost your phone, you may enter one of your recovery codes. + = f.text_field :otp_attempt, class: 'form-control', placeholder: 'Two-factor Authentication code', required: true, autofocus: true + %p.help-block.hint Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes. .prepend-top-20 = f.submit "Verify code", class: "btn btn-save" -- cgit v1.2.1 From d6c2d6bab9f00c288df3318424c4c1bbbca614dc Mon Sep 17 00:00:00 2001 From: Artem Sidorenko Date: Sat, 30 Apr 2016 17:38:39 +0200 Subject: Use sign out path only if not empty --- app/controllers/application_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1c53b0b21a3..17b3f49aed1 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -117,7 +117,7 @@ class ApplicationController < ActionController::Base end def after_sign_out_path_for(resource) - current_application_settings.after_sign_out_path || new_user_session_path + current_application_settings.after_sign_out_path.presence || new_user_session_path end def abilities -- cgit v1.2.1 From 3004386b55fede6381e5e0794c12625e2b83de25 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Tue, 3 May 2016 15:37:59 -0600 Subject: Revert "Remove the Devise Async gem." This reverts commit 1cc614f2bdd30b4fce35ee9e680f9272b9012978. It was causing the ActiveJob integration to fail, so unfortunately we'll have to add the gem again. --- CHANGELOG | 1 - Gemfile | 1 + Gemfile.lock | 3 +++ app/models/user.rb | 2 +- config/initializers/devise_async.rb | 1 + 5 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 config/initializers/devise_async.rb diff --git a/CHANGELOG b/CHANGELOG index 11b1768c8eb..5e64e776f78 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,7 +10,6 @@ v 8.8.0 (unreleased) - Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project - Updated search UI - Display informative message when new milestone is created - - Replace Devise Async with Devise ActiveJob integration. !3902 (Connor Shea) - Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea) - Added button to toggle whitespaces changes on diff view - Backport GitLab Enterprise support from EE diff --git a/Gemfile b/Gemfile index 25c13fda575..890fcbc1318 100644 --- a/Gemfile +++ b/Gemfile @@ -20,6 +20,7 @@ gem "pg", '~> 0.18.2', group: :postgres # Authentication libraries gem 'devise', '~> 3.5.4' gem 'doorkeeper', '~> 3.1' +gem 'devise-async', '~> 0.9.0' gem 'omniauth', '~> 1.3.1' gem 'omniauth-auth0', '~> 1.4.1' gem 'omniauth-azure-oauth2', '~> 0.0.6' diff --git a/Gemfile.lock b/Gemfile.lock index b1e954e0884..ae91b0fb6dd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -164,6 +164,8 @@ GEM responders thread_safe (~> 0.1) warden (~> 1.2.3) + devise-async (0.9.0) + devise (~> 3.2) devise-two-factor (2.0.1) activesupport attr_encrypted (~> 1.3.2) @@ -920,6 +922,7 @@ DEPENDENCIES database_cleaner (~> 1.4.0) default_value_for (~> 3.0.0) devise (~> 3.5.4) + devise-async (~> 0.9.0) devise-two-factor (~> 2.0.0) diffy (~> 3.0.3) doorkeeper (~> 3.1) diff --git a/app/models/user.rb b/app/models/user.rb index b6f405c6981..ab48f8f1960 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -91,7 +91,7 @@ class User < ActiveRecord::Base devise :two_factor_backupable, otp_number_of_backup_codes: 10 serialize :otp_backup_codes, JSON - devise :lockable, :recoverable, :rememberable, :trackable, + devise :lockable, :async, :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :confirmable, :registerable attr_accessor :force_random_password diff --git a/config/initializers/devise_async.rb b/config/initializers/devise_async.rb new file mode 100644 index 00000000000..05a1852cdbd --- /dev/null +++ b/config/initializers/devise_async.rb @@ -0,0 +1 @@ +Devise::Async.backend = :sidekiq -- cgit v1.2.1 From 82b5bb91179438bb74f0b6ce31f6fd3cebac6645 Mon Sep 17 00:00:00 2001 From: Aral Balkan Date: Wed, 4 May 2016 06:58:40 +0000 Subject: Made it clearer that issue_id means iid, not id. --- doc/api/notes.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/api/notes.md b/doc/api/notes.md index 7aa1c2155bf..a6b5b1787fd 100644 --- a/doc/api/notes.md +++ b/doc/api/notes.md @@ -15,7 +15,7 @@ GET /projects/:id/issues/:issue_id/notes Parameters: - `id` (required) - The ID of a project -- `issue_id` (required) - The ID of an issue +- `issue_id` (required) - The IID of an issue (not ID) ```json [ @@ -73,7 +73,7 @@ GET /projects/:id/issues/:issue_id/notes/:note_id Parameters: - `id` (required) - The ID of a project -- `issue_id` (required) - The ID of a project issue +- `issue_id` (required) - The IID of a project issue (not ID) - `note_id` (required) - The ID of an issue note ### Create new issue note @@ -87,7 +87,7 @@ POST /projects/:id/issues/:issue_id/notes Parameters: - `id` (required) - The ID of a project -- `issue_id` (required) - The ID of an issue +- `issue_id` (required) - The IID of an issue (not ID) - `body` (required) - The content of a note - `created_at` (optional) - Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z @@ -102,7 +102,7 @@ PUT /projects/:id/issues/:issue_id/notes/:note_id Parameters: - `id` (required) - The ID of a project -- `issue_id` (required) - The ID of an issue +- `issue_id` (required) - The IID of an issue (not ID) - `note_id` (required) - The ID of a note - `body` (required) - The content of a note @@ -120,7 +120,7 @@ Parameters: | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `id` | integer | yes | The ID of a project | -| `issue_id` | integer | yes | The ID of an issue | +| `issue_id` | integer | yes | The IID of an issue | | `note_id` | integer | yes | The ID of a note | ```bash -- cgit v1.2.1 From 5f89c9642e6fa48d0487e40ea2dc6977676855dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Wed, 4 May 2016 12:17:12 +0200 Subject: Fix a spec that was failing due to !3483 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spec were skipped in this MR so that tests started to fail in master instead of in this MR! Signed-off-by: Rémy Coutable --- spec/features/login_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb index 4433ef2d6f1..8c38dd5b122 100644 --- a/spec/features/login_spec.rb +++ b/spec/features/login_spec.rb @@ -37,7 +37,7 @@ feature 'Login', feature: true do end def enter_code(code) - fill_in 'Two-factor authentication code', with: code + fill_in 'Two-factor Authentication code', with: code click_button 'Verify code' end -- cgit v1.2.1 From 70551217a6cc250dc2e9a61720fc447df74e38c7 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 4 May 2016 13:17:43 +0200 Subject: Fixed username links in the performance guide These would end up being rendered as: @yorickpeterse @yorickpeterse [ci skip] --- doc/development/performance.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/development/performance.md b/doc/development/performance.md index 41f415812a0..fb37b3a889c 100644 --- a/doc/development/performance.md +++ b/doc/development/performance.md @@ -16,7 +16,7 @@ The process of solving performance problems is roughly as follows: timings, etc) to the issue mentioned in step 1. 4. Solve the problem. 5. Create a merge request, assign the "performance" label and ping the right - people (e.g. [@yorickpeterse][@yorickpeterse] and [@joshfng][@joshfng]). + people (e.g. [@yorickpeterse][yorickpeterse] and [@joshfng][joshfng]). 6. Once a change has been deployed make sure to _again_ measure for at least 24 hours to see if your changes have any impact on the production environment. 7. Repeat until you're done. @@ -253,6 +253,6 @@ impact on runtime performance, and as such, using a constant instead of referencing an object directly may even slow code down. [#15607]: https://gitlab.com/gitlab-org/gitlab-ce/issues/15607 -[@yorickpeterse]: https://gitlab.com/u/yorickpeterse -[@joshfng]: https://gitlab.com/u/joshfng +[yorickpeterse]: https://gitlab.com/u/yorickpeterse +[joshfng]: https://gitlab.com/u/joshfng [anti-pattern]: https://en.wikipedia.org/wiki/Anti-pattern -- cgit v1.2.1 From 9bd5ac50b4c0677a2999ccee4f13e2c8e20a2def Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Wed, 4 May 2016 21:33:55 +0900 Subject: Use new build badge URLs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 36f4bb12df0..c1a29c3bb1e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # GitLab -[![build status](https://ci.gitlab.com/projects/1/status.svg?ref=master)](https://ci.gitlab.com/projects/1?ref=master) +[![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) [![Build Status](https://semaphoreci.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/400484/shields_badge.svg)](https://semaphoreci.com/gitlabhq/gitlabhq) [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq) [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.svg?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master) -- cgit v1.2.1 From f660b2173e408a0e527b9852c92b2d57982885b5 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 4 May 2016 12:54:11 +0100 Subject: Instrument methods used in email diffs Make all of the nested constant instrumentation for core app code work the same way, add mailer instrumentation, and add instrumentation to the premailer gem. --- CHANGELOG | 3 +++ config/initializers/metrics.rb | 37 ++++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4c68c836080..268c7a81108 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,9 @@ v 8.8.0 (unreleased) - Added multiple colors for labels in dropdowns when dups happen. - Improve description for the Two-factor Authentication sign-in screen. (Connor Shea) +v 8.7.3 + - Emails, Gitlab::Email::Message, Gitlab::Diff, and Premailer::Adapter::Nokogiri are now instrumented + v 8.7.2 - The "New Branch" button is now loaded asynchronously - Fix error 500 when trying to create a wiki page diff --git a/config/initializers/metrics.rb b/config/initializers/metrics.rb index 283936d0efc..b2d08d87bac 100644 --- a/config/initializers/metrics.rb +++ b/config/initializers/metrics.rb @@ -61,12 +61,30 @@ if Gitlab::Metrics.enabled? config.instrument_instance_methods(const) end - Dir[Rails.root.join('app', 'finders', '*.rb')].each do |path| - const = File.basename(path, '.rb').camelize.constantize - - config.instrument_instance_methods(const) + # Path to search => prefix to strip from constant + paths_to_instrument = { + ['app', 'finders'] => ['app', 'finders'], + ['app', 'mailers', 'emails'] => ['app', 'mailers'], + ['app', 'services', '**'] => ['app', 'services'], + ['lib', 'gitlab', 'diff'] => ['lib'], + ['lib', 'gitlab', 'email', 'message'] => ['lib'] + } + + paths_to_instrument.each do |(path, prefix)| + prefix = Rails.root.join(*prefix) + + Dir[Rails.root.join(*path + ['*.rb'])].each do |file_path| + path = Pathname.new(file_path).relative_path_from(prefix) + const = path.to_s.sub('.rb', '').camelize.constantize + + config.instrument_methods(const) + config.instrument_instance_methods(const) + end end + config.instrument_methods(Premailer::Adapter::Nokogiri) + config.instrument_instance_methods(Premailer::Adapter::Nokogiri) + [ :Blame, :Branch, :BranchCollection, :Blob, :Commit, :Diff, :Repository, :Tag, :TagCollection, :Tree @@ -97,17 +115,6 @@ if Gitlab::Metrics.enabled? config.instrument_methods(Gitlab::ReferenceExtractor) config.instrument_instance_methods(Gitlab::ReferenceExtractor) - # Instrument all service classes - services = Rails.root.join('app', 'services') - - Dir[services.join('**', '*.rb')].each do |file_path| - path = Pathname.new(file_path).relative_path_from(services) - const = path.to_s.sub('.rb', '').camelize.constantize - - config.instrument_methods(const) - config.instrument_instance_methods(const) - end - # Instrument the classes used for checking if somebody has push access. config.instrument_instance_methods(Gitlab::GitAccess) config.instrument_instance_methods(Gitlab::GitAccessWiki) -- cgit v1.2.1 From 44f89eafc08a7967544429a3f930354a5f9bbbaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 15 Apr 2016 12:15:52 +0200 Subject: Use Rugged's TagCollection#create instead of gitlab-shell's Repository#add_tag for better performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- CHANGELOG | 1 + app/models/repository.rb | 11 ++++++++-- app/services/create_tag_service.rb | 38 +++++++++++++++------------------- features/steps/project/commits/tags.rb | 4 ++-- lib/gitlab/backend/shell.rb | 18 ---------------- spec/models/repository_spec.rb | 11 ++++++---- spec/requests/api/tags_spec.rb | 4 ++-- 7 files changed, 38 insertions(+), 49 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4c5c2b42dfa..577a3643d97 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,7 @@ v 8.8.0 (unreleased) - Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea) - Added button to toggle whitespaces changes on diff view - Backport GitLab Enterprise support from EE + - Create tags using Rugged for performance reasons. !3745 - Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718 - Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes) - Added multiple colors for labels in dropdowns when dups happen. diff --git a/app/models/repository.rb b/app/models/repository.rb index b4319297e43..c4e38980a83 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -146,10 +146,17 @@ class Repository find_branch(branch_name) end - def add_tag(tag_name, ref, message = nil) + def add_tag(user, tag_name, ref, message = nil) before_push_tag - gitlab_shell.add_tag(path_with_namespace, tag_name, ref, message) + options = { message: message, tagger: user_to_committer(user) } if message + + tag = rugged.tags.create(tag_name, ref, options) + if tag.annotated? + Gitlab::Git::Tag.new(tag_name, ref, tag.annotation.message) + else + Gitlab::Git::Tag.new(tag_name, ref) + end end def rm_branch(user, branch_name) diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb index 55985380d31..775f9db2a46 100644 --- a/app/services/create_tag_service.rb +++ b/app/services/create_tag_service.rb @@ -8,32 +8,28 @@ class CreateTagService < BaseService end repository = project.repository - existing_tag = repository.find_tag(tag_name) - if existing_tag - return error('Tag already exists') - end - message.strip! if message + begin + new_tag = repository.add_tag(current_user, tag_name, ref, message) + rescue Rugged::TagError + return error("Tag #{tag_name} already exists") + rescue Rugged::ReferenceError + return error("Target #{ref} is invalid") + end - repository.add_tag(tag_name, ref, message) - new_tag = repository.find_tag(tag_name) - - if new_tag - push_data = create_push_data(project, current_user, new_tag) - EventCreateService.new.push(project, current_user, push_data) - project.execute_hooks(push_data.dup, :tag_push_hooks) - project.execute_services(push_data.dup, :tag_push_hooks) - CreateCommitBuildsService.new.execute(project, current_user, push_data) + push_data = create_push_data(project, current_user, new_tag) - if release_description - CreateReleaseService.new(@project, @current_user). - execute(tag_name, release_description) - end + EventCreateService.new.push(project, current_user, push_data) + project.execute_hooks(push_data.dup, :tag_push_hooks) + project.execute_services(push_data.dup, :tag_push_hooks) + CreateCommitBuildsService.new.execute(project, current_user, push_data) - success(new_tag) - else - error('Invalid reference name') + if release_description + CreateReleaseService.new(@project, @current_user). + execute(tag_name, release_description) end + + success(new_tag) end def success(branch) diff --git a/features/steps/project/commits/tags.rb b/features/steps/project/commits/tags.rb index eff4234a44a..912ba580efd 100644 --- a/features/steps/project/commits/tags.rb +++ b/features/steps/project/commits/tags.rb @@ -57,11 +57,11 @@ class Spinach::Features::ProjectCommitsTags < Spinach::FeatureSteps end step 'I should see new an error that tag ref is invalid' do - expect(page).to have_content 'Invalid reference name' + expect(page).to have_content 'Target foo is invalid' end step 'I should see new an error that tag already exists' do - expect(page).to have_content 'Tag already exists' + expect(page).to have_content 'Tag v1.0.0 already exists' end step "I visit tag 'v1.1.0' page" do diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index 5e2fb863a8f..132f9cd1966 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -79,24 +79,6 @@ module Gitlab 'rm-project', "#{name}.git"]) end - # Add repository tag from passed ref - # - # path - project path with namespace - # tag_name - new tag name - # ref - HEAD for new tag - # message - optional message for tag (annotated tag) - # - # Ex. - # add_tag("gitlab/gitlab-ci", "v4.0", "master") - # add_tag("gitlab/gitlab-ci", "v4.0", "master", "message") - # - def add_tag(path, tag_name, ref, message = nil) - cmd = %W(#{gitlab_shell_path}/bin/gitlab-projects create-tag #{path}.git - #{tag_name} #{ref}) - cmd << message unless message.nil? || message.empty? - Gitlab::Utils.system_silent(cmd) - end - # Gc repository # # path - project path with namespace diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 397bb5a8028..5cdf644a0e1 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -859,12 +859,15 @@ describe Repository, models: true do describe '#add_tag' do it 'adds a tag' do + user = build_stubbed(:user) expect(repository).to receive(:before_push_tag) + expect(repository.rugged.tags).to receive(:create). + with('8.5', 'master', + hash_including(message: 'foo', + tagger: hash_including(name: user.name, email: user.email))). + and_call_original - expect_any_instance_of(Gitlab::Shell).to receive(:add_tag). - with(repository.path_with_namespace, '8.5', 'master', 'foo') - - repository.add_tag('8.5', 'master', 'foo') + repository.add_tag(user, '8.5', 'master', 'foo') end end diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb index edcb2bedbf7..12e170b232f 100644 --- a/spec/requests/api/tags_spec.rb +++ b/spec/requests/api/tags_spec.rb @@ -147,7 +147,7 @@ describe API::API, api: true do tag_name: 'v8.0.0', ref: 'master' expect(response.status).to eq(400) - expect(json_response['message']).to eq('Tag already exists') + expect(json_response['message']).to eq('Tag v8.0.0 already exists') end it 'should return 400 if ref name is invalid' do @@ -155,7 +155,7 @@ describe API::API, api: true do tag_name: 'mytag', ref: 'foo' expect(response.status).to eq(400) - expect(json_response['message']).to eq('Invalid reference name') + expect(json_response['message']).to eq('Target foo is invalid') end end -- cgit v1.2.1 From 209f2f1e6fd861dd7bb6a73389400b4bb266d26d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 25 Apr 2016 16:31:45 +0200 Subject: Use a similar approach to branch creation for tag creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- app/models/repository.rb | 17 +++++----- app/services/create_branch_service.rb | 5 --- app/services/create_tag_service.rb | 46 +++++++++------------------ spec/models/repository_spec.rb | 34 ++++++++++++++------ spec/services/create_tag_service_spec.rb | 53 ++++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 53 deletions(-) create mode 100644 spec/services/create_tag_service_spec.rb diff --git a/app/models/repository.rb b/app/models/repository.rb index c4e38980a83..d5d70f41fd3 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -146,17 +146,20 @@ class Repository find_branch(branch_name) end - def add_tag(user, tag_name, ref, message = nil) - before_push_tag + def add_tag(user, tag_name, target, message = nil) + oldrev = Gitlab::Git::BLANK_SHA + ref = Gitlab::Git::TAG_REF_PREFIX + tag_name + target = commit(target).try(:id) + + return false unless target options = { message: message, tagger: user_to_committer(user) } if message - tag = rugged.tags.create(tag_name, ref, options) - if tag.annotated? - Gitlab::Git::Tag.new(tag_name, ref, tag.annotation.message) - else - Gitlab::Git::Tag.new(tag_name, ref) + GitHooksService.new.execute(user, path_to_repo, oldrev, target, ref) do + rugged.tags.create(tag_name, target, options) end + + find_tag(tag_name) end def rm_branch(user, branch_name) diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb index 707c2f7ff85..9f4481a8153 100644 --- a/app/services/create_branch_service.rb +++ b/app/services/create_branch_service.rb @@ -43,9 +43,4 @@ class CreateBranchService < BaseService out[:branch] = branch out end - - def build_push_data(project, user, branch) - Gitlab::PushDataBuilder. - build(project, user, Gitlab::Git::BLANK_SHA, branch.target, "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch.name}", []) - end end diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb index 775f9db2a46..91ed0e354d0 100644 --- a/app/services/create_tag_service.rb +++ b/app/services/create_tag_service.rb @@ -1,46 +1,30 @@ require_relative 'base_service' class CreateTagService < BaseService - def execute(tag_name, ref, message, release_description = nil) + def execute(tag_name, target, message, release_description = nil) valid_tag = Gitlab::GitRefValidator.validate(tag_name) - if valid_tag == false - return error('Tag name invalid') - end + return error('Tag name invalid') unless valid_tag repository = project.repository message.strip! if message + + new_tag = nil begin - new_tag = repository.add_tag(current_user, tag_name, ref, message) + new_tag = repository.add_tag(current_user, tag_name, target, message) rescue Rugged::TagError return error("Tag #{tag_name} already exists") - rescue Rugged::ReferenceError - return error("Target #{ref} is invalid") + rescue GitHooksService::PreReceiveError + return error('Tag creation was rejected by Git hook') end - push_data = create_push_data(project, current_user, new_tag) - - EventCreateService.new.push(project, current_user, push_data) - project.execute_hooks(push_data.dup, :tag_push_hooks) - project.execute_services(push_data.dup, :tag_push_hooks) - CreateCommitBuildsService.new.execute(project, current_user, push_data) - - if release_description - CreateReleaseService.new(@project, @current_user). - execute(tag_name, release_description) + if new_tag + if release_description + CreateReleaseService.new(@project, @current_user). + execute(tag_name, release_description) + end + success.merge(tag: new_tag) + else + error("Target #{target} is invalid") end - - success(new_tag) - end - - def success(branch) - out = super() - out[:tag] = branch - out - end - - def create_push_data(project, user, tag) - commits = [project.commit(tag.target)].compact - Gitlab::PushDataBuilder. - build(project, user, Gitlab::Git::BLANK_SHA, tag.target, "#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}", commits, tag.message) end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 5cdf644a0e1..b3359a42237 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -858,16 +858,30 @@ describe Repository, models: true do end describe '#add_tag' do - it 'adds a tag' do - user = build_stubbed(:user) - expect(repository).to receive(:before_push_tag) - expect(repository.rugged.tags).to receive(:create). - with('8.5', 'master', - hash_including(message: 'foo', - tagger: hash_including(name: user.name, email: user.email))). - and_call_original - - repository.add_tag(user, '8.5', 'master', 'foo') + context 'with a valid target' do + let(:user) { build_stubbed(:user) } + + it 'creates the tag using rugged' do + expect(repository.rugged.tags).to receive(:create). + with('8.5', repository.commit('master').id, + hash_including(message: 'foo', + tagger: hash_including(name: user.name, email: user.email))). + and_call_original + + repository.add_tag(user, '8.5', 'master', 'foo') + end + + it 'returns a Gitlab::Git::Tag object' do + tag = repository.add_tag(user, '8.5', 'master', 'foo') + + expect(tag).to be_a(Gitlab::Git::Tag) + end + end + + context 'with an invalid target' do + it 'returns false' do + expect(repository.add_tag(user, '8.5', 'bar', 'foo')).to be false + end end end diff --git a/spec/services/create_tag_service_spec.rb b/spec/services/create_tag_service_spec.rb new file mode 100644 index 00000000000..91f9e663b66 --- /dev/null +++ b/spec/services/create_tag_service_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe CreateTagService, services: true do + let(:project) { create(:project) } + let(:repository) { project.repository } + let(:user) { create(:user) } + let(:service) { described_class.new(project, user) } + + describe '#execute' do + it 'creates the tag and returns success' do + response = service.execute('v42.42.42', 'master', 'Foo') + + expect(response[:status]).to eq(:success) + expect(response[:tag]).to be_a Gitlab::Git::Tag + expect(response[:tag].name).to eq('v42.42.42') + end + + context 'when target is invalid' do + it 'returns an error' do + response = service.execute('v1.1.0', 'foo', 'Foo') + + expect(response).to eq(status: :error, + message: 'Target foo is invalid') + end + end + + context 'when tag already exists' do + it 'returns an error' do + expect(repository).to receive(:add_tag). + with(user, 'v1.1.0', 'master', 'Foo'). + and_raise(Rugged::TagError) + + response = service.execute('v1.1.0', 'master', 'Foo') + + expect(response).to eq(status: :error, + message: 'Tag v1.1.0 already exists') + end + end + + context 'when pre-receive hook fails' do + it 'returns an error' do + expect(repository).to receive(:add_tag). + with(user, 'v1.1.0', 'master', 'Foo'). + and_raise(GitHooksService::PreReceiveError) + + response = service.execute('v1.1.0', 'master', 'Foo') + + expect(response).to eq(status: :error, + message: 'Tag creation was rejected by Git hook') + end + end + end +end -- cgit v1.2.1 From fb5682e7cd587e7e6c871588240fc49b325b042f Mon Sep 17 00:00:00 2001 From: Artem Sidorenko Date: Sat, 30 Apr 2016 16:35:10 +0200 Subject: Use the new admin settings for gravatar --- CHANGELOG | 1 + app/views/profiles/show.html.haml | 4 ++-- config/gitlab.yml.example | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index cc6588c6cbd..4505b424987 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,7 @@ v 8.8.0 (unreleased) - Added multiple colors for labels in dropdowns when dups happen. - Improve description for the Two-factor Authentication sign-in screen. (Connor Shea) - API support for the 'since' and 'until' operators on commit requests (Paco Guzman) + - Fix Gravatar hint in user profile when Gravatar is disabled. !3988 (Artem Sidorenko) v 8.7.3 - Emails, Gitlab::Email::Message, Gitlab::Diff, and Premailer::Adapter::Nokogiri are now instrumented diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index f59d27f7ed0..eef50d887c7 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -8,11 +8,11 @@ %p - if @user.avatar? You can change your avatar here - - if Gitlab.config.gravatar.enabled + - if gravatar_enabled? or remove the current avatar to revert to #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} - else You can upload an avatar here - - if Gitlab.config.gravatar.enabled + - if gravatar_enabled? or change it at #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} .col-lg-9 .clearfix.avatar-image.append-bottom-default diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 07ce4b6d715..e682bcb976d 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -152,7 +152,6 @@ production: &base ## Gravatar ## For Libravatar see: http://doc.gitlab.com/ce/customization/libravatar.html gravatar: - enabled: true # Use user avatar image from Gravatar.com (default: true) # gravatar urls: possible placeholders: %{hash} %{size} %{email} # plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon # ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon -- cgit v1.2.1 From 731b231357f3b0b71f60a3bb1f81f8cd78f3e318 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 3 May 2016 20:55:35 -0700 Subject: Log to application.log when an admin starts and stops impersonating a user Closes gitlab-org/gitlab-ee#536 --- CHANGELOG | 1 + app/controllers/admin/impersonations_controller.rb | 2 ++ app/controllers/admin/users_controller.rb | 2 ++ 3 files changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index b2f5c283a1a..5f1793d472a 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.8.0 (unreleased) - Project#open_branches has been cleaned up and no longer loads entire records into memory. + - Log to application.log when an admin starts and stops impersonating a user - Make build status canceled if any of the jobs was canceled and none failed - Remove future dates from contribution calendar graph. - Support e-mail notifications for comments on project snippets diff --git a/app/controllers/admin/impersonations_controller.rb b/app/controllers/admin/impersonations_controller.rb index 2db824c87ef..8be35f00a77 100644 --- a/app/controllers/admin/impersonations_controller.rb +++ b/app/controllers/admin/impersonations_controller.rb @@ -7,6 +7,8 @@ class Admin::ImpersonationsController < Admin::ApplicationController warden.set_user(impersonator, scope: :user) + Gitlab::AppLogger.info("User #{original_user.username} has stopped impersonating #{impersonator.username}") + session[:impersonator_id] = nil redirect_to admin_user_path(original_user) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index b8976fa09a9..f2f654c7bcd 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -41,6 +41,8 @@ class Admin::UsersController < Admin::ApplicationController warden.set_user(user, scope: :user) + Gitlab::AppLogger.info("User #{current_user.username} has started impersonating #{user.username}") + flash[:alert] = "You are now impersonating #{user.username}" redirect_to root_path -- cgit v1.2.1 From b9672d4b38514a14cc39773d30f55c9629973f63 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 4 May 2016 00:59:20 -0700 Subject: Limit the number of merge requests per project to avoid long seeds This step was taking a long time because seed_fu creates N / 2 merge requests for each repo, where N is the number of branches for that repo. At the time of this writing, there are 234 branches on the gitlab-ce repo, leading to 117 merge requests. --- db/fixtures/development/10_merge_requests.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/db/fixtures/development/10_merge_requests.rb b/db/fixtures/development/10_merge_requests.rb index 0825776ffaa..87fb8e3300d 100644 --- a/db/fixtures/development/10_merge_requests.rb +++ b/db/fixtures/development/10_merge_requests.rb @@ -1,6 +1,9 @@ Gitlab::Seeder.quiet do + # Limit the number of merge requests per project to avoid long seeds + MAX_NUM_MERGE_REQUESTS = 10 + Project.all.reject(&:empty_repo?).each do |project| - branches = project.repository.branch_names + branches = project.repository.branch_names.sample(MAX_NUM_MERGE_REQUESTS * 2) branches.each do |branch_name| break if branches.size < 2 -- cgit v1.2.1 From 525e05b6536123a3117b5ff53fd46a96382d5f9d Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 28 Apr 2016 16:48:37 -0700 Subject: Expire repository exists? and has_visible_content? caches after a push if necessary Closes #17012 --- CHANGELOG | 1 + app/services/git_push_service.rb | 1 + app/services/git_tag_push_service.rb | 1 + 3 files changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 25d26535b72..925740e5d98 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -20,6 +20,7 @@ v 8.8.0 (unreleased) - Improve description for the Two-factor Authentication sign-in screen. (Connor Shea) - API support for the 'since' and 'until' operators on commit requests (Paco Guzman) - Fix Gravatar hint in user profile when Gravatar is disabled. !3988 (Artem Sidorenko) + - Expire repository exists? and has_visible_content? caches after a push if necessary v 8.7.3 - Emails, Gitlab::Email::Message, Gitlab::Diff, and Premailer::Adapter::Nokogiri are now instrumented diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index b7af80055bf..66136b62617 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -17,6 +17,7 @@ class GitPushService < BaseService # 6. Checks if the project's main language has changed # def execute + @project.repository.after_create if @project.empty_repo? @project.repository.after_push_commit(branch_name, params[:newrev]) if push_remove_branch? diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb index 64271d8bc5c..7410442609d 100644 --- a/app/services/git_tag_push_service.rb +++ b/app/services/git_tag_push_service.rb @@ -2,6 +2,7 @@ class GitTagPushService < BaseService attr_accessor :push_data def execute + project.repository.after_create if project.empty_repo? project.repository.before_push_tag @push_data = build_push_data -- cgit v1.2.1 From 6b4e255aa86864571b7d8dbc338986d4017b4215 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Wed, 4 May 2016 15:00:33 -0500 Subject: Remove break-all from links --- app/assets/stylesheets/pages/notes.scss | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 9619d65db85..50ca755bcb6 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -114,10 +114,6 @@ ul.notes { word-break: keep-all; } } - - a { - word-break: break-all; - } } .note-header { -- cgit v1.2.1 From 75523d1df91cc871847a00cad4e5e1d44278a647 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 3 May 2016 21:32:49 -0700 Subject: Sanitize repo paths in new project error message Closes #17243 --- CHANGELOG | 1 + app/helpers/projects_helper.rb | 6 ++++++ app/views/projects/imports/new.html.haml | 2 +- spec/helpers/projects_helper_spec.rb | 9 +++++++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 25d26535b72..e5dc5e5d4a5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.8.0 (unreleased) - Project#open_branches has been cleaned up and no longer loads entire records into memory. - Make build status canceled if any of the jobs was canceled and none failed + - Sanitize repo paths in new project error message - Remove future dates from contribution calendar graph. - Support e-mail notifications for comments on project snippets - Use ActionDispatch Remote IP for Akismet checking diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 3d5e61d2c18..3720b0085e5 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -341,4 +341,10 @@ module ProjectsHelper ) end end + + def sanitize_repo_path(message) + return '' unless message.present? + + message.strip.gsub(Gitlab.config.gitlab_shell.repos_path.chomp('/'), "[REPOS PATH]") + end end diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml index 6027fb23360..a8a8caf7280 100644 --- a/app/views/projects/imports/new.html.haml +++ b/app/views/projects/imports/new.html.haml @@ -10,7 +10,7 @@ .panel-body %pre :preserve - #{@project.import_error.try(:strip)} + #{sanitize_repo_path(@project.import_error)} = form_for @project, url: namespace_project_import_path(@project.namespace, @project), method: :post, html: { class: 'form-horizontal' } do |f| = render "shared/import_form", f: f diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 62389188d2c..29bcb8c5892 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -131,4 +131,13 @@ describe ProjectsHelper do end end end + + describe '#sanitized_import_error' do + it 'removes the repo path' do + repo = File.join(Gitlab.config.gitlab_shell.repos_path, '/namespace/test.git') + import_error = "Could not clone #{repo}\n" + + expect(sanitize_repo_path(import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git') + end + end end -- cgit v1.2.1 From 655b2640ae9cbe2737369401969e99caeddf192d Mon Sep 17 00:00:00 2001 From: Benedikt Huss Date: Wed, 4 May 2016 09:34:25 +0200 Subject: Merge request widget displays TeamCity build state and code coverage correctly again --- .../javascripts/merge_request_widget.js.coffee | 12 ++++---- .../merge_request_widget_spec.js.coffee | 35 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 spec/javascripts/merge_request_widget_spec.js.coffee diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee index 065626beeb8..1abda3530c4 100644 --- a/app/assets/javascripts/merge_request_widget.js.coffee +++ b/app/assets/javascripts/merge_request_widget.js.coffee @@ -68,13 +68,13 @@ class @MergeRequestWidget $.getJSON @opts.ci_status_url, (data) => @readyForCICheck = true - if @firstCICheck - @firstCICheck = false + if @firstCICheck || @opts.ci_status is '' + if @firstCICheck + @firstCICheck = false @opts.ci_status = data.status - - if @opts.ci_status is '' - @opts.ci_status = data.status - return + @showCIStatus data.status + if data.coverage + @showCICoverage data.coverage if data.status isnt @opts.ci_status and data.status? @showCIStatus data.status diff --git a/spec/javascripts/merge_request_widget_spec.js.coffee b/spec/javascripts/merge_request_widget_spec.js.coffee new file mode 100644 index 00000000000..e1fb610654e --- /dev/null +++ b/spec/javascripts/merge_request_widget_spec.js.coffee @@ -0,0 +1,35 @@ +#= require merge_request_widget + +describe 'MergeRequestWidget', -> + + beforeEach -> + window.notifyPermissions = () -> + @opts = {ci_status_url:"http://sampledomain.local/ci/getstatus",ci_status:""} + @class = new MergeRequestWidget(@opts) + @ciStatusData = {"title":"Sample MR title","sha":"12a34bc5","status":"success","coverage":98} + + describe 'getCIStatus', -> + beforeEach -> + spyOn(jQuery, 'getJSON').and.callFake (req, cb) => + cb(@ciStatusData) + + it 'should call showCIStatus even if a notification should not be displayed', -> + spy = spyOn(@class, 'showCIStatus').and.stub() + @class.getCIStatus(false) + expect(spy).toHaveBeenCalledWith(@ciStatusData.status) + + it 'should call showCIStatus when a notification should be displayed', -> + spy = spyOn(@class, 'showCIStatus').and.stub() + @class.getCIStatus(true) + expect(spy).toHaveBeenCalledWith(@ciStatusData.status) + + it 'should call showCICoverage when the coverage rate is set', -> + spy = spyOn(@class, 'showCICoverage').and.stub() + @class.getCIStatus(true) + expect(spy).toHaveBeenCalledWith(@ciStatusData.coverage) + + it 'should not call showCICoverage when the coverage rate is not set', -> + @ciStatusData.coverage = null + spy = spyOn(@class, 'showCICoverage').and.stub() + @class.getCIStatus(true) + expect(spy).not.toHaveBeenCalled() -- cgit v1.2.1 From 92c25f42009ce42c439efa4236d14ac1440711e4 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 4 May 2016 17:33:58 -0400 Subject: Use `number_to_human_size` helper to show repository size This will intelligently format large repository sizes in GBs (or, shudder, TBs). --- app/helpers/projects_helper.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 3d5e61d2c18..058233c88ad 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -200,7 +200,8 @@ module ProjectsHelper end def repository_size(project = @project) - "#{project.repository_size} MB" + size_in_bytes = project.repository_size * 1.megabyte + number_to_human_size(size_in_bytes, delimiter: ',', precision: 2) rescue # In order to prevent 500 error # when application cannot allocate memory -- cgit v1.2.1 From 5448970950008fb49092fcfbdb155161d707e10f Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 4 May 2016 17:39:06 -0400 Subject: Remove `rescue` clause from `repository_size` helper The repository size has since become calculated (and cached) more intelligently, and this should no longer be necessary. --- app/helpers/projects_helper.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 058233c88ad..20e47f77b48 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -202,11 +202,6 @@ module ProjectsHelper def repository_size(project = @project) size_in_bytes = project.repository_size * 1.megabyte number_to_human_size(size_in_bytes, delimiter: ',', precision: 2) - rescue - # In order to prevent 500 error - # when application cannot allocate memory - # to calculate repo size - just show 'Unknown' - 'unknown' end def default_url_to_repo(project = @project) -- cgit v1.2.1 From 0e9c2e721b08e244e63f1d26ac3771a8d858cd76 Mon Sep 17 00:00:00 2001 From: Benedikt Huss Date: Wed, 4 May 2016 20:45:12 +0200 Subject: Feedback from stanhu --- CHANGELOG | 1 + .../javascripts/merge_request_widget.js.coffee | 19 ++++++++----------- spec/javascripts/merge_request_widget_spec.js.coffee | 20 +++++++++++++++++--- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0e6e2505ec6..d2ff4c32f2d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -22,6 +22,7 @@ v 8.8.0 (unreleased) - API support for the 'since' and 'until' operators on commit requests (Paco Guzman) - Fix Gravatar hint in user profile when Gravatar is disabled. !3988 (Artem Sidorenko) - Expire repository exists? and has_visible_content? caches after a push if necessary + - Merge request widget displays TeamCity build state and code coverage correctly again. v 8.7.3 - Emails, Gitlab::Email::Message, Gitlab::Diff, and Premailer::Adapter::Nokogiri are now instrumented diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee index 1abda3530c4..17a5a057a94 100644 --- a/app/assets/javascripts/merge_request_widget.js.coffee +++ b/app/assets/javascripts/merge_request_widget.js.coffee @@ -68,20 +68,18 @@ class @MergeRequestWidget $.getJSON @opts.ci_status_url, (data) => @readyForCICheck = true - if @firstCICheck || @opts.ci_status is '' - if @firstCICheck - @firstCICheck = false - @opts.ci_status = data.status - @showCIStatus data.status - if data.coverage - @showCICoverage data.coverage + if data.status is '' + return - if data.status isnt @opts.ci_status and data.status? + if @firstCiCheck || data.status isnt @opts.ci_status and data.status? + @opts.ci_status = data.status @showCIStatus data.status if data.coverage @showCICoverage data.coverage - if showNotification + # The first check should only update the UI, a notification + # should only be displayed on status changes + if showNotification and not @firstCiCheck status = @ciLabelForStatus(data.status) if status is "preparing" @@ -104,8 +102,7 @@ class @MergeRequestWidget @close() Turbolinks.visit _this.opts.builds_path ) - - @opts.ci_status = data.status + @firstCiCheck = false showCIStatus: (state) -> $('.ci_widget').hide() diff --git a/spec/javascripts/merge_request_widget_spec.js.coffee b/spec/javascripts/merge_request_widget_spec.js.coffee index e1fb610654e..c0bd8a29e43 100644 --- a/spec/javascripts/merge_request_widget_spec.js.coffee +++ b/spec/javascripts/merge_request_widget_spec.js.coffee @@ -4,7 +4,21 @@ describe 'MergeRequestWidget', -> beforeEach -> window.notifyPermissions = () -> - @opts = {ci_status_url:"http://sampledomain.local/ci/getstatus",ci_status:""} + window.notify = () -> + @opts = { + ci_status_url:"http://sampledomain.local/ci/getstatus", + ci_status:"", + ci_message: { + normal: "Build {{status}} for \"{{title}}\"", + preparing: "{{status}} build for \"{{title}}\"" + }, + ci_title: { + preparing: "{{status}} build", + normal: "Build {{status}}" + }, + gitlab_icon:"gitlab_logo.png", + builds_path:"http://sampledomain.local/sampleBuildsPath" + } @class = new MergeRequestWidget(@opts) @ciStatusData = {"title":"Sample MR title","sha":"12a34bc5","status":"success","coverage":98} @@ -25,11 +39,11 @@ describe 'MergeRequestWidget', -> it 'should call showCICoverage when the coverage rate is set', -> spy = spyOn(@class, 'showCICoverage').and.stub() - @class.getCIStatus(true) + @class.getCIStatus(false) expect(spy).toHaveBeenCalledWith(@ciStatusData.coverage) it 'should not call showCICoverage when the coverage rate is not set', -> @ciStatusData.coverage = null spy = spyOn(@class, 'showCICoverage').and.stub() - @class.getCIStatus(true) + @class.getCIStatus(false) expect(spy).not.toHaveBeenCalled() -- cgit v1.2.1