From 6e6a99061dbec4bb45a398a03e8a13a084e44035 Mon Sep 17 00:00:00 2001 From: Ted Hogan Date: Mon, 23 Nov 2015 11:36:47 -0700 Subject: No space required after WIP identifier Modified changelog --- CHANGELOG | 1 + app/models/merge_request.rb | 2 +- spec/models/merge_request_spec.rb | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index fc7b6e75b1d..2453b35ead3 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.3.0 (unreleased) - Fix: Assignee selector is empty when 'Unassigned' is selected (Jose Corcuera) + - WIP identifier on merge requests no longer requires trailing space v 8.2.0 - Improved performance of finding projects and groups in various places diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 1b3d6079d2c..2b336ca8927 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -239,7 +239,7 @@ class MergeRequest < ActiveRecord::Base end def work_in_progress? - !!(title =~ /\A\[?WIP\]?:? /i) + !!(title =~ /\A\[?WIP(\]|:| )/i) end def mergeable? diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 567c911425c..edf211c85c1 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -162,6 +162,21 @@ describe MergeRequest do expect(subject).to be_work_in_progress end + it "detects the 'WIP' prefix" do + subject.title = "WIP#{subject.title}" + expect(subject).to be_work_in_progress + end + + it "detects the 'WIP:' prefix" do + subject.title = "WIP:#{subject.title}" + expect(subject).to be_work_in_progress + end + + it "detects the '[WIP]' prefix" do + subject.title = "[WIP]#{subject.title}" + expect(subject).to be_work_in_progress + end + it "doesn't detect WIP for words starting with WIP" do subject.title = "Wipwap #{subject.title}" expect(subject).not_to be_work_in_progress -- cgit v1.2.1 From f0c2f7481febf1e1149cb3dba87780c462759d14 Mon Sep 17 00:00:00 2001 From: Ted Hogan Date: Wed, 6 Jan 2016 10:48:08 -0700 Subject: Removed redundent and incorrect tests on WIP --- spec/models/merge_request_spec.rb | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 0d3901f4d00..ecfbbb0cfc9 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -193,16 +193,6 @@ describe MergeRequest, models: true do expect(subject).to be_work_in_progress end - it "detects the 'WIP' prefix" do - subject.title = "WIP#{subject.title}" - expect(subject).to be_work_in_progress - end - - it "detects the 'WIP:' prefix" do - subject.title = "WIP:#{subject.title}" - expect(subject).to be_work_in_progress - end - it "detects the '[WIP]' prefix" do subject.title = "[WIP]#{subject.title}" expect(subject).to be_work_in_progress -- cgit v1.2.1 From 67a6fee5b124a768279b0681b52be19f138530dc Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 15 Jan 2016 18:12:36 +0100 Subject: Prototype of Git blobs via workhorse --- app/controllers/projects/raw_controller.rb | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index be7d5c187fe..e55cdea94ae 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -1,3 +1,5 @@ +require 'base64' + # Controller for viewing a file's raw class Projects::RawController < Projects::ApplicationController include ExtractsPath @@ -15,7 +17,10 @@ class Projects::RawController < Projects::ApplicationController if @blob.lfs_pointer? send_lfs_object else - stream_data + headers['Gitlab-Workhorse-Repo-Path'] = @repository.path_to_repo + headers['Gitlab-Workhorse-Send-Blob'] = Base64.urlsafe_encode64(@commit.id + ':' + @path) + headers['Content-Disposition'] = 'inline' + render nothing: true, content_type: get_blob_type end else render_404 @@ -34,16 +39,6 @@ class Projects::RawController < Projects::ApplicationController end end - def stream_data - type = get_blob_type - - send_data( - @blob.data, - type: type, - disposition: 'inline' - ) - end - def send_lfs_object lfs_object = find_lfs_object -- cgit v1.2.1 From 53ddb8f2ccaa95a19d530827e3fc7500d02ccfff Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Wed, 20 Jan 2016 13:44:39 +0100 Subject: Use a /raw/ request to show an image --- app/views/projects/blob/_image.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/blob/_image.html.haml b/app/views/projects/blob/_image.html.haml index c090f690d1d..51fa91b08e4 100644 --- a/app/views/projects/blob/_image.html.haml +++ b/app/views/projects/blob/_image.html.haml @@ -1,2 +1,2 @@ .file-content.image_file - %img{ src: "data:#{blob.mime_type};base64,#{Base64.encode64(blob.data)}"} + %img{ src: namespace_project_raw_path(@project.namespace, @project, @id)} -- cgit v1.2.1 From d781eee575ffd5e05500e9e2e18c1a2a245a2339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis=20Roch=C3=A9?= Date: Fri, 22 Jan 2016 14:33:25 +0000 Subject: Fix typo indentation in CI projects' API --- doc/ci/api/projects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ci/api/projects.md b/doc/ci/api/projects.md index 74a4c64d000..fe6b1c01352 100644 --- a/doc/ci/api/projects.md +++ b/doc/ci/api/projects.md @@ -18,7 +18,7 @@ GET /ci/projects Returns: ```json - [ +[ { "id" : 271, "name" : "gitlabhq", -- cgit v1.2.1 From acfc526828923db381ab01d872ecd1b82618ddc3 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Mon, 25 Jan 2016 06:34:30 +0000 Subject: update OAuth doc --- doc/integration/oauth_provider.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md index dbe5a175c82..f0c2a45b6ae 100644 --- a/doc/integration/oauth_provider.md +++ b/doc/integration/oauth_provider.md @@ -26,7 +26,7 @@ Every application you authorized will be shown in your "Authorized application" ![authorized_application](img/oauth_provider_authorized_application.png) -At any time you can revoke access just clicking button "Revoke" +As you can see we use default scope "api" here which is only scope we have so far. At any time you can revoke access just clicking button "Revoke". ### OAuth applications in admin area -- cgit v1.2.1 From 5287da7412e01ac1508bd15bec5bae7c3a0afa1b Mon Sep 17 00:00:00 2001 From: fbretel Date: Mon, 25 Jan 2016 13:19:27 +0000 Subject: Consistent rails_socket use. --- lib/support/init.d/gitlab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab index 1633891c8a0..9e90a99f15b 100755 --- a/lib/support/init.d/gitlab +++ b/lib/support/init.d/gitlab @@ -219,7 +219,7 @@ start_gitlab() { echo "The Unicorn web server already running with pid $wpid, not restarting." else # Remove old socket if it exists - rm -f "$socket_path"/gitlab.socket 2>/dev/null + rm -f "$rails_socket" 2>/dev/null # Start the web server RAILS_ENV=$RAILS_ENV bin/web start fi -- cgit v1.2.1 From e32eb5715141101a95e97c4f51a2f96976822c9a Mon Sep 17 00:00:00 2001 From: Mike Chelen Date: Wed, 27 Jan 2016 02:10:03 +0000 Subject: explicitly call script with bash for consistency --- doc/ci/languages/php.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ci/languages/php.md b/doc/ci/languages/php.md index 77f9fae5bb6..aeadd6a448e 100644 --- a/doc/ci/languages/php.md +++ b/doc/ci/languages/php.md @@ -97,7 +97,7 @@ image: php:5.6 before_script: # Install dependencies -- ci/docker_install.sh > /dev/null +- bash ci/docker_install.sh > /dev/null test:app: script: @@ -112,7 +112,7 @@ with a different docker image version and the runner will do the rest: ```yaml before_script: # Install dependencies -- ci/docker_install.sh > /dev/null +- bash ci/docker_install.sh > /dev/null # We test PHP5.6 test:5.6: -- cgit v1.2.1 From 9109619ee6fe85ee7e8ebfa51c6587319b523930 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 28 Jan 2016 15:02:44 +0100 Subject: Use less memory while counting lines --- app/views/shared/_file_highlight.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml index 2bc98983d67..331bad3ccf7 100644 --- a/app/views/shared/_file_highlight.html.haml +++ b/app/views/shared/_file_highlight.html.haml @@ -1,7 +1,7 @@ .file-content.code.js-syntax-highlight{ class: user_color_scheme } .line-numbers - if blob.data.present? - - blob.data.lines.each_index do |index| + - 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. -- cgit v1.2.1 From 26d97ac5e19c242594b59d224a77d41d0f1de6e1 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 28 Jan 2016 18:04:46 +0100 Subject: Send more raw blob data with workhorse --- app/controllers/projects/avatars_controller.rb | 13 ++++++------- app/controllers/projects/raw_controller.rb | 2 +- lib/api/repositories.rb | 6 ++++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb index 548f1b9ebfe..0cd65ad5b16 100644 --- a/app/controllers/projects/avatars_controller.rb +++ b/app/controllers/projects/avatars_controller.rb @@ -2,15 +2,14 @@ class Projects::AvatarsController < Projects::ApplicationController before_action :project def show - @blob = @project.repository.blob_at_branch('master', @project.avatar_in_git) + repository = @project.repository + @blob = repository.blob_at_branch('master', @project.avatar_in_git) if @blob headers['X-Content-Type-Options'] = 'nosniff' - send_data( - @blob.data, - type: @blob.mime_type, - disposition: 'inline', - filename: @blob.name - ) + headers['Gitlab-Workhorse-Repo-Path'] = repository.path_to_repo + headers['Gitlab-Workhorse-Send-Blob'] = @blob.id + headers['Content-Disposition'] = 'inline' + render nothing: true, content_type: @blob.content_type else render_404 end diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index e55cdea94ae..b3c846bc3c3 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -18,7 +18,7 @@ class Projects::RawController < Projects::ApplicationController send_lfs_object else headers['Gitlab-Workhorse-Repo-Path'] = @repository.path_to_repo - headers['Gitlab-Workhorse-Send-Blob'] = Base64.urlsafe_encode64(@commit.id + ':' + @path) + headers['Gitlab-Workhorse-Send-Blob'] = @blob.id headers['Content-Disposition'] = 'inline' render nothing: true, content_type: get_blob_type end diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index d7c48639eba..0f4cd2443b0 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -57,7 +57,8 @@ module API not_found! "File" unless blob content_type 'text/plain' - present blob.data + header 'Gitlab-Workhorse-Repo-Path', repo.path_to_repo + header 'Gitlab-Workhorse-Send-Blob', blob.id end # Get a raw blob contents by blob sha @@ -83,7 +84,8 @@ module API env['api.format'] = :txt content_type blob.mime_type - present blob.data + header 'Gitlab-Workhorse-Repo-Path', repo.path_to_repo + header 'Gitlab-Workhorse-Send-Blob', blob.id end # Get a an archive of the repository -- cgit v1.2.1 From 368b855d88597a48637145838f61113af9c0e98e Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 28 Jan 2016 18:08:37 +0100 Subject: No need for base64 anymore --- app/controllers/projects/raw_controller.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index b3c846bc3c3..b8b90489027 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -1,5 +1,3 @@ -require 'base64' - # Controller for viewing a file's raw class Projects::RawController < Projects::ApplicationController include ExtractsPath -- cgit v1.2.1 From 0197549d57bd32ee933ee775c625ed6fc5f5eec8 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 28 Jan 2016 18:09:52 +0100 Subject: Cannot see a raw blob without workhorse --- features/steps/project/source/browse_files.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb index d08935aa101..71db552f7b4 100644 --- a/features/steps/project/source/browse_files.rb +++ b/features/steps/project/source/browse_files.rb @@ -52,7 +52,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps end step 'I should see raw file content' do - expect(source).to eq sample_blob.data + expect(source).to eq '' # Body is filled in by gitlab-workhorse end step 'I click button "Edit"' do -- cgit v1.2.1 From fc334e72f40ab5394c70f5cd29829dc3c0b0d485 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 29 Jan 2016 10:28:05 +0000 Subject: Adds the markdown link at the cursor poisition When writing a comment and then dropping an image it will correctly add the image markdown link at the cursor position Fixes #12822 --- app/assets/javascripts/dropzone_input.js.coffee | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/dropzone_input.js.coffee b/app/assets/javascripts/dropzone_input.js.coffee index c714c0fa939..32a5594a5b1 100644 --- a/app/assets/javascripts/dropzone_input.js.coffee +++ b/app/assets/javascripts/dropzone_input.js.coffee @@ -65,8 +65,13 @@ class @DropzoneInput return success: (header, response) -> + link_markdown = response.link.markdown child = $(dropzone[0]).children("textarea") - $(child).val $(child).val() + response.link.markdown + "\n" + cursor_pos = child.prop "selectionStart" + value = $(child).val() + new_text = "#{value.substring(0, cursor_pos)}#{link_markdown}#{value.substring(cursor_pos, value.length)}" + + $(child).val new_text + "\n" return error: (temp, errorMessage) -> -- cgit v1.2.1 From 76534e776e76ef868de7f41fa03bc933882a7b1e Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 29 Jan 2016 15:55:31 +0000 Subject: Keeps cursor at the correct place after changing text in dropzone --- app/assets/javascripts/dropzone_input.js.coffee | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/dropzone_input.js.coffee b/app/assets/javascripts/dropzone_input.js.coffee index 32a5594a5b1..b502131a99d 100644 --- a/app/assets/javascripts/dropzone_input.js.coffee +++ b/app/assets/javascripts/dropzone_input.js.coffee @@ -65,13 +65,7 @@ class @DropzoneInput return success: (header, response) -> - link_markdown = response.link.markdown - child = $(dropzone[0]).children("textarea") - cursor_pos = child.prop "selectionStart" - value = $(child).val() - new_text = "#{value.substring(0, cursor_pos)}#{link_markdown}#{value.substring(cursor_pos, value.length)}" - - $(child).val new_text + "\n" + pasteText response.link.markdown return error: (temp, errorMessage) -> @@ -133,6 +127,7 @@ class @DropzoneInput beforeSelection = $(child).val().substring 0, caretStart afterSelection = $(child).val().substring caretEnd, textEnd $(child).val beforeSelection + text + afterSelection + child.get(0).setSelectionRange caretStart + text.length, caretEnd + text.length form_textarea.trigger "input" getFilename = (e) -> -- cgit v1.2.1 From a1e1e72375c6b8f511c779c74b3dd1073afff6c1 Mon Sep 17 00:00:00 2001 From: Warren Guy Date: Sat, 30 Jan 2016 18:30:51 +0800 Subject: Generate valid Message-ID in email rejection mailer Use a Message-ID that is RFC 2111 compliant. This fix is consistent with how the Message-ID is generated in the 'notify' mailer. --- app/mailers/email_rejection_mailer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/mailers/email_rejection_mailer.rb b/app/mailers/email_rejection_mailer.rb index 883f1c73ad4..76db31a4c45 100644 --- a/app/mailers/email_rejection_mailer.rb +++ b/app/mailers/email_rejection_mailer.rb @@ -10,7 +10,7 @@ class EmailRejectionMailer < BaseMailer subject: "[Rejected] #{@original_message.subject}" } - headers['Message-ID'] = SecureRandom.hex + headers['Message-ID'] = "<#{SecureRandom.hex}@#{Gitlab.config.gitlab.host}>" headers['In-Reply-To'] = @original_message.message_id headers['References'] = @original_message.message_id -- cgit v1.2.1 From 026c31dafc80059ec429b484dc28e03e91df2238 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sat, 23 Jan 2016 14:59:22 -0800 Subject: Bump New Relic gem version to avoid warnings in Web page --- CHANGELOG | 1 + Gemfile | 2 +- Gemfile.lock | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0a21462ebdb..a8cbcdfe26d 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.5.0 (unreleased) - Ensure rake tasks that don't need a DB connection can be run without one + - Update New Relic gem to 3.14.1.311 (Stan Hu) - Add "visibility" flag to GET /projects api endpoint - Ignore binary files in code search to prevent Error 500 (Stan Hu) - Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push diff --git a/Gemfile b/Gemfile index a09d44f8bfd..a1a9c776ae7 100644 --- a/Gemfile +++ b/Gemfile @@ -299,7 +299,7 @@ group :production do gem "gitlab_meta", '7.0' end -gem "newrelic_rpm", '~> 3.9.4.245' +gem "newrelic_rpm", '~> 3.14' gem 'newrelic-grape' gem 'octokit', '~> 3.8.0' diff --git a/Gemfile.lock b/Gemfile.lock index ec92964df25..4ca79ccd49f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -481,7 +481,7 @@ GEM newrelic-grape (2.1.0) grape newrelic_rpm - newrelic_rpm (3.9.4.245) + newrelic_rpm (3.14.1.311) nokogiri (1.6.7.2) mini_portile2 (~> 2.0.0.rc2) nprogress-rails (0.1.6.7) @@ -961,7 +961,7 @@ DEPENDENCIES nested_form (~> 0.3.2) net-ssh (~> 3.0.1) newrelic-grape - newrelic_rpm (~> 3.9.4.245) + newrelic_rpm (~> 3.14) nokogiri (= 1.6.7.2) nprogress-rails (~> 0.1.6.7) oauth2 (~> 1.0.0) -- cgit v1.2.1 From 2828274b418cccc8171692495dd2856209dbfa49 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 25 Jan 2016 21:17:38 -0800 Subject: Remove newrelic_grape gem since the New Relic gem now provides native support: https://docs.newrelic.com/docs/agents/ruby-agent/frameworks/grape-instrumentation --- Gemfile | 1 - Gemfile.lock | 4 ---- 2 files changed, 5 deletions(-) diff --git a/Gemfile b/Gemfile index a1a9c776ae7..0420043e869 100644 --- a/Gemfile +++ b/Gemfile @@ -300,7 +300,6 @@ group :production do end gem "newrelic_rpm", '~> 3.14' -gem 'newrelic-grape' gem 'octokit', '~> 3.8.0' diff --git a/Gemfile.lock b/Gemfile.lock index 4ca79ccd49f..981607bdd6b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -478,9 +478,6 @@ GEM net-ldap (0.12.1) net-ssh (3.0.1) netrc (0.11.0) - newrelic-grape (2.1.0) - grape - newrelic_rpm newrelic_rpm (3.14.1.311) nokogiri (1.6.7.2) mini_portile2 (~> 2.0.0.rc2) @@ -960,7 +957,6 @@ DEPENDENCIES mysql2 (~> 0.3.16) nested_form (~> 0.3.2) net-ssh (~> 3.0.1) - newrelic-grape newrelic_rpm (~> 3.14) nokogiri (= 1.6.7.2) nprogress-rails (~> 0.1.6.7) -- cgit v1.2.1 From 9040010481e6ab9b1d9ee2d0699dc99d1109f2f2 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 14 Jan 2016 19:16:50 +0000 Subject: Added dropdown to list all projects on project header When clicking the current project name, it shows a dropdown menu with a list of all projects for that group or user --- app/assets/stylesheets/framework/header.scss | 22 ++++++++++++++++++++- app/helpers/projects_helper.rb | 29 ++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index f875b1460e7..0789d8133f9 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -73,7 +73,6 @@ header { .title { margin: 0; - overflow: hidden; font-size: 19px; line-height: $header-height; font-weight: normal; @@ -88,6 +87,27 @@ header { text-decoration: underline; } } + + .dropdown { + display: inline-block; + } + + .dropdown-toggle-caret { + margin-left: 5px; + } + + .dropdown-item { + &.active { + .dropdown-link { + color: #fff; + } + } + + .dropdown-link:hover { + color: #fff; + text-decoration: none; + } + } } .navbar-collapse { diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 8c8b355028c..5afbdb332cc 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -45,6 +45,7 @@ module ProjectsHelper end def project_title(project, name = nil, url = nil) + project_id = project.id namespace_link = if project.group link_to(simple_sanitize(project.group.name), group_path(project.group)) @@ -53,14 +54,34 @@ module ProjectsHelper link_to(simple_sanitize(owner.name), user_path(owner)) end - project_link = link_to(simple_sanitize(project.name), project_path(project)) + all_projects = + if project.group + project.group.projects + else + PersonalProjectsFinder.new(project.namespace.owner).execute(current_user) + end + + project_link = content_tag :div, {class: "dropdown"} do + output = content_tag :a, {class: "dropdown-toggle", href: "#", data: {toggle: "dropdown"}} do + btnOutput = simple_sanitize(project.name) + btnOutput += content_tag :span, nil, {class: "caret dropdown-toggle-caret"} + end + + list = all_projects.map do |project| + content_tag :li, {class: "dropdown-item #{"active" if project_id == project.id}"} do + link_to(simple_sanitize(project.name), project_path(project), {class: "dropdown-link"}) + end + end + + output += content_tag :ul, {class: "dropdown-menu"} do + list.join.html_safe + end + end full_title = namespace_link + ' / ' + project_link full_title += ' · '.html_safe + link_to(simple_sanitize(name), url) if name - content_tag :span do - full_title - end + full_title end def remove_project_message(project) -- cgit v1.2.1 From 14394e8bad388dcb331f16353af46755740b216a Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 15 Jan 2016 07:30:36 +0000 Subject: pulls in all user projects --- app/assets/stylesheets/framework/header.scss | 8 ++++++++ app/helpers/projects_helper.rb | 13 +++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 0789d8133f9..c71c1cbae34 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -92,8 +92,16 @@ header { display: inline-block; } + .dropdown-menu { + max-height: 300px; + overflow: auto; + } + .dropdown-toggle-caret { + position: relative; + top: -2px; margin-left: 5px; + font-size: 10px; } .dropdown-item { diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 5afbdb332cc..238bbbbe0a5 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -54,22 +54,19 @@ module ProjectsHelper link_to(simple_sanitize(owner.name), user_path(owner)) end - all_projects = - if project.group - project.group.projects - else - PersonalProjectsFinder.new(project.namespace.owner).execute(current_user) - end + all_projects = current_user.authorized_projects.sorted_by_activity.non_archived project_link = content_tag :div, {class: "dropdown"} do output = content_tag :a, {class: "dropdown-toggle", href: "#", data: {toggle: "dropdown"}} do btnOutput = simple_sanitize(project.name) - btnOutput += content_tag :span, nil, {class: "caret dropdown-toggle-caret"} + btnOutput += content_tag :span, nil, {class: "fa fa-chevron-down dropdown-toggle-caret"} end list = all_projects.map do |project| content_tag :li, {class: "dropdown-item #{"active" if project_id == project.id}"} do - link_to(simple_sanitize(project.name), project_path(project), {class: "dropdown-link"}) + link_to project_path(project), {class: "dropdown-link"} do + project.owner.name + ' / ' + simple_sanitize(project.name) + end end end -- cgit v1.2.1 From 81e7086fec60c368dcd54ff7195f37f6cb8f481c Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 15 Jan 2016 09:13:12 +0000 Subject: uses AJAX to select the projects --- app/assets/javascripts/project.js.coffee | 10 ++++++++++ app/assets/stylesheets/framework/common.scss | 4 ++-- app/assets/stylesheets/framework/header.scss | 22 ---------------------- app/helpers/projects_helper.rb | 20 ++++---------------- .../shared/_new_project_item_select.html.haml | 8 ++++---- 5 files changed, 20 insertions(+), 44 deletions(-) diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee index d7a658f8faa..9e313436804 100644 --- a/app/assets/javascripts/project.js.coffee +++ b/app/assets/javascripts/project.js.coffee @@ -50,3 +50,13 @@ class @Project $('#notifications-button').empty().append("" + label + "") $(@).parents('ul').find('li.active').removeClass 'active' $(@).parent().addClass 'active' + + @._projectSelectDropdown() + + _projectSelectDropdown: -> + new ProjectSelect() + + $('.js-projects-dropdown-toggle').on 'click', (e) -> + e.preventDefault() + + $('.js-projects-dropdown').select2 'open' diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 6ea2219073c..ea56d9e12a0 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -376,11 +376,11 @@ table { margin-bottom: $gl-padding; } -.new-project-item-select-holder { +.project-item-select-holder { display: inline-block; position: relative; - .new-project-item-select { + .project-item-select { position: absolute; top: 0; right: 0; diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index c71c1cbae34..7871a33b6c5 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -88,34 +88,12 @@ header { } } - .dropdown { - display: inline-block; - } - - .dropdown-menu { - max-height: 300px; - overflow: auto; - } - .dropdown-toggle-caret { position: relative; top: -2px; margin-left: 5px; font-size: 10px; } - - .dropdown-item { - &.active { - .dropdown-link { - color: #fff; - } - } - - .dropdown-link:hover { - color: #fff; - text-decoration: none; - } - } } .navbar-collapse { diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 238bbbbe0a5..c175de94361 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -56,23 +56,11 @@ module ProjectsHelper all_projects = current_user.authorized_projects.sorted_by_activity.non_archived - project_link = content_tag :div, {class: "dropdown"} do - output = content_tag :a, {class: "dropdown-toggle", href: "#", data: {toggle: "dropdown"}} do - btnOutput = simple_sanitize(project.name) - btnOutput += content_tag :span, nil, {class: "fa fa-chevron-down dropdown-toggle-caret"} - end - - list = all_projects.map do |project| - content_tag :li, {class: "dropdown-item #{"active" if project_id == project.id}"} do - link_to project_path(project), {class: "dropdown-link"} do - project.owner.name + ' / ' + simple_sanitize(project.name) - end - end - end + project_link = link_to project_path(project), {class: "project-item-select-holder js-projects-dropdown-toggle"} do + link_output = simple_sanitize(project.name) + link_output += content_tag :span, nil, {class: "fa fa-chevron-down dropdown-toggle-caret"} - output += content_tag :ul, {class: "dropdown-menu"} do - list.join.html_safe - end + link_output += project_select_tag :project_path, class: "project-item-select js-projects-dropdown", data: { include_groups: false } end full_title = namespace_link + ' / ' + project_link diff --git a/app/views/shared/_new_project_item_select.html.haml b/app/views/shared/_new_project_item_select.html.haml index c4431d66927..46095912821 100644 --- a/app/views/shared/_new_project_item_select.html.haml +++ b/app/views/shared/_new_project_item_select.html.haml @@ -1,6 +1,6 @@ - if @projects.any? - .prepend-left-10.new-project-item-select-holder - = project_select_tag :project_path, class: "new-project-item-select", data: { include_groups: local_assigns[:include_groups] } + .prepend-left-10.project-item-select-holder + = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups] } %a.btn.btn-new.new-project-item-select-button = icon('plus') = local_assigns[:label] @@ -8,12 +8,12 @@ :javascript $('.new-project-item-select-button').on('click', function() { - $('.new-project-item-select').select2('open'); + $('.project-item-select').select2('open'); }); var relativePath = '#{local_assigns[:path]}'; - $('.new-project-item-select').on('click', function() { + $('.project-item-select').on('click', function() { window.location = $(this).val() + '/' + relativePath; }); -- cgit v1.2.1 From a5267d0fbdc3e67d7d7cf3445fd1470676accc7a Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 15 Jan 2016 09:17:09 +0000 Subject: selecting project in dropdown takes user to the correct project --- app/assets/javascripts/project.js.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee index 9e313436804..fd7844baac4 100644 --- a/app/assets/javascripts/project.js.coffee +++ b/app/assets/javascripts/project.js.coffee @@ -56,6 +56,9 @@ class @Project _projectSelectDropdown: -> new ProjectSelect() + $('.project-item-select').on 'click', -> + window.location = $(this).val() + $('.js-projects-dropdown-toggle').on 'click', (e) -> e.preventDefault() -- cgit v1.2.1 From 60139345403fe2ddeed27a49582800b365606e2c Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 15 Jan 2016 11:08:12 +0000 Subject: fixes issue when user is not logged in but viewing public project --- app/helpers/projects_helper.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index c175de94361..6c66d0f7251 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -54,13 +54,15 @@ module ProjectsHelper link_to(simple_sanitize(owner.name), user_path(owner)) end - all_projects = current_user.authorized_projects.sorted_by_activity.non_archived + all_projects = current_user.authorized_projects.sorted_by_activity.non_archived if current_user - project_link = link_to project_path(project), {class: "project-item-select-holder js-projects-dropdown-toggle"} do + project_link = link_to project_path(project), {class: "project-item-select-holder #{"js-projects-dropdown-toggle" if current_user}"} do link_output = simple_sanitize(project.name) - link_output += content_tag :span, nil, {class: "fa fa-chevron-down dropdown-toggle-caret"} + link_output += content_tag :span, nil, {class: "fa fa-chevron-down dropdown-toggle-caret"} if current_user - link_output += project_select_tag :project_path, class: "project-item-select js-projects-dropdown", data: { include_groups: false } + link_output += project_select_tag :project_path, class: "project-item-select js-projects-dropdown", data: { include_groups: false } if current_user + + link_output end full_title = namespace_link + ' / ' + project_link -- cgit v1.2.1 From e79b5ff9d65b5a872bfc69649441d6262ac76b4d Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 15 Jan 2016 11:10:27 +0000 Subject: removed un-used variable --- app/helpers/projects_helper.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 6c66d0f7251..705d1e786f4 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -54,8 +54,6 @@ module ProjectsHelper link_to(simple_sanitize(owner.name), user_path(owner)) end - all_projects = current_user.authorized_projects.sorted_by_activity.non_archived if current_user - project_link = link_to project_path(project), {class: "project-item-select-holder #{"js-projects-dropdown-toggle" if current_user}"} do link_output = simple_sanitize(project.name) link_output += content_tag :span, nil, {class: "fa fa-chevron-down dropdown-toggle-caret"} if current_user -- cgit v1.2.1 From 09dc9bd5686501b2c9847896fee9713cf7cf4aea Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 15 Jan 2016 11:43:49 +0000 Subject: rubocop fixes --- app/helpers/projects_helper.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 705d1e786f4..e7e472cbb5b 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -45,7 +45,6 @@ module ProjectsHelper end def project_title(project, name = nil, url = nil) - project_id = project.id namespace_link = if project.group link_to(simple_sanitize(project.group.name), group_path(project.group)) @@ -54,9 +53,9 @@ module ProjectsHelper link_to(simple_sanitize(owner.name), user_path(owner)) end - project_link = link_to project_path(project), {class: "project-item-select-holder #{"js-projects-dropdown-toggle" if current_user}"} do + project_link = link_to project_path(project), { class: "project-item-select-holder #{"js-projects-dropdown-toggle" if current_user}" } do link_output = simple_sanitize(project.name) - link_output += content_tag :span, nil, {class: "fa fa-chevron-down dropdown-toggle-caret"} if current_user + link_output += content_tag :span, nil, { class: "fa fa-chevron-down dropdown-toggle-caret" } if current_user link_output += project_select_tag :project_path, class: "project-item-select js-projects-dropdown", data: { include_groups: false } if current_user -- cgit v1.2.1 From d34928ca580b9a605f1fb4f0bc0077b99d694d9b Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 15 Jan 2016 13:04:37 +0000 Subject: remove period from function call --- app/assets/javascripts/project.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee index fd7844baac4..15c5bfa47e9 100644 --- a/app/assets/javascripts/project.js.coffee +++ b/app/assets/javascripts/project.js.coffee @@ -51,7 +51,7 @@ class @Project $(@).parents('ul').find('li.active').removeClass 'active' $(@).parent().addClass 'active' - @._projectSelectDropdown() + @_projectSelectDropdown() _projectSelectDropdown: -> new ProjectSelect() -- cgit v1.2.1 From ad7ec74458523caad5c10108bde620de9a52fe12 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Sun, 17 Jan 2016 14:54:28 +0000 Subject: removed private method naming --- app/assets/javascripts/project.js.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee index 15c5bfa47e9..bf987f115ae 100644 --- a/app/assets/javascripts/project.js.coffee +++ b/app/assets/javascripts/project.js.coffee @@ -51,9 +51,9 @@ class @Project $(@).parents('ul').find('li.active').removeClass 'active' $(@).parent().addClass 'active' - @_projectSelectDropdown() + @projectSelectDropdown() - _projectSelectDropdown: -> + projectSelectDropdown: -> new ProjectSelect() $('.project-item-select').on 'click', -> -- cgit v1.2.1 From 56b0c46bf6da069be4ea935de4bad35a50e7f3c9 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Sun, 17 Jan 2016 17:19:50 +0000 Subject: added tests --- app/assets/javascripts/project.js.coffee | 9 +++-- spec/javascripts/fixtures/project_title.html.haml | 7 ++++ spec/javascripts/fixtures/projects.json | 1 + spec/javascripts/project_title_spec.js.coffee | 46 +++++++++++++++++++++++ 4 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 spec/javascripts/fixtures/project_title.html.haml create mode 100644 spec/javascripts/fixtures/projects.json create mode 100644 spec/javascripts/project_title_spec.js.coffee diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee index bf987f115ae..76bc4ff42a2 100644 --- a/app/assets/javascripts/project.js.coffee +++ b/app/assets/javascripts/project.js.coffee @@ -56,10 +56,13 @@ class @Project projectSelectDropdown: -> new ProjectSelect() - $('.project-item-select').on 'click', -> - window.location = $(this).val() + $('.project-item-select').on 'click', (e) => + @changeProject $(e.currentTarget).val() $('.js-projects-dropdown-toggle').on 'click', (e) -> e.preventDefault() - $('.js-projects-dropdown').select2 'open' + $('.js-projects-dropdown').select2('open') + + changeProject: (url) -> + window.location = url diff --git a/spec/javascripts/fixtures/project_title.html.haml b/spec/javascripts/fixtures/project_title.html.haml new file mode 100644 index 00000000000..4286d1be669 --- /dev/null +++ b/spec/javascripts/fixtures/project_title.html.haml @@ -0,0 +1,7 @@ +%h1.title + %a + GitLab Org + %a.project-item-select-holder.js-projects-dropdown-toggle{href: "/gitlab-org/gitlab-test"} + GitLab Test + %span.fa.fa-chevron-down.dropdown-toggle-caret + %input#project_path.project-item-select.js-projects-dropdown.ajax-project-select{type: "hidden", name: "project_path", "data-include-groups" => "false"} diff --git a/spec/javascripts/fixtures/projects.json b/spec/javascripts/fixtures/projects.json new file mode 100644 index 00000000000..84e8d0ba1e4 --- /dev/null +++ b/spec/javascripts/fixtures/projects.json @@ -0,0 +1 @@ +[{"id":9,"description":"","default_branch":null,"tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:root/test.git","http_url_to_repo":"http://localhost:3000/root/test.git","web_url":"http://localhost:3000/root/test","owner":{"name":"Administrator","username":"root","id":1,"state":"active","avatar_url":"http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon","web_url":"http://localhost:3000/u/root"},"name":"test","name_with_namespace":"Administrator / test","path":"test","path_with_namespace":"root/test","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-14T19:08:05.364Z","last_activity_at":"2016-01-14T19:08:07.418Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":1,"name":"root","path":"root","owner_id":1,"created_at":"2016-01-13T20:19:44.439Z","updated_at":"2016-01-13T20:19:44.439Z","description":"","avatar":null},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":0,"permissions":{"project_access":null,"group_access":null}},{"id":8,"description":"Voluptatem quae nulla eius numquam ullam voluptatibus quia modi.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:h5bp/html5-boilerplate.git","http_url_to_repo":"http://localhost:3000/h5bp/html5-boilerplate.git","web_url":"http://localhost:3000/h5bp/html5-boilerplate","name":"Html5 Boilerplate","name_with_namespace":"H5bp / Html5 Boilerplate","path":"html5-boilerplate","path_with_namespace":"h5bp/html5-boilerplate","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:57.525Z","last_activity_at":"2016-01-13T20:27:57.280Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":5,"name":"H5bp","path":"h5bp","owner_id":null,"created_at":"2016-01-13T20:19:57.239Z","updated_at":"2016-01-13T20:19:57.239Z","description":"Tempore accusantium possimus aut libero.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":{"access_level":10,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":7,"description":"Modi odio mollitia dolorem qui.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:twitter/typeahead-js.git","http_url_to_repo":"http://localhost:3000/twitter/typeahead-js.git","web_url":"http://localhost:3000/twitter/typeahead-js","name":"Typeahead.Js","name_with_namespace":"Twitter / Typeahead.Js","path":"typeahead-js","path_with_namespace":"twitter/typeahead-js","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:56.212Z","last_activity_at":"2016-01-13T20:27:51.496Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":4,"name":"Twitter","path":"twitter","owner_id":null,"created_at":"2016-01-13T20:19:54.480Z","updated_at":"2016-01-13T20:19:54.480Z","description":"Id voluptatem ipsa maiores omnis repudiandae et et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":4,"permissions":{"project_access":null,"group_access":{"access_level":10,"notification_level":3}}},{"id":6,"description":"Omnis asperiores ipsa et beatae quidem necessitatibus quia.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:twitter/flight.git","http_url_to_repo":"http://localhost:3000/twitter/flight.git","web_url":"http://localhost:3000/twitter/flight","name":"Flight","name_with_namespace":"Twitter / Flight","path":"flight","path_with_namespace":"twitter/flight","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:54.754Z","last_activity_at":"2016-01-13T20:27:50.502Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":4,"name":"Twitter","path":"twitter","owner_id":null,"created_at":"2016-01-13T20:19:54.480Z","updated_at":"2016-01-13T20:19:54.480Z","description":"Id voluptatem ipsa maiores omnis repudiandae et et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":4,"permissions":{"project_access":null,"group_access":{"access_level":10,"notification_level":3}}},{"id":5,"description":"Voluptatem commodi voluptate placeat architecto beatae illum dolores fugiat.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-test.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-test.git","web_url":"http://localhost:3000/gitlab-org/gitlab-test","name":"Gitlab Test","name_with_namespace":"Gitlab Org / Gitlab Test","path":"gitlab-test","path_with_namespace":"gitlab-org/gitlab-test","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:53.202Z","last_activity_at":"2016-01-13T20:27:41.626Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}},{"id":4,"description":"Aut molestias quas est ut aperiam officia quod libero.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-shell.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-shell.git","web_url":"http://localhost:3000/gitlab-org/gitlab-shell","name":"Gitlab Shell","name_with_namespace":"Gitlab Org / Gitlab Shell","path":"gitlab-shell","path_with_namespace":"gitlab-org/gitlab-shell","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:51.882Z","last_activity_at":"2016-01-13T20:27:35.678Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":{"access_level":20,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":3,"description":"Excepturi molestiae quia repellendus omnis est illo illum eligendi.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-ci.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-ci.git","web_url":"http://localhost:3000/gitlab-org/gitlab-ci","name":"Gitlab Ci","name_with_namespace":"Gitlab Org / Gitlab Ci","path":"gitlab-ci","path_with_namespace":"gitlab-org/gitlab-ci","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:50.346Z","last_activity_at":"2016-01-13T20:27:30.115Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":3,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}},{"id":2,"description":"Adipisci quaerat dignissimos enim sed ipsam dolorem quia.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":10,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-ce.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-ce.git","web_url":"http://localhost:3000/gitlab-org/gitlab-ce","name":"Gitlab Ce","name_with_namespace":"Gitlab Org / Gitlab Ce","path":"gitlab-ce","path_with_namespace":"gitlab-org/gitlab-ce","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:49.065Z","last_activity_at":"2016-01-13T20:26:58.454Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":{"access_level":30,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":1,"description":"Vel voluptatem maxime saepe ex quia.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:documentcloud/underscore.git","http_url_to_repo":"http://localhost:3000/documentcloud/underscore.git","web_url":"http://localhost:3000/documentcloud/underscore","name":"Underscore","name_with_namespace":"Documentcloud / Underscore","path":"underscore","path_with_namespace":"documentcloud/underscore","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:45.862Z","last_activity_at":"2016-01-13T20:25:03.106Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":2,"name":"Documentcloud","path":"documentcloud","owner_id":null,"created_at":"2016-01-13T20:19:44.464Z","updated_at":"2016-01-13T20:19:44.464Z","description":"Aut impedit perferendis fuga et ipsa repellat cupiditate et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}}] diff --git a/spec/javascripts/project_title_spec.js.coffee b/spec/javascripts/project_title_spec.js.coffee new file mode 100644 index 00000000000..47c7b7febe3 --- /dev/null +++ b/spec/javascripts/project_title_spec.js.coffee @@ -0,0 +1,46 @@ +#= require select2 +#= require api +#= require project_select +#= require project + +window.gon = {} +window.gon.api_version = 'v3' + +describe 'Project Title', -> + fixture.preload('project_title.html') + fixture.preload('projects.json') + + beforeEach -> + fixture.load('project_title.html') + @project = new Project() + + spyOn(@project, 'changeProject').and.callFake (url) -> + window.current_project_url = url + + describe 'project list', -> + beforeEach => + @projects_data = fixture.load('projects.json')[0] + + spyOn(jQuery, 'ajax').and.callFake (req) => + expect(req.url).toBe('/api/v3/projects.json') + d = $.Deferred() + d.resolve @projects_data + d.promise() + + it 'to show on toggle click', => + $('.js-projects-dropdown-toggle').click() + + expect($('.title .select2-container').hasClass('select2-dropdown-open')).toBe(true) + expect($('.ajax-project-dropdown li').length).toBe(@projects_data.length) + + it 'hide dropdown', -> + $("#select2-drop-mask").click() + + expect($('.title .select2-container').hasClass('select2-dropdown-open')).toBe(false) + + it 'change project when clicking item', -> + $('.js-projects-dropdown-toggle').click() + $('.ajax-project-dropdown li:nth-child(2)').trigger('mouseup') + + expect($('.title .select2-container').hasClass('select2-dropdown-open')).toBe(false) + expect(window.current_project_url).toBe('http://localhost:3000/h5bp/html5-boilerplate') -- cgit v1.2.1 From 15bc1a01ab31b4288a3dea429cb7d77d272afbe5 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Sun, 17 Jan 2016 18:12:05 +0000 Subject: added feature test --- spec/features/projects_spec.rb | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index 9a01c89ae2a..ed97b6cb577 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -82,7 +82,26 @@ feature 'Project', feature: true do it 'click project-settings and find leave project' do find('#project-settings-button').click - expect(page).to have_link('Leave Project') + expect(page).to have_link('Leave Project') + end + end + + describe 'project title' do + include WaitForAjax + + let(:user) { create(:user) } + let(:project) { create(:project, namespace: user.namespace) } + + before do + login_with(user) + project.team.add_user(user, Gitlab::Access::MASTER) + visit namespace_project_path(project.namespace, project) + end + + it 'click toggle and show dropdown', js: true do + find('.js-projects-dropdown-toggle').click + wait_for_ajax + expect(page).to have_css('.select2-results li', count: 1) end end -- cgit v1.2.1 From 797bcdf43e19f159492b80ddc635f4bbcf6b41a1 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 31 Jan 2016 15:56:27 -0500 Subject: Add notes about the regression issues to CONTRIBUTING.md [ci skip] --- CONTRIBUTING.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1bd91f0bdce..a6c85e2a6bb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -177,6 +177,26 @@ is probably 1, adding a new Git Hook maybe 4 or 5, big features 7-9. issues or chunks. You can simply not set the weight of a parent issue and set weights to children issues. +### Regression issues + +Every monthly release has a corresponding issue on the CE issue tracker to keep +track of functionality broken by that release and any fixes that need to be +included in a patch release (see [8.3 Regressions] as an example). + +As outlined in the issue description, the intended workflow is to post one note +with a reference to an issue describing the regression, and then to update that +note with a reference to the merge request that fixes it as it becomes available. + +If you're a contributor who doesn't have the required permissions to update +other users' notes, please post a new note with a reference to both the issue +and the merge request. + +The release manager will [update the notes] in the regression issue as fixes are +addressed. + +[8.3 Regressions]: https://gitlab.com/gitlab-org/gitlab-ce/issues/4127 +[update the notes]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc/pro-tips.md#update-the-regression-issue + ## Merge requests We welcome merge requests with fixes and improvements to GitLab code, tests, -- cgit v1.2.1 From 64c8ee47c96d9245081abdf1b9d4ec39cdfc5883 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 1 Feb 2016 10:41:52 +0100 Subject: WIP lazy blobs --- app/controllers/projects/blob_controller.rb | 3 +++ app/models/ci/commit.rb | 6 +++++- app/models/tree.rb | 2 ++ app/views/projects/blob/_blob.html.haml | 1 + lib/api/files.rb | 6 ++++-- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index c56a3497bb2..9045e668735 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -33,6 +33,7 @@ class Projects::BlobController < Projects::ApplicationController def edit @last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha + blob.load_all_data!(@repository) end def update @@ -51,6 +52,7 @@ class Projects::BlobController < Projects::ApplicationController def preview @content = params[:content] + @blob.load_all_data!(@repository) diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true) @diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/)) @@ -65,6 +67,7 @@ class Projects::BlobController < Projects::ApplicationController end def diff + @blob.load_all_data!(@repository) @form = UnfoldForm.new(params) @lines = @blob.data.lines[@form.since - 1..@form.to - 1] diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb index d2a29236942..96786ac4573 100644 --- a/app/models/ci/commit.rb +++ b/app/models/ci/commit.rb @@ -205,7 +205,11 @@ module Ci end def ci_yaml_file - @ci_yaml_file ||= project.repository.blob_at(sha, '.gitlab-ci.yml').data + return @ci_yaml_file if defined?(@ci_yaml_file) + + blob = project.repository.blob_at(sha, '.gitlab-ci.yml') + blob.load_all_data!(project.repository) + @ci_yaml_file = blob.data rescue nil end diff --git a/app/models/tree.rb b/app/models/tree.rb index e0e04d8859f..ecee54c3e0a 100644 --- a/app/models/tree.rb +++ b/app/models/tree.rb @@ -31,6 +31,8 @@ class Tree git_repo = repository.raw_repository @readme = Gitlab::Git::Blob.find(git_repo, sha, readme_path) + @readme.load_all_data!(git_repo) + @readme end def trees diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml index 3d8d88834e2..50aea968980 100644 --- a/app/views/projects/blob/_blob.html.haml +++ b/app/views/projects/blob/_blob.html.haml @@ -35,6 +35,7 @@ - if blob.lfs_pointer? = render "download", blob: blob - elsif blob.text? + - blob.load_all_data!(@repository) = render "text", blob: blob - elsif blob.image? = render "image", blob: blob diff --git a/lib/api/files.rb b/lib/api/files.rb index 8ad2c1883c7..c1d86f313b0 100644 --- a/lib/api/files.rb +++ b/lib/api/files.rb @@ -58,9 +58,11 @@ module API commit = user_project.commit(ref) not_found! 'Commit' unless commit - blob = user_project.repository.blob_at(commit.sha, file_path) + repo = user_project.repository + blob = repo.blob_at(commit.sha, file_path) if blob + blob.load_all_data!(repo) status(200) { @@ -72,7 +74,7 @@ module API ref: ref, blob_id: blob.id, commit_id: commit.id, - last_commit_id: user_project.repository.last_commit_for_path(commit.sha, file_path).id + last_commit_id: repo.last_commit_for_path(commit.sha, file_path).id } else not_found! 'File' -- cgit v1.2.1 From 02afa6793cca042f8563b0e26472606c743d76f5 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 1 Feb 2016 11:33:22 +0100 Subject: Use only one header to send git blobs --- app/controllers/projects/avatars_controller.rb | 3 +-- app/controllers/projects/raw_controller.rb | 3 +-- lib/api/repositories.rb | 6 ++---- lib/gitlab/workhorse.rb | 21 +++++++++++++++++++++ 4 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 lib/gitlab/workhorse.rb diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb index 0cd65ad5b16..eb501c3964c 100644 --- a/app/controllers/projects/avatars_controller.rb +++ b/app/controllers/projects/avatars_controller.rb @@ -6,8 +6,7 @@ class Projects::AvatarsController < Projects::ApplicationController @blob = repository.blob_at_branch('master', @project.avatar_in_git) if @blob headers['X-Content-Type-Options'] = 'nosniff' - headers['Gitlab-Workhorse-Repo-Path'] = repository.path_to_repo - headers['Gitlab-Workhorse-Send-Blob'] = @blob.id + headers.store(*Gitlab::Workhorse.send_git_blob(repository, @blob)) headers['Content-Disposition'] = 'inline' render nothing: true, content_type: @blob.content_type else diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index b8b90489027..2ab8a6b83bb 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -15,8 +15,7 @@ class Projects::RawController < Projects::ApplicationController if @blob.lfs_pointer? send_lfs_object else - headers['Gitlab-Workhorse-Repo-Path'] = @repository.path_to_repo - headers['Gitlab-Workhorse-Send-Blob'] = @blob.id + headers.store(*Gitlab::Workhorse.send_git_blob(@repository, @blob)) headers['Content-Disposition'] = 'inline' render nothing: true, content_type: get_blob_type end diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index 0f4cd2443b0..c95d2d2001d 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -57,8 +57,7 @@ module API not_found! "File" unless blob content_type 'text/plain' - header 'Gitlab-Workhorse-Repo-Path', repo.path_to_repo - header 'Gitlab-Workhorse-Send-Blob', blob.id + header *Gitlab::Workhorse.send_git_blob(repo, blob) end # Get a raw blob contents by blob sha @@ -84,8 +83,7 @@ module API env['api.format'] = :txt content_type blob.mime_type - header 'Gitlab-Workhorse-Repo-Path', repo.path_to_repo - header 'Gitlab-Workhorse-Send-Blob', blob.id + header *Gitlab::Workhorse.send_git_blob(repo, blob) end # Get a an archive of the repository diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb new file mode 100644 index 00000000000..ff6fbf0b5c1 --- /dev/null +++ b/lib/gitlab/workhorse.rb @@ -0,0 +1,21 @@ +require 'base64' +require 'json' + +module Gitlab + class Workhorse + class << self + def send_git_blob(repository, blob) + params_hash = { + 'RepoPath' => repository.path_to_repo, + 'BlobId' => blob.id, + } + params = Base64.urlsafe_encode64(JSON.dump(params_hash)) + + [ + 'Gitlab-Workhorse-Send-Data', + "git-blob:#{params}", + ] + end + end + end +end \ No newline at end of file -- cgit v1.2.1 From b2a634c352ab23ed1180b7678b5c83db0137c0f7 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 1 Feb 2016 12:01:13 +0100 Subject: Avoid trailing 'charset=' garbage --- app/controllers/projects/avatars_controller.rb | 3 ++- app/controllers/projects/raw_controller.rb | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb index eb501c3964c..bc40e601030 100644 --- a/app/controllers/projects/avatars_controller.rb +++ b/app/controllers/projects/avatars_controller.rb @@ -8,7 +8,8 @@ class Projects::AvatarsController < Projects::ApplicationController headers['X-Content-Type-Options'] = 'nosniff' headers.store(*Gitlab::Workhorse.send_git_blob(repository, @blob)) headers['Content-Disposition'] = 'inline' - render nothing: true, content_type: @blob.content_type + headers['Content-Type'] = @blob.content_type + head :ok # 'render nothing: true' messes up the Content-Type else render_404 end diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index 2ab8a6b83bb..87b4d08da0e 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -17,7 +17,8 @@ class Projects::RawController < Projects::ApplicationController else headers.store(*Gitlab::Workhorse.send_git_blob(@repository, @blob)) headers['Content-Disposition'] = 'inline' - render nothing: true, content_type: get_blob_type + headers['Content-Type'] = get_blob_type + head :ok # 'render nothing: true' messes up the Content-Type end else render_404 -- cgit v1.2.1 From b1f22aa35aa62d72f514b3f9beee0a190b6599cc Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 1 Feb 2016 12:27:35 +0100 Subject: Gotta have newlines --- lib/gitlab/workhorse.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index ff6fbf0b5c1..a23120a4176 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -18,4 +18,4 @@ module Gitlab end end end -end \ No newline at end of file +end -- cgit v1.2.1 From 1256dabb445211fe48f1d53cc5be15ad99793178 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 1 Feb 2016 13:54:39 +0100 Subject: Instrument all Gitlab::Git instance methods --- config/initializers/metrics.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/initializers/metrics.rb b/config/initializers/metrics.rb index 0945b93ed5d..e69552631ff 100644 --- a/config/initializers/metrics.rb +++ b/config/initializers/metrics.rb @@ -49,12 +49,14 @@ if Gitlab::Metrics.enabled? config.instrument_instance_methods(Gitlab::Shell) config.instrument_methods(Gitlab::Git) - config.instrument_instance_methods(Gitlab::Git::Repository) Gitlab::Git.constants.each do |name| const = Gitlab::Git.const_get(name) - config.instrument_methods(const) if const.is_a?(Module) + next unless const.is_a?(Module) + + config.instrument_methods(const) + config.instrument_instance_methods(const) end Dir[Rails.root.join('app', 'finders', '*.rb')].each do |path| -- cgit v1.2.1 From d11d425acc6b6aeaf85113dc9b2aca89b36dfe78 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 1 Feb 2016 14:00:28 +0100 Subject: Develop with a custom gitlab_git branch --- Gemfile | 2 +- Gemfile.lock | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Gemfile b/Gemfile index a09d44f8bfd..88236146a14 100644 --- a/Gemfile +++ b/Gemfile @@ -49,7 +49,7 @@ gem "browser", '~> 1.0.0' # Extracting information from a git repository # Provide access to Gitlab::Git library -gem "gitlab_git", '~> 7.2.23' +gem "gitlab_git", git: 'https://gitlab.com/gitlab-org/gitlab_git.git', branch: 'lazy-blob' # LDAP Auth # GitLab fork with several improvements to original library. For full list of changes diff --git a/Gemfile.lock b/Gemfile.lock index ec92964df25..d6a5fe9dd0e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,14 @@ +GIT + remote: https://gitlab.com/gitlab-org/gitlab_git.git + revision: dbf224a5d0404ab094e53144b5e01a88b5e9dbaa + branch: lazy-blob + specs: + gitlab_git (7.2.24) + activesupport (~> 4.0) + charlock_holmes (~> 0.7.3) + github-linguist (~> 4.7.0) + rugged (~> 0.23.3) + GEM remote: https://rubygems.org/ specs: @@ -356,11 +367,6 @@ GEM posix-spawn (~> 0.3) gitlab_emoji (0.2.0) gemojione (~> 2.1) - gitlab_git (7.2.24) - activesupport (~> 4.0) - charlock_holmes (~> 0.7.3) - github-linguist (~> 4.7.0) - rugged (~> 0.23.3) gitlab_meta (7.0) gitlab_omniauth-ldap (1.2.1) net-ldap (~> 0.9) @@ -934,7 +940,7 @@ DEPENDENCIES github-markup (~> 1.3.1) gitlab-flowdock-git-hook (~> 1.0.1) gitlab_emoji (~> 0.2.0) - gitlab_git (~> 7.2.23) + gitlab_git! gitlab_meta (= 7.0) gitlab_omniauth-ldap (~> 1.2.1) gollum-lib (~> 4.1.0) -- cgit v1.2.1 From 29d376025dbca5512a3d8204b262bfb576384b6c Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 1 Feb 2016 14:34:22 +0100 Subject: Update gitlab_git (lazy-blob branch) --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index d6a5fe9dd0e..2c63cca6111 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: https://gitlab.com/gitlab-org/gitlab_git.git - revision: dbf224a5d0404ab094e53144b5e01a88b5e9dbaa + revision: 170a36889aebfd43e3e1e20b6b7661c896816b41 branch: lazy-blob specs: gitlab_git (7.2.24) @@ -350,7 +350,7 @@ GEM json get_process_mem (0.2.0) gherkin-ruby (0.3.2) - github-linguist (4.7.3) + github-linguist (4.7.4) charlock_holmes (~> 0.7.3) escape_utils (~> 1.1.0) mime-types (>= 1.19) -- cgit v1.2.1 From b1a7cb57cd695f1348e38710007f1676e95cce8c Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 1 Feb 2016 14:41:35 +0100 Subject: Update gitlab_git@lazy-blob again --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2c63cca6111..9473e918632 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: https://gitlab.com/gitlab-org/gitlab_git.git - revision: 170a36889aebfd43e3e1e20b6b7661c896816b41 + revision: 69f2185b8bfc8c54b70a1ce4c8c81d9b9a977ce6 branch: lazy-blob specs: gitlab_git (7.2.24) -- cgit v1.2.1 From 33fb55a572364feca70fcc0f15b80da6176f4d71 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 1 Feb 2016 15:03:58 +0100 Subject: Instrument various Rugged constants --- config/initializers/metrics.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/config/initializers/metrics.rb b/config/initializers/metrics.rb index e69552631ff..3e1deb8d306 100644 --- a/config/initializers/metrics.rb +++ b/config/initializers/metrics.rb @@ -64,6 +64,16 @@ if Gitlab::Metrics.enabled? config.instrument_instance_methods(const) end + + [ + :Blame, :Branch, :BranchCollection, :Blob, :Commit, :Diff, :Repository, + :Tag, :TagCollection, :Tree + ].each do |name| + const = Rugged.const_get(name) + + config.instrument_methods(const) + config.instrument_instance_methods(const) + end end GC::Profiler.enable -- cgit v1.2.1 From b4e6ee7adc5ad4cb4ab42c5b691684885e2562f1 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 1 Feb 2016 15:19:55 +0100 Subject: Update development version of gitlab_git --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9473e918632..9aacbced998 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: https://gitlab.com/gitlab-org/gitlab_git.git - revision: 69f2185b8bfc8c54b70a1ce4c8c81d9b9a977ce6 + revision: 57160e1cbcf4c03e68aa881dfa8e2f55c37a3ee6 branch: lazy-blob specs: gitlab_git (7.2.24) -- cgit v1.2.1 From 72bd004b3114fad43feaa7d21e0c2cde4b5b6a0d Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 1 Feb 2016 16:20:49 +0100 Subject: Allow "@" in file names and path --- lib/gitlab/regex.rb | 8 ++++---- spec/lib/gitlab/regex_spec.rb | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index 53ab2686b43..5c35c5b1450 100644 --- a/lib/gitlab/regex.rb +++ b/lib/gitlab/regex.rb @@ -44,19 +44,19 @@ module Gitlab def file_name_regex - @file_name_regex ||= /\A[a-zA-Z0-9_\-\.]*\z/.freeze + @file_name_regex ||= /\A[a-zA-Z0-9_\-\.\@]*\z/.freeze end def file_name_regex_message - "can contain only letters, digits, '_', '-' and '.'. " + "can contain only letters, digits, '_', '-', '@' and '.'. " end def file_path_regex - @file_path_regex ||= /\A[a-zA-Z0-9_\-\.\/]*\z/.freeze + @file_path_regex ||= /\A[a-zA-Z0-9_\-\.\/\@]*\z/.freeze end def file_path_regex_message - "can contain only letters, digits, '_', '-' and '.'. Separate directories with a '/'. " + "can contain only letters, digits, '_', '-', '@' and '.'. Separate directories with a '/'. " end diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb index d67ee423b9b..c51b10bdc69 100644 --- a/spec/lib/gitlab/regex_spec.rb +++ b/spec/lib/gitlab/regex_spec.rb @@ -21,4 +21,12 @@ describe Gitlab::Regex, lib: true do it { expect('Dash – is this').to match(Gitlab::Regex.project_name_regex) } it { expect('?gitlab').not_to match(Gitlab::Regex.project_name_regex) } end + + describe 'file name regex' do + it { expect('foo@bar').to match(Gitlab::Regex.file_name_regex) } + end + + describe 'file path regex' do + it { expect('foo@/bar').to match(Gitlab::Regex.file_path_regex) } + end end -- cgit v1.2.1 From e6cb010088c92a4c26fd2ac201944327369e7803 Mon Sep 17 00:00:00 2001 From: Aral Balkan Date: Sat, 25 Jul 2015 10:39:49 +0000 Subject: Added note: working copy changes (e.g., deleted vendor folder) should be stashed before beginning the update process. We should probably include this notice on all update guides. [ci skip] --- doc/update/6.x-or-7.x-to-7.14.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/update/6.x-or-7.x-to-7.14.md b/doc/update/6.x-or-7.x-to-7.14.md index 4516a102084..c45fc9340ea 100644 --- a/doc/update/6.x-or-7.x-to-7.14.md +++ b/doc/update/6.x-or-7.x-to-7.14.md @@ -14,6 +14,12 @@ possible to edit the label text and color. The characters `?`, `&` and `,` are no longer allowed however so those will be removed from your tags during the database migrations for GitLab 7.2. +## Stash changes + +If you [deleted the vendors folder during your original installation](https://github.com/gitlabhq/gitlabhq/issues/4883#issuecomment-31108431), [you will get an error](https://gitlab.com/gitlab-org/gitlab-ce/issues/1494) when you attempt to rebuild the assets in step 7. To avoid this, stash the changes in your GitLab working copy before starting: + + git stash + ## 0. Stop server sudo service gitlab stop -- cgit v1.2.1 From 06c0025f16480fce831362317ed6427d51ab3c64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 1 Feb 2016 19:10:25 +0100 Subject: Improving the "Environment variables" administration doc --- config/database.yml.env | 12 +++++- doc/administration/environment_variables.md | 60 ++++++++++++++--------------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/config/database.yml.env b/config/database.yml.env index b2ff23cb5ab..1e35651c9a6 100644 --- a/config/database.yml.env +++ b/config/database.yml.env @@ -1,9 +1,17 @@ <%= ENV['RAILS_ENV'] %>: + ## Connection information + # Please be aware that the DATABASE_URL environment variable will take + # precedence over the following 6 parameters. For more information, see + # doc/administration/environment_variables.md adapter: <%= ENV['GITLAB_DATABASE_ADAPTER'] || 'postgresql' %> - encoding: <%= ENV['GITLAB_DATABASE_ENCODING'] || 'unicode' %> database: <%= ENV['GITLAB_DATABASE_DATABASE'] || "gitlab_#{ENV['RAILS_ENV']}" %> - pool: <%= ENV['GITLAB_DATABASE_POOL'] || '10' %> username: <%= ENV['GITLAB_DATABASE_USERNAME'] || 'root' %> password: <%= ENV['GITLAB_DATABASE_PASSWORD'] || '' %> host: <%= ENV['GITLAB_DATABASE_HOST'] || 'localhost' %> port: <%= ENV['GITLAB_DATABASE_PORT'] || '5432' %> + + ## Behavior information + # The following parameters will be used even if you're using the DATABASE_URL + # environment variable. + encoding: <%= ENV['GITLAB_DATABASE_ENCODING'] || 'unicode' %> + pool: <%= ENV['GITLAB_DATABASE_POOL'] || '10' %> diff --git a/doc/administration/environment_variables.md b/doc/administration/environment_variables.md index 0faef526d43..b0aa420e055 100644 --- a/doc/administration/environment_variables.md +++ b/doc/administration/environment_variables.md @@ -2,7 +2,7 @@ ## Introduction -Commonly people configure GitLab via the gitlab.rb configuration file in the Omnibus package. +Commonly people configure GitLab via the `gitlab.rb` configuration file in the Omnibus package. But if you prefer to use environment variables we allow that too. @@ -10,45 +10,45 @@ But if you prefer to use environment variables we allow that too. Variable | Type | Explanation -------- | ---- | ----------- -GITLAB_ROOT_PASSWORD | string | sets the password for the `root` user on installation -GITLAB_HOST | url | hostname of the GitLab server includes http or https -RAILS_ENV | production / development / staging / test | Rails environment -DATABASE_URL | url | For example: postgresql://localhost/blog_development?pool=5 -GITLAB_EMAIL_FROM | email | Email address used in the "From" field in mails sent by GitLab -GITLAB_EMAIL_DISPLAY_NAME | string | Name used in the "From" field in mails sent by GitLab -GITLAB_EMAIL_REPLY_TO | email | Email address used in the "Reply-To" field in mails sent by GitLab -GITLAB_UNICORN_MEMORY_MIN | integer | The minimum memory threshold (in bytes) for the Unicorn worker killer -GITLAB_UNICORN_MEMORY_MAX | integer | The maximum memory threshold (in bytes) for the Unicorn worker killer +`GITLAB_ROOT_PASSWORD` | string | Sets the password for the `root` user on installation +`GITLAB_HOST` | url | Hostname of the GitLab server includes http or https +`RAILS_ENV` | production / development / staging / test | Rails environment +`DATABASE_URL` | url | For example: postgresql://localhost/blog_development +`GITLAB_EMAIL_FROM` | email | Email address used in the "From" field in mails sent by GitLab +`GITLAB_EMAIL_DISPLAY_NAME` | string | Name used in the "From" field in mails sent by GitLab +`GITLAB_EMAIL_REPLY_TO` | email | Email address used in the "Reply-To" field in mails sent by GitLab +`GITLAB_UNICORN_MEMORY_MIN` | integer | The minimum memory threshold (in bytes) for the Unicorn worker killer +`GITLAB_UNICORN_MEMORY_MAX` | integer | The maximum memory threshold (in bytes) for the Unicorn worker killer ## Complete database variables -As explained in the [Heroku documentation](https://devcenter.heroku.com/articles/rails-database-connection-behavior) the DATABASE_URL doesn't let you set: +The recommended way of specifying your database connection information is to set +the `DATABASE_URL` environment variable. This variable only holds connection +information (adapter, database, username, password, host and port), but not +behavior information (encoding, pool). If you don't want to use `DATABASE_URL` +and/or want to set database behavior information, you will have to: -- adapter -- database -- username -- password -- host -- port +- copy our template `config/database.yml` file: `cp config/database.yml.env config/database.yml` +- set a value for some `GITLAB_DATABASE_XXX` variables -To do so please `cp config/database.yml.env config/database.yml` and use the following variables: +The list of `GITLAB_DATABASE_XXX` variables that you can set is as follow: -Variable | Default ---- | --- -GITLAB_DATABASE_ADAPTER | postgresql -GITLAB_DATABASE_ENCODING | unicode -GITLAB_DATABASE_DATABASE | gitlab_#{ENV['RAILS_ENV'] -GITLAB_DATABASE_POOL | 10 -GITLAB_DATABASE_USERNAME | root -GITLAB_DATABASE_PASSWORD | -GITLAB_DATABASE_HOST | localhost -GITLAB_DATABASE_PORT | 5432 +Variable | Default value | Overridden by `DATABASE_URL`? +--- | --- | --- +`GITLAB_DATABASE_ADAPTER` | `postgresql` | Yes +`GITLAB_DATABASE_DATABASE` | `gitlab_#{ENV['RAILS_ENV']` | Yes +`GITLAB_DATABASE_USERNAME` | `root` | Yes +`GITLAB_DATABASE_PASSWORD` | None | Yes +`GITLAB_DATABASE_HOST` | `localhost` | Yes +`GITLAB_DATABASE_PORT` | `5432` | Yes +`GITLAB_DATABASE_ENCODING` | `unicode` | No +`GITLAB_DATABASE_POOL` | `10` | No ## Adding more variables We welcome merge requests to make more settings configurable via variables. -Please make changes in the file config/initializers/1_settings.rb -Please stick to the naming scheme "GITLAB_#{name 1_settings.rb in upper case}". +Please make changes in the `config/initializers/1_settings.rb` file. +Please stick to the naming scheme `GITLAB_#{name in 1_settings.rb in upper case}`. ## Omnibus configuration -- cgit v1.2.1 From 9dfc4511ff1b8029ce8ad4e6c94bc0f39164b02d Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 28 Jan 2016 11:49:41 +0100 Subject: Updated contributing guide for stable releases Fixes #12784 --- CONTRIBUTING.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e7659b06c71..4130c57d472 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -257,6 +257,18 @@ 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 guidelines](https://github.com/thoughtbot/guides/tree/master/code-review) into account. +## Changes for Stable Releases + +Sometimes certain changes have to be added to an existing stable release. +Two examples are bug fixes and performance improvements. In these cases the +corresponding merge request should be updated to have the following: + +1. A milestone indicating what release the merge request should be merged into. +1. The label "Pick into Stable" + +This makes it easier for release managers to keep track of what still has to be +merged and where changes have to be merged into. + ## Definition of done If you contribute to GitLab please know that changes involve more than just -- cgit v1.2.1 From 7eb961f0816fd8be628162ca58a5377aae7ac165 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Tue, 2 Feb 2016 11:17:20 +0100 Subject: Improve tooltips on admin menu --- app/views/layouts/nav/_admin.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml index cffdb52cc23..62e6fba5e34 100644 --- a/app/views/layouts/nav/_admin.html.haml +++ b/app/views/layouts/nav/_admin.html.haml @@ -1,6 +1,6 @@ %ul.nav.nav-sidebar = nav_link(controller: :dashboard, html_options: {class: 'home'}) do - = link_to admin_root_path, title: "Stats" do + = link_to admin_root_path, title: 'Overview' do = icon('dashboard fw') %span Overview @@ -25,13 +25,13 @@ %span Deploy Keys = nav_link path: ['runners#index', 'runners#show'] do - = link_to admin_runners_path do + = link_to admin_runners_path, title: 'Runners' do = icon('cog fw') %span Runners %span.count= number_with_delimiter(Ci::Runner.count(:all)) = nav_link path: 'builds#index' do - = link_to admin_builds_path do + = link_to admin_builds_path, title: 'Builds' do = icon('link fw') %span Builds -- cgit v1.2.1 From c76e6b982bb171f24592b62264b28eb3fbe1bafc Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 2 Feb 2016 14:17:08 +0100 Subject: Move load command into _text partial --- app/views/projects/blob/_blob.html.haml | 1 - app/views/projects/blob/_text.html.haml | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml index 50aea968980..3d8d88834e2 100644 --- a/app/views/projects/blob/_blob.html.haml +++ b/app/views/projects/blob/_blob.html.haml @@ -35,7 +35,6 @@ - if blob.lfs_pointer? = render "download", blob: blob - elsif blob.text? - - blob.load_all_data!(@repository) = render "text", blob: blob - elsif blob.image? = render "image", blob: blob diff --git a/app/views/projects/blob/_text.html.haml b/app/views/projects/blob/_text.html.haml index 906e5ccb360..d09cd73558c 100644 --- a/app/views/projects/blob/_text.html.haml +++ b/app/views/projects/blob/_text.html.haml @@ -1,3 +1,4 @@ +- blob.load_all_data!(@repository) - if markup?(blob.name) .file-content.wiki = render_markup(blob.name, blob.data) -- cgit v1.2.1 From d20e75a8d80c2828336cd22897ea6868d666f8a5 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sat, 9 Jan 2016 19:30:34 +0000 Subject: Support Akismet spam checking for creation of issues via API Currently any spam detected by Akismet by non-members via API will be logged in a separate table in the admin page. Closes #5612 --- CHANGELOG | 1 + Gemfile | 3 +- Gemfile.lock | 2 + .../admin/application_settings_controller.rb | 2 + app/controllers/admin/spam_logs_controller.rb | 33 +++++++++++++++ app/models/application_setting.rb | 8 +++- app/models/spam_log.rb | 13 ++++++ app/models/spam_report.rb | 5 +++ app/models/user.rb | 1 + app/services/create_spam_log_service.rb | 13 ++++++ .../admin/application_settings/_form.html.haml | 23 ++++++++-- app/views/admin/spam_logs/_spam_log.html.haml | 30 +++++++++++++ app/views/admin/spam_logs/index.html.haml | 21 +++++++++ app/views/layouts/nav/_admin.html.haml | 7 +++ config/routes.rb | 2 + ...31152326_add_akismet_to_application_settings.rb | 8 ++++ db/migrate/20160109054846_create_spam_logs.rb | 16 +++++++ db/schema.rb | 15 +++++++ doc/integration/README.md | 1 + doc/integration/akismet.md | 30 +++++++++++++ doc/integration/img/akismet_settings.png | Bin 0 -> 55837 bytes features/admin/spam_logs.feature | 8 ++++ features/steps/admin/spam_logs.rb | 18 ++++++++ features/steps/shared/paths.rb | 4 ++ lib/api/issues.rb | 22 +++++++++- lib/gitlab/akismet_helper.rb | 39 +++++++++++++++++ lib/gitlab/current_settings.rb | 3 +- .../controllers/admin/spam_logs_controller_spec.rb | 47 +++++++++++++++++++++ spec/factories/spam_logs.rb | 7 +++ spec/lib/gitlab/akismet_helper_spec.rb | 35 +++++++++++++++ spec/requests/api/issues_spec.rb | 22 ++++++++++ 31 files changed, 432 insertions(+), 7 deletions(-) create mode 100644 app/controllers/admin/spam_logs_controller.rb create mode 100644 app/models/spam_log.rb create mode 100644 app/models/spam_report.rb create mode 100644 app/services/create_spam_log_service.rb create mode 100644 app/views/admin/spam_logs/_spam_log.html.haml create mode 100644 app/views/admin/spam_logs/index.html.haml create mode 100644 db/migrate/20151231152326_add_akismet_to_application_settings.rb create mode 100644 db/migrate/20160109054846_create_spam_logs.rb create mode 100644 doc/integration/akismet.md create mode 100644 doc/integration/img/akismet_settings.png create mode 100644 features/admin/spam_logs.feature create mode 100644 features/steps/admin/spam_logs.rb create mode 100644 lib/gitlab/akismet_helper.rb create mode 100644 spec/controllers/admin/spam_logs_controller_spec.rb create mode 100644 spec/factories/spam_logs.rb create mode 100644 spec/lib/gitlab/akismet_helper_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 7a70516173c..1be1f7374df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -74,6 +74,7 @@ v 8.4.0 - Don't notify users twice if they are both project watchers and subscribers (Stan Hu) - Remove gray background from layout in UI - Fix signup for OAuth providers that don't provide a name + - Support Akismet spam checking for creation of issues via API (Stan Hu) - Implement new UI for group page - Implement search inside emoji picker - Let the CI runner know about builds that this build depends on diff --git a/Gemfile b/Gemfile index c9d428a1798..9f012e1a7e5 100644 --- a/Gemfile +++ b/Gemfile @@ -36,8 +36,9 @@ gem 'omniauth-twitter', '~> 1.2.0' gem 'omniauth_crowd', '~> 2.2.0' gem 'rack-oauth2', '~> 1.2.1' -# reCAPTCHA protection +# Spam and anti-bot protection gem 'recaptcha', require: 'recaptcha/rails' +gem 'akismet', '~> 2.0' # Two-factor authentication gem 'devise-two-factor', '~> 2.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index b4f7587c419..9570d387f68 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -49,6 +49,7 @@ GEM addressable (2.3.8) after_commit_queue (1.3.0) activerecord (>= 3.0) + akismet (2.0.0) allocations (1.0.3) annotate (2.6.10) activerecord (>= 3.2, <= 4.3) @@ -884,6 +885,7 @@ DEPENDENCIES acts-as-taggable-on (~> 3.4) addressable (~> 2.3.8) after_commit_queue + akismet (~> 2.0) allocations (~> 1.0) annotate (~> 2.6.0) asana (~> 0.4.0) diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 9943745208e..1515086b16d 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -79,6 +79,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :recaptcha_private_key, :sentry_enabled, :sentry_dsn, + :akismet_enabled, + :akismet_api_key, restricted_visibility_levels: [], import_sources: [] ) diff --git a/app/controllers/admin/spam_logs_controller.rb b/app/controllers/admin/spam_logs_controller.rb new file mode 100644 index 00000000000..69f94dd3ba8 --- /dev/null +++ b/app/controllers/admin/spam_logs_controller.rb @@ -0,0 +1,33 @@ +class Admin::SpamLogsController < Admin::ApplicationController + before_action :set_spam_log, only: [:destroy] + + def index + @spam_logs = SpamLog.order(created_at: :desc).page(params[:page]) + end + + def destroy + @spam_log.destroy + message = 'Spam log was successfully destroyed.' + + if params[:remove_user] + username = @spam_log.user.username + @spam_log.user.destroy + message = "User #{username} was successfully destroyed." + end + + respond_to do |format| + format.json { render json: '{}' } + format.html { redirect_to admin_spam_logs_path, notice: message } + end + end + + private + + def set_spam_log + @spam_log = SpamLog.find(params[:id]) + end + + def spam_log_params + params[:spam_log] + end +end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 59563b8823c..9cafc78f761 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -88,6 +88,10 @@ class ApplicationSetting < ActiveRecord::Base presence: true, if: :sentry_enabled + validates :akismet_api_key, + presence: true, + if: :akismet_enabled + validates_each :restricted_visibility_levels do |record, attr, value| unless value.nil? value.each do |level| @@ -143,7 +147,9 @@ class ApplicationSetting < ActiveRecord::Base shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'], max_artifacts_size: Settings.artifacts['max_size'], require_two_factor_authentication: false, - two_factor_grace_period: 48 + two_factor_grace_period: 48, + recaptcha_enabled: false, + akismet_enabled: false ) end diff --git a/app/models/spam_log.rb b/app/models/spam_log.rb new file mode 100644 index 00000000000..132c5713e0a --- /dev/null +++ b/app/models/spam_log.rb @@ -0,0 +1,13 @@ +class SpamLog < ActiveRecord::Base + belongs_to :user + + validates :user, presence: true + + def truncated_description + if description.present? && description.length > 100 + return description[0..100] + "..." + end + + description + end +end diff --git a/app/models/spam_report.rb b/app/models/spam_report.rb new file mode 100644 index 00000000000..cdc7321b08e --- /dev/null +++ b/app/models/spam_report.rb @@ -0,0 +1,5 @@ +class SpamReport < ActiveRecord::Base + belongs_to :user + + validates :user, presence: true +end diff --git a/app/models/user.rb b/app/models/user.rb index 4214f01f6a4..63c895683f7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -138,6 +138,7 @@ class User < ActiveRecord::Base has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest" has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy has_one :abuse_report, dependent: :destroy + has_many :spam_log, dependent: :destroy has_many :builds, dependent: :nullify, class_name: 'Ci::Build' diff --git a/app/services/create_spam_log_service.rb b/app/services/create_spam_log_service.rb new file mode 100644 index 00000000000..59a66fde47a --- /dev/null +++ b/app/services/create_spam_log_service.rb @@ -0,0 +1,13 @@ +class CreateSpamLogService < BaseService + def initialize(project, user, params) + super(project, user, params) + end + + def execute + spam_params = params.merge({ user_id: @current_user.id, + project_id: @project.id } ) + spam_log = SpamLog.new(spam_params) + spam_log.save + spam_log + end +end diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index b0f1a34cbec..b4e3d96d405 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -218,20 +218,37 @@ = f.label :recaptcha_enabled do = f.check_box :recaptcha_enabled Enable reCAPTCHA - %span.help-block#recaptcha_help_block Helps preventing bots from creating accounts + %span.help-block#recaptcha_help_block Helps prevent bots from creating accounts .form-group = f.label :recaptcha_site_key, 'reCAPTCHA Site Key', class: 'control-label col-sm-2' .col-sm-10 = f.text_field :recaptcha_site_key, class: 'form-control' .help-block - Generate site and private keys here: - %a{ href: 'http://www.google.com/recaptcha', target: '_blank'} http://www.google.com/recaptcha + Generate site and private keys at + %a{ href: 'http://www.google.com/recaptcha', target: 'blank'} http://www.google.com/recaptcha + .form-group = f.label :recaptcha_private_key, 'reCAPTCHA Private Key', class: 'control-label col-sm-2' .col-sm-10 = f.text_field :recaptcha_private_key, class: 'form-control' + .form-group + .col-sm-offset-2.col-sm-10 + .checkbox + = f.label :akismet_enabled do + = f.check_box :akismet_enabled + Enable Akismet + %span.help-block#akismet_help_block Helps prevent bots from creating issues + + .form-group + = f.label :akismet_api_key, 'Akismet API Key', class: 'control-label col-sm-2' + .col-sm-10 + = f.text_field :akismet_api_key, class: 'form-control' + .help-block + Generate API key at + %a{ href: 'http://www.akismet.com', target: 'blank'} http://www.akismet.com + %fieldset %legend Error Reporting and Logging %p diff --git a/app/views/admin/spam_logs/_spam_log.html.haml b/app/views/admin/spam_logs/_spam_log.html.haml new file mode 100644 index 00000000000..1c793bbf738 --- /dev/null +++ b/app/views/admin/spam_logs/_spam_log.html.haml @@ -0,0 +1,30 @@ +- user = spam_log.user +%tr + %td + = spam_log.created_at.to_s(:short) + %td + - if user + = link_to user.name, user + - else + (removed) + %td + = spam_log.source_ip + %td + = spam_log.via_api ? 'Y' : 'N' + %td + = spam_log.noteable_type + %td + = spam_log.title + %td + = spam_log.truncated_description + %td + - if user + = link_to 'Remove user', admin_spam_log_path(spam_log, remove_user: true), + data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" }, method: :delete, class: "btn btn-xs btn-remove" + %td + - if user && !user.blocked? + = link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs" + - else + .btn.btn-xs.disabled + Already Blocked + = link_to 'Remove log', [:admin, spam_log, format: :json], remote: true, method: :delete, class: "btn btn-xs btn-close js-remove-tr" diff --git a/app/views/admin/spam_logs/index.html.haml b/app/views/admin/spam_logs/index.html.haml new file mode 100644 index 00000000000..439468e572b --- /dev/null +++ b/app/views/admin/spam_logs/index.html.haml @@ -0,0 +1,21 @@ +- page_title "Spam Logs" +%h3.page-title Spam Logs +%hr +- if @spam_logs.present? + .table-holder + %table.table + %thead + %tr + %th Date + %th User + %th Source IP + %th Via API? + %th Type + %th Title + %th Description + %th Primary Action + %th + = render @spam_logs + = paginate @spam_logs +- else + %h4 There are no Spam Logs diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml index cffdb52cc23..8dc20587421 100644 --- a/app/views/layouts/nav/_admin.html.haml +++ b/app/views/layouts/nav/_admin.html.haml @@ -82,6 +82,13 @@ Abuse Reports %span.count= number_with_delimiter(AbuseReport.count(:all)) + = nav_link(controller: :spam_logs) do + = link_to admin_spam_logs_path, title: "Spam Logs" do + = icon('exclamation-triangle fw') + %span + Spam Logs + %span.count= number_with_delimiter(SpamLog.count(:all)) + = nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do = link_to admin_application_settings_path, title: 'Settings' do = icon('cogs fw') diff --git a/config/routes.rb b/config/routes.rb index 54cc338b605..034bfaf1bcd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -211,6 +211,8 @@ Rails.application.routes.draw do end resources :abuse_reports, only: [:index, :destroy] + resources :spam_logs, only: [:index, :destroy] + resources :applications resources :groups, constraints: { id: /[^\/]+/ } do diff --git a/db/migrate/20151231152326_add_akismet_to_application_settings.rb b/db/migrate/20151231152326_add_akismet_to_application_settings.rb new file mode 100644 index 00000000000..3f52c758f9a --- /dev/null +++ b/db/migrate/20151231152326_add_akismet_to_application_settings.rb @@ -0,0 +1,8 @@ +class AddAkismetToApplicationSettings < ActiveRecord::Migration + def change + change_table :application_settings do |t| + t.boolean :akismet_enabled, default: false + t.string :akismet_api_key + end + end +end diff --git a/db/migrate/20160109054846_create_spam_logs.rb b/db/migrate/20160109054846_create_spam_logs.rb new file mode 100644 index 00000000000..f12fe9f8f78 --- /dev/null +++ b/db/migrate/20160109054846_create_spam_logs.rb @@ -0,0 +1,16 @@ +class CreateSpamLogs < ActiveRecord::Migration + def change + create_table :spam_logs do |t| + t.integer :user_id + t.string :source_ip + t.string :user_agent + t.boolean :via_api + t.integer :project_id + t.string :noteable_type + t.string :title + t.text :description + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 2ad2c23fba5..d546e06cd8a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -64,6 +64,8 @@ ActiveRecord::Schema.define(version: 20160128233227) do t.integer "metrics_sample_interval", default: 15 t.boolean "sentry_enabled", default: false t.string "sentry_dsn" + t.boolean "akismet_enabled", default: false + t.string "akismet_api_key" end create_table "audit_events", force: :cascade do |t| @@ -770,6 +772,19 @@ ActiveRecord::Schema.define(version: 20160128233227) do add_index "snippets", ["project_id"], name: "index_snippets_on_project_id", using: :btree add_index "snippets", ["visibility_level"], name: "index_snippets_on_visibility_level", using: :btree + create_table "spam_logs", force: :cascade do |t| + t.integer "user_id" + t.string "source_ip" + t.string "user_agent" + t.boolean "via_api" + t.integer "project_id" + t.string "noteable_type" + t.string "title" + t.text "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "subscriptions", force: :cascade do |t| t.integer "user_id" t.integer "subscribable_id" diff --git a/doc/integration/README.md b/doc/integration/README.md index 83116bc8370..281eea8363d 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -15,6 +15,7 @@ See the documentation below for details on how to configure these services. - [OAuth2 provider](oauth_provider.md) OAuth2 application creation - [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages - [reCAPTCHA](recaptcha.md) Configure GitLab to use Google reCAPTCHA for new users +- [Akismet](akismet.md) Configure Akismet to stop spam GitLab Enterprise Edition contains [advanced Jenkins support][jenkins]. diff --git a/doc/integration/akismet.md b/doc/integration/akismet.md new file mode 100644 index 00000000000..5cc09bd536d --- /dev/null +++ b/doc/integration/akismet.md @@ -0,0 +1,30 @@ +# Akismet + +GitLab leverages [Akismet](http://akismet.com) to protect against spam. Currently +GitLab uses Akismet to prevent users who are not members of a project from +creating spam via the GitLab API. Detected spam will be rejected, and +an entry in the "Spam Log" section in the Admin page will be created. + +Privacy note: GitLab submits the user's IP and user agent to Akismet. Note that +adding a user to a project will disable the Akismet check and prevent this +from happening. + +## Configuration + +To use Akismet: + +1. Go to the URL: https://akismet.com/account/ + +2. Sign-in or create a new account. + +3. Click on "Show" to reveal the API key. + +4. Go to Applications Settings on Admin Area (`admin/application_settings`) + +5. Check the `Enable Akismet` checkbox + +6. Fill in the API key from step 3. + +7. Save the configuration. + +![Screenshot of Akismet settings](img/akismet_settings.png) diff --git a/doc/integration/img/akismet_settings.png b/doc/integration/img/akismet_settings.png new file mode 100644 index 00000000000..ccdd3adb1c5 Binary files /dev/null and b/doc/integration/img/akismet_settings.png differ diff --git a/features/admin/spam_logs.feature b/features/admin/spam_logs.feature new file mode 100644 index 00000000000..92a5389e3a4 --- /dev/null +++ b/features/admin/spam_logs.feature @@ -0,0 +1,8 @@ +Feature: Admin spam logs + Background: + Given I sign in as an admin + And spam logs exist + + Scenario: Browse spam logs + When I visit spam logs page + Then I should see list of spam logs diff --git a/features/steps/admin/spam_logs.rb b/features/steps/admin/spam_logs.rb new file mode 100644 index 00000000000..79d18b036b0 --- /dev/null +++ b/features/steps/admin/spam_logs.rb @@ -0,0 +1,18 @@ +class Spinach::Features::AdminSpamLogs < Spinach::FeatureSteps + include SharedAuthentication + include SharedPaths + include SharedAdmin + + step 'I should see list of spam logs' do + page.should have_content("Spam Logs") + spam_log = SpamLog.first + page.should have_content spam_log.title + page.should have_content spam_log.description + page.should have_link("Remove user") + page.should have_link("Block user") + end + + step 'spam logs exist' do + create(:spam_log) + end +end diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 4264c9c6f1a..2c854ac7bf9 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -191,6 +191,10 @@ module SharedPaths visit admin_application_settings_path end + step 'I visit spam logs page' do + visit admin_spam_logs_path + end + step 'I visit applications page' do visit admin_applications_path end diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 6e7a7672070..cdadd13c13a 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -3,6 +3,8 @@ module API class Issues < Grape::API before { authenticate! } + helpers ::Gitlab::AkismetHelper + helpers do def filter_issues_state(issues, state) case state @@ -19,6 +21,15 @@ module API def filter_issues_milestone(issues, milestone) issues.includes(:milestone).where('milestones.title' => milestone) end + + def create_spam_log(project, current_user, attrs) + params = attrs.dup + params[:source_ip] = env['REMOTE_ADDR'] + params[:user_agent] = env['HTTP_USER_AGENT'] + params[:noteable_type] = 'Issue' + params[:via_api] = true + ::CreateSpamLogService.new(project, current_user, params).execute + end end resource :issues do @@ -114,7 +125,16 @@ module API render_api_error!({ labels: errors }, 400) end - issue = ::Issues::CreateService.new(user_project, current_user, attrs).execute + project = user_project + text = attrs[:title] + text += "\n#{attrs[:description]}" if attrs[:description].present? + + if check_for_spam?(project, current_user) && is_spam?(env, current_user, text) + create_spam_log(project, current_user, attrs) + render_api_error!({ error: 'Spam detected' }, 400) + end + + issue = ::Issues::CreateService.new(project, current_user, attrs).execute if issue.valid? # Find or create labels and attach to issue. Labels are valid because diff --git a/lib/gitlab/akismet_helper.rb b/lib/gitlab/akismet_helper.rb new file mode 100644 index 00000000000..71f525309fe --- /dev/null +++ b/lib/gitlab/akismet_helper.rb @@ -0,0 +1,39 @@ +module Gitlab + module AkismetHelper + def akismet_enabled? + current_application_settings.akismet_enabled + end + + def akismet_client + ::Akismet::Client.new(current_application_settings.akismet_api_key, + Gitlab.config.gitlab.url) + 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'] + + params = { + type: 'comment', + text: text, + created_at: DateTime.now, + author: user.name, + author_email: user.email, + referrer: environment['HTTP_REFERER'], + } + + begin + is_spam, is_blatant = client.check(ip_address, user_agent, params) + is_spam || is_blatant + rescue => e + Rails.logger.error("Unable to connect to Akismet: #{e}, skipping check") + false + end + end + end +end diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index a6b2f14521c..8531c7e87e1 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -34,7 +34,8 @@ module Gitlab shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'], max_artifacts_size: Settings.artifacts['max_size'], require_two_factor_authentication: false, - two_factor_grace_period: 48 + two_factor_grace_period: 48, + akismet_enabled: false ) end diff --git a/spec/controllers/admin/spam_logs_controller_spec.rb b/spec/controllers/admin/spam_logs_controller_spec.rb new file mode 100644 index 00000000000..2486298fc78 --- /dev/null +++ b/spec/controllers/admin/spam_logs_controller_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Admin::SpamLogsController do + let(:admin) { create(:admin) } + let(:spam_log) { create(:spam_log, user: admin) } + + before do + sign_in(admin) + end + + describe '#index' do + it 'lists all spam logs' do + get :index + expect(response.status).to eq(200) + end + end + + describe '#destroy' do + it 'destroys just spam log' do + user = spam_log.user + delete :destroy, id: spam_log.id + + expect(SpamLog.all.count).to eq(0) + expect(User.find(user.id)).to be_truthy + expect(response.status).to eq(302) + end + + it 'destroys user and his spam logs' do + user = spam_log.user + delete :destroy, id: spam_log.id, remove_user: true + + expect(SpamLog.all.count).to eq(0) + expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound) + expect(response.status).to eq(302) + end + + it 'destroys user and his spam logs with JSON format' do + user = spam_log.user + delete :destroy, id: spam_log.id, remove_user: true, format: :json + + expect(SpamLog.all.count).to eq(0) + expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound) + expect(JSON.parse(response.body)).to eq({}) + expect(response.status).to eq(200) + end + end +end diff --git a/spec/factories/spam_logs.rb b/spec/factories/spam_logs.rb new file mode 100644 index 00000000000..9e8686d73c2 --- /dev/null +++ b/spec/factories/spam_logs.rb @@ -0,0 +1,7 @@ +# Read about factories at https://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :spam_log do + user + end +end diff --git a/spec/lib/gitlab/akismet_helper_spec.rb b/spec/lib/gitlab/akismet_helper_spec.rb new file mode 100644 index 00000000000..9858935180a --- /dev/null +++ b/spec/lib/gitlab/akismet_helper_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe Gitlab::AkismetHelper, type: :helper do + let(:project) { create(:project) } + let(:user) { create(:user) } + + before do + allow(Gitlab.config.gitlab).to receive(:url).and_return(Settings.send(:build_gitlab_url)) + current_application_settings.akismet_enabled = true + current_application_settings.akismet_api_key = '12345' + end + + describe '#check_for_spam?' do + it 'returns true for non-member' do + expect(helper.check_for_spam?(project, user)).to eq(true) + end + + it 'returns false for member' do + project.team << [user, :guest] + expect(helper.check_for_spam?(project, user)).to eq(false) + end + end + + describe '#is_spam?' do + it 'returns true for spam' do + environment = { + 'REMOTE_ADDR' => '127.0.0.1', + 'HTTP_USER_AGENT' => 'Test User Agent' + } + + allow_any_instance_of(::Akismet::Client).to receive(:check).and_return([true, true]) + expect(helper.is_spam?(environment, user, 'Is this spam?')).to eq(true) + end + end +end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 5e65ad18c0e..2e50344c149 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -241,6 +241,28 @@ describe API::API, api: true do end end + describe 'POST /projects/:id/issues with spam filtering' do + before do + Grape::Endpoint.before_each do |endpoint| + allow(endpoint).to receive(:check_for_spam?).and_return(true) + allow(endpoint).to receive(:is_spam?).and_return(true) + end + end + + it "should create a new project issue" do + post api("/projects/#{project.id}/issues", user), + title: 'new issue', labels: 'label, label2' + expect(response.status).to eq(400) + expect(json_response['message']).to eq({ "error" => "Spam detected" }) + spam_logs = SpamLog.all + expect(spam_logs.count).to eq(1) + expect(spam_logs[0].title).to eq('new issue') + expect(spam_logs[0].user).to eq(user) + expect(spam_logs[0].noteable_type).to eq('Issue') + expect(spam_logs[0].project_id).to eq(project.id) + end + end + describe "PUT /projects/:id/issues/:issue_id to update only title" do it "should update a project issue" do put api("/projects/#{project.id}/issues/#{issue.id}", user), -- cgit v1.2.1 From 64c9768bd6916edfc1e43907ca5e976524b8d51b Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 26 Jan 2016 16:59:23 -0200 Subject: Use truncate helper on spam logs list --- app/models/spam_log.rb | 8 -------- app/views/admin/spam_logs/_spam_log.html.haml | 2 +- features/steps/admin/spam_logs.rb | 22 ++++++++++++++++------ spec/factories/spam_logs.rb | 4 ++++ 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/app/models/spam_log.rb b/app/models/spam_log.rb index 132c5713e0a..b7b32b478a7 100644 --- a/app/models/spam_log.rb +++ b/app/models/spam_log.rb @@ -2,12 +2,4 @@ class SpamLog < ActiveRecord::Base belongs_to :user validates :user, presence: true - - def truncated_description - if description.present? && description.length > 100 - return description[0..100] + "..." - end - - description - end end diff --git a/app/views/admin/spam_logs/_spam_log.html.haml b/app/views/admin/spam_logs/_spam_log.html.haml index 1c793bbf738..9f9f1d75895 100644 --- a/app/views/admin/spam_logs/_spam_log.html.haml +++ b/app/views/admin/spam_logs/_spam_log.html.haml @@ -16,7 +16,7 @@ %td = spam_log.title %td - = spam_log.truncated_description + = truncate(spam_log.description, length: 100) %td - if user = link_to 'Remove user', admin_spam_log_path(spam_log, remove_user: true), diff --git a/features/steps/admin/spam_logs.rb b/features/steps/admin/spam_logs.rb index 79d18b036b0..ad825fd414c 100644 --- a/features/steps/admin/spam_logs.rb +++ b/features/steps/admin/spam_logs.rb @@ -4,15 +4,25 @@ class Spinach::Features::AdminSpamLogs < Spinach::FeatureSteps include SharedAdmin step 'I should see list of spam logs' do - page.should have_content("Spam Logs") - spam_log = SpamLog.first - page.should have_content spam_log.title - page.should have_content spam_log.description - page.should have_link("Remove user") - page.should have_link("Block user") + expect(page).to have_content('Spam Logs') + expect(page).to have_content spam_log.source_ip + expect(page).to have_content spam_log.noteable_type + expect(page).to have_content 'N' + expect(page).to have_content spam_log.title + expect(page).to have_content truncate(spam_log.description) + expect(page).to have_link('Remove user') + expect(page).to have_link('Block user') end step 'spam logs exist' do create(:spam_log) end + + def spam_log + @spam_log ||= SpamLog.first + end + + def truncate(description) + "#{spam_log.description[0...97]}..." + end end diff --git a/spec/factories/spam_logs.rb b/spec/factories/spam_logs.rb index 9e8686d73c2..d90e5d6bf26 100644 --- a/spec/factories/spam_logs.rb +++ b/spec/factories/spam_logs.rb @@ -3,5 +3,9 @@ FactoryGirl.define do factory :spam_log do user + source_ip { FFaker::Internet.ip_v4_address } + noteable_type 'Issue' + title { FFaker::Lorem.sentence } + description { FFaker::Lorem.paragraph(5) } end end -- cgit v1.2.1 From 80d0a2a6d8dccbb9888f9cd4dc3c3e7e208817e6 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 26 Jan 2016 17:01:56 -0200 Subject: Add model spec for SpamLog --- spec/models/spam_log_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 spec/models/spam_log_spec.rb diff --git a/spec/models/spam_log_spec.rb b/spec/models/spam_log_spec.rb new file mode 100644 index 00000000000..076f3e44c70 --- /dev/null +++ b/spec/models/spam_log_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe SpamLog, models: true do + describe 'associations' do + it { is_expected.to belong_to(:user) } + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:user) } + end +end -- cgit v1.2.1 From e38a1fc83ee7a9fb04fe370204f0094723890f00 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 26 Jan 2016 17:55:33 -0200 Subject: Fix typo on User model --- app/models/user.rb | 2 +- spec/models/user_spec.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/user.rb b/app/models/user.rb index 63c895683f7..234c1cd89f9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -138,7 +138,7 @@ class User < ActiveRecord::Base has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest" has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy has_one :abuse_report, dependent: :destroy - has_many :spam_log, dependent: :destroy + has_many :spam_logs, dependent: :destroy has_many :builds, dependent: :nullify, class_name: 'Ci::Build' diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 0bef68e2885..cee051f5732 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -91,6 +91,7 @@ describe User, models: true do it { is_expected.to have_many(:assigned_merge_requests).dependent(:destroy) } it { is_expected.to have_many(:identities).dependent(:destroy) } it { is_expected.to have_one(:abuse_report) } + it { is_expected.to have_many(:spam_logs).dependent(:destroy) } end describe 'validations' do -- cgit v1.2.1 From 62cad887ea695d40afee894089f894ee398cf98a Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 26 Jan 2016 18:03:01 -0200 Subject: Use time_ago_with_tooltip on spam logs list --- app/views/admin/spam_logs/_spam_log.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/spam_logs/_spam_log.html.haml b/app/views/admin/spam_logs/_spam_log.html.haml index 9f9f1d75895..51e94acce22 100644 --- a/app/views/admin/spam_logs/_spam_log.html.haml +++ b/app/views/admin/spam_logs/_spam_log.html.haml @@ -1,7 +1,7 @@ - user = spam_log.user %tr %td - = spam_log.created_at.to_s(:short) + = time_ago_with_tooltip(spam_log.created_at) %td - if user = link_to user.name, user -- cgit v1.2.1 From a2bbf004779db402e67a918db893c166502f5050 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 26 Jan 2016 18:08:20 -0200 Subject: Refactor spam filtering on issues API --- lib/api/issues.rb | 15 ++++++++------- spec/requests/api/issues_spec.rb | 11 ++++++++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/api/issues.rb b/lib/api/issues.rb index cdadd13c13a..252744515da 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -23,11 +23,13 @@ module API end def create_spam_log(project, current_user, attrs) - params = attrs.dup - params[:source_ip] = env['REMOTE_ADDR'] - params[:user_agent] = env['HTTP_USER_AGENT'] - params[:noteable_type] = 'Issue' - params[:via_api] = true + params = attrs.merge({ + source_ip: env['REMOTE_ADDR'], + user_agent: env['HTTP_USER_AGENT'], + noteable_type: 'Issue', + via_api: true + }) + ::CreateSpamLogService.new(project, current_user, params).execute end end @@ -126,8 +128,7 @@ module API end project = user_project - text = attrs[:title] - text += "\n#{attrs[:description]}" if attrs[:description].present? + text = [attrs[:title], attrs[:description]].reject(&:blank?).join("\n") if check_for_spam?(project, current_user) && is_spam?(env, current_user, text) create_spam_log(project, current_user, attrs) diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 2e50344c149..dcf1b394a3f 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -249,14 +249,19 @@ describe API::API, api: true do end end - it "should create a new project issue" do - post api("/projects/#{project.id}/issues", user), - title: 'new issue', labels: 'label, label2' + it "should not create a new project issue" do + expect { + post api("/projects/#{project.id}/issues", user), + title: 'new issue', description: 'content here', labels: 'label, label2' + }.not_to change(Issue, :count) + expect(response.status).to eq(400) expect(json_response['message']).to eq({ "error" => "Spam detected" }) + spam_logs = SpamLog.all expect(spam_logs.count).to eq(1) expect(spam_logs[0].title).to eq('new issue') + expect(spam_logs[0].description).to eq('content here') expect(spam_logs[0].user).to eq(user) expect(spam_logs[0].noteable_type).to eq('Issue') expect(spam_logs[0].project_id).to eq(project.id) -- cgit v1.2.1 From 718b1dddfe8d7422e8de8b2fbbd8357fc1c3b5e4 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 26 Jan 2016 19:20:01 -0200 Subject: Refactor Admin::SpamLogsController to block user before destroying --- app/controllers/admin/spam_logs_controller.rb | 30 +++++-------------- app/models/spam_log.rb | 5 ++++ app/views/admin/spam_logs/_spam_log.html.haml | 8 +++-- app/views/admin/spam_logs/index.html.haml | 2 +- .../controllers/admin/spam_logs_controller_spec.rb | 35 +++++++++------------- spec/models/spam_log_spec.rb | 14 +++++++++ 6 files changed, 46 insertions(+), 48 deletions(-) diff --git a/app/controllers/admin/spam_logs_controller.rb b/app/controllers/admin/spam_logs_controller.rb index 69f94dd3ba8..377e9741e5f 100644 --- a/app/controllers/admin/spam_logs_controller.rb +++ b/app/controllers/admin/spam_logs_controller.rb @@ -1,33 +1,17 @@ class Admin::SpamLogsController < Admin::ApplicationController - before_action :set_spam_log, only: [:destroy] - def index - @spam_logs = SpamLog.order(created_at: :desc).page(params[:page]) + @spam_logs = SpamLog.order(id: :desc).page(params[:page]) end def destroy - @spam_log.destroy - message = 'Spam log was successfully destroyed.' + spam_log = SpamLog.find(params[:id]) if params[:remove_user] - username = @spam_log.user.username - @spam_log.user.destroy - message = "User #{username} was successfully destroyed." - end - - respond_to do |format| - format.json { render json: '{}' } - format.html { redirect_to admin_spam_logs_path, notice: message } + spam_log.remove_user + redirect_to admin_spam_logs_path, notice: "User #{spam_log.user.username} was successfully removed." + else + spam_log.destroy + render nothing: true end end - - private - - def set_spam_log - @spam_log = SpamLog.find(params[:id]) - end - - def spam_log_params - params[:spam_log] - end end diff --git a/app/models/spam_log.rb b/app/models/spam_log.rb index b7b32b478a7..12df68ef83b 100644 --- a/app/models/spam_log.rb +++ b/app/models/spam_log.rb @@ -2,4 +2,9 @@ class SpamLog < ActiveRecord::Base belongs_to :user validates :user, presence: true + + def remove_user + user.block + user.destroy + end end diff --git a/app/views/admin/spam_logs/_spam_log.html.haml b/app/views/admin/spam_logs/_spam_log.html.haml index 51e94acce22..8aea67f4497 100644 --- a/app/views/admin/spam_logs/_spam_log.html.haml +++ b/app/views/admin/spam_logs/_spam_log.html.haml @@ -4,13 +4,15 @@ = time_ago_with_tooltip(spam_log.created_at) %td - if user - = link_to user.name, user + = link_to user.name, [:admin, user] + .light.small + Joined #{time_ago_with_tooltip(user.created_at)} - else (removed) %td = spam_log.source_ip %td - = spam_log.via_api ? 'Y' : 'N' + = spam_log.via_api? ? 'Y' : 'N' %td = spam_log.noteable_type %td @@ -27,4 +29,4 @@ - else .btn.btn-xs.disabled Already Blocked - = link_to 'Remove log', [:admin, spam_log, format: :json], remote: true, method: :delete, class: "btn btn-xs btn-close js-remove-tr" + = link_to 'Remove log', [:admin, spam_log], remote: true, method: :delete, class: "btn btn-xs btn-close js-remove-tr" diff --git a/app/views/admin/spam_logs/index.html.haml b/app/views/admin/spam_logs/index.html.haml index 439468e572b..0fdd5bd9960 100644 --- a/app/views/admin/spam_logs/index.html.haml +++ b/app/views/admin/spam_logs/index.html.haml @@ -9,7 +9,7 @@ %th Date %th User %th Source IP - %th Via API? + %th API? %th Type %th Title %th Description diff --git a/spec/controllers/admin/spam_logs_controller_spec.rb b/spec/controllers/admin/spam_logs_controller_spec.rb index 2486298fc78..6beebc362e9 100644 --- a/spec/controllers/admin/spam_logs_controller_spec.rb +++ b/spec/controllers/admin/spam_logs_controller_spec.rb @@ -1,8 +1,10 @@ require 'spec_helper' describe Admin::SpamLogsController do - let(:admin) { create(:admin) } - let(:spam_log) { create(:spam_log, user: admin) } + let(:admin) { create(:admin) } + let(:user) { create(:user) } + let!(:first_spam) { create(:spam_log, user: user) } + let!(:second_spam) { create(:spam_log, user: user) } before do sign_in(admin) @@ -11,37 +13,28 @@ describe Admin::SpamLogsController do describe '#index' do it 'lists all spam logs' do get :index + expect(response.status).to eq(200) end end describe '#destroy' do - it 'destroys just spam log' do - user = spam_log.user - delete :destroy, id: spam_log.id + it 'removes only the spam log when removing log' do + expect { + delete :destroy, id: first_spam.id + }.to change { SpamLog.count }.by(-1) - expect(SpamLog.all.count).to eq(0) expect(User.find(user.id)).to be_truthy - expect(response.status).to eq(302) + expect(response.status).to eq(200) end - it 'destroys user and his spam logs' do - user = spam_log.user - delete :destroy, id: spam_log.id, remove_user: true + it 'removes user and his spam logs when removing the user' do + delete :destroy, id: first_spam.id, remove_user: true - expect(SpamLog.all.count).to eq(0) - expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound) + expect(flash[:notice]).to eq "User #{user.username} was successfully removed." expect(response.status).to eq(302) - end - - it 'destroys user and his spam logs with JSON format' do - user = spam_log.user - delete :destroy, id: spam_log.id, remove_user: true, format: :json - - expect(SpamLog.all.count).to eq(0) + expect(SpamLog.count).to eq(0) expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound) - expect(JSON.parse(response.body)).to eq({}) - expect(response.status).to eq(200) end end end diff --git a/spec/models/spam_log_spec.rb b/spec/models/spam_log_spec.rb index 076f3e44c70..c4ec7625cb0 100644 --- a/spec/models/spam_log_spec.rb +++ b/spec/models/spam_log_spec.rb @@ -8,4 +8,18 @@ describe SpamLog, models: true do describe 'validations' do it { is_expected.to validate_presence_of(:user) } end + + describe '#remove_user' do + it 'blocks the user' do + spam_log = build(:spam_log) + + expect { spam_log.remove_user }.to change { spam_log.user.blocked? }.to(true) + end + + it 'removes the user' do + spam_log = build(:spam_log) + + expect { spam_log.remove_user }.to change { User.count }.by(-1) + end + end end -- cgit v1.2.1 From eefc46e0d5310cce5b5a64c1b982d5348d465f83 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 26 Jan 2016 19:51:52 -0200 Subject: Fix rubocop offenses --- spec/controllers/admin/spam_logs_controller_spec.rb | 5 +---- spec/requests/api/issues_spec.rb | 14 +++++++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/spec/controllers/admin/spam_logs_controller_spec.rb b/spec/controllers/admin/spam_logs_controller_spec.rb index 6beebc362e9..b51b303a714 100644 --- a/spec/controllers/admin/spam_logs_controller_spec.rb +++ b/spec/controllers/admin/spam_logs_controller_spec.rb @@ -20,10 +20,7 @@ describe Admin::SpamLogsController do describe '#destroy' do it 'removes only the spam log when removing log' do - expect { - delete :destroy, id: first_spam.id - }.to change { SpamLog.count }.by(-1) - + expect { delete :destroy, id: first_spam.id }.to change { SpamLog.count }.by(-1) expect(User.find(user.id)).to be_truthy expect(response.status).to eq(200) end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index dcf1b394a3f..4443036d98f 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -249,12 +249,16 @@ describe API::API, api: true do end end - it "should not create a new project issue" do - expect { - post api("/projects/#{project.id}/issues", user), - title: 'new issue', description: 'content here', labels: 'label, label2' - }.not_to change(Issue, :count) + let(:params) do + { + title: 'new issue', + description: 'content here', + labels: 'label, label2' + } + end + it "should not create a new project issue" do + expect { post api("/projects/#{project.id}/issues", user), params }.not_to change(Issue, :count) expect(response.status).to eq(400) expect(json_response['message']).to eq({ "error" => "Spam detected" }) -- cgit v1.2.1 From 07384aa00d8a8759cdb29ba51ae32a6032ba2571 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 1 Feb 2016 22:05:56 -0200 Subject: Memoize Akismet client initialization on AkismetHelper --- lib/gitlab/akismet_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/akismet_helper.rb b/lib/gitlab/akismet_helper.rb index 71f525309fe..b366c89889e 100644 --- a/lib/gitlab/akismet_helper.rb +++ b/lib/gitlab/akismet_helper.rb @@ -5,8 +5,8 @@ module Gitlab end def akismet_client - ::Akismet::Client.new(current_application_settings.akismet_api_key, - Gitlab.config.gitlab.url) + @akismet_client ||= ::Akismet::Client.new(current_application_settings.akismet_api_key, + Gitlab.config.gitlab.url) end def check_for_spam?(project, user) -- cgit v1.2.1 From 0ea5d764f2ad8d94adfca36b20ce92e67af81e36 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 1 Feb 2016 22:25:00 -0200 Subject: Hide the link for spam logs if the Askimet is disabled --- app/helpers/application_settings_helper.rb | 4 ++++ app/views/layouts/nav/_admin.html.haml | 13 +++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 7d6b58ee21a..23693629a4c 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -23,6 +23,10 @@ module ApplicationSettingsHelper current_application_settings.user_oauth_applications end + def askimet_enabled? + current_application_settings.akismet_enabled? + end + # Return a group of checkboxes that use Bootstrap's button plugin for a # toggle button effect. def restricted_level_checkboxes(help_block_id) diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml index 8dc20587421..5f8212ea264 100644 --- a/app/views/layouts/nav/_admin.html.haml +++ b/app/views/layouts/nav/_admin.html.haml @@ -82,12 +82,13 @@ Abuse Reports %span.count= number_with_delimiter(AbuseReport.count(:all)) - = nav_link(controller: :spam_logs) do - = link_to admin_spam_logs_path, title: "Spam Logs" do - = icon('exclamation-triangle fw') - %span - Spam Logs - %span.count= number_with_delimiter(SpamLog.count(:all)) + - if askimet_enabled? + = nav_link(controller: :spam_logs) do + = link_to admin_spam_logs_path, title: "Spam Logs" do + = icon('exclamation-triangle fw') + %span + Spam Logs + %span.count= number_with_delimiter(SpamLog.count(:all)) = nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do = link_to admin_application_settings_path, title: 'Settings' do -- cgit v1.2.1 From dffacbb12c0abd4edf677aed2d9e201b41fd2dae Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 1 Feb 2016 22:28:33 -0200 Subject: Update CHANGELOG --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 1be1f7374df..187ab000057 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -22,6 +22,7 @@ v 8.5.0 (unreleased) - Deprecate API "merge_request/:merge_request_id/comments". Use "merge_requests/:merge_request_id/notes" instead - Deprecate API "merge_request/:merge_request_id/...". Use "merge_requests/:merge_request_id/..." instead - Mark inline difference between old and new paths when a file is renamed + - Support Akismet spam checking for creation of issues via API (Stan Hu) v 8.4.3 - Increase lfs_objects size column to 8-byte integer to allow files larger @@ -74,7 +75,6 @@ v 8.4.0 - Don't notify users twice if they are both project watchers and subscribers (Stan Hu) - Remove gray background from layout in UI - Fix signup for OAuth providers that don't provide a name - - Support Akismet spam checking for creation of issues via API (Stan Hu) - Implement new UI for group page - Implement search inside emoji picker - Let the CI runner know about builds that this build depends on -- cgit v1.2.1 From 0a4db90d36870211df2dc1e606b01602666706c8 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 2 Feb 2016 14:35:09 +0100 Subject: Use begin/end instead of defined? --- app/models/ci/commit.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb index 96786ac4573..ecbd2078b1d 100644 --- a/app/models/ci/commit.rb +++ b/app/models/ci/commit.rb @@ -205,11 +205,11 @@ module Ci end def ci_yaml_file - return @ci_yaml_file if defined?(@ci_yaml_file) - - blob = project.repository.blob_at(sha, '.gitlab-ci.yml') - blob.load_all_data!(project.repository) - @ci_yaml_file = blob.data + @ci_yaml_file ||= begin + blob = project.repository.blob_at(sha, '.gitlab-ci.yml') + blob.load_all_data!(project.repository) + blob.data + end rescue nil end -- cgit v1.2.1 From e08aa3df905f09f1c964fb056cba922a1d6eaa85 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 2 Feb 2016 15:04:50 +0100 Subject: Use gitlab_git 8.0.0 --- Gemfile | 2 +- Gemfile.lock | 20 +++++++------------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Gemfile b/Gemfile index 88236146a14..a511b114f9d 100644 --- a/Gemfile +++ b/Gemfile @@ -49,7 +49,7 @@ gem "browser", '~> 1.0.0' # Extracting information from a git repository # Provide access to Gitlab::Git library -gem "gitlab_git", git: 'https://gitlab.com/gitlab-org/gitlab_git.git', branch: 'lazy-blob' +gem "gitlab_git", '~> 8.0.0' # LDAP Auth # GitLab fork with several improvements to original library. For full list of changes diff --git a/Gemfile.lock b/Gemfile.lock index 9aacbced998..211cb9a42ae 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,14 +1,3 @@ -GIT - remote: https://gitlab.com/gitlab-org/gitlab_git.git - revision: 57160e1cbcf4c03e68aa881dfa8e2f55c37a3ee6 - branch: lazy-blob - specs: - gitlab_git (7.2.24) - activesupport (~> 4.0) - charlock_holmes (~> 0.7.3) - github-linguist (~> 4.7.0) - rugged (~> 0.23.3) - GEM remote: https://rubygems.org/ specs: @@ -350,7 +339,7 @@ GEM json get_process_mem (0.2.0) gherkin-ruby (0.3.2) - github-linguist (4.7.4) + github-linguist (4.7.3) charlock_holmes (~> 0.7.3) escape_utils (~> 1.1.0) mime-types (>= 1.19) @@ -367,6 +356,11 @@ GEM posix-spawn (~> 0.3) gitlab_emoji (0.2.0) gemojione (~> 2.1) + gitlab_git (8.0.0) + activesupport (~> 4.0) + charlock_holmes (~> 0.7.3) + github-linguist (~> 4.7.0) + rugged (~> 0.23.3) gitlab_meta (7.0) gitlab_omniauth-ldap (1.2.1) net-ldap (~> 0.9) @@ -940,7 +934,7 @@ DEPENDENCIES github-markup (~> 1.3.1) gitlab-flowdock-git-hook (~> 1.0.1) gitlab_emoji (~> 0.2.0) - gitlab_git! + gitlab_git (~> 8.0.0) gitlab_meta (= 7.0) gitlab_omniauth-ldap (~> 1.2.1) gollum-lib (~> 4.1.0) -- cgit v1.2.1 From b67f8eee0d2810be4a010c5e968e1848b4ca3c88 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 2 Feb 2016 15:06:14 +0100 Subject: Use @repository --- app/controllers/projects/avatars_controller.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb index bc40e601030..f7e6bb34443 100644 --- a/app/controllers/projects/avatars_controller.rb +++ b/app/controllers/projects/avatars_controller.rb @@ -2,11 +2,10 @@ class Projects::AvatarsController < Projects::ApplicationController before_action :project def show - repository = @project.repository - @blob = repository.blob_at_branch('master', @project.avatar_in_git) + @blob = @repository.blob_at_branch('master', @project.avatar_in_git) if @blob headers['X-Content-Type-Options'] = 'nosniff' - headers.store(*Gitlab::Workhorse.send_git_blob(repository, @blob)) + headers.store(*Gitlab::Workhorse.send_git_blob(@repository, @blob)) headers['Content-Disposition'] = 'inline' headers['Content-Type'] = @blob.content_type head :ok # 'render nothing: true' messes up the Content-Type -- cgit v1.2.1 From c41a8be8d266ceefac307939a2acfd103260fb29 Mon Sep 17 00:00:00 2001 From: Michi302 Date: Wed, 6 Jan 2016 20:11:50 +0100 Subject: Fix add_pagination_headers to keep request parameters in Link header --- CHANGELOG | 1 + lib/api/helpers.rb | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7a70516173c..f207e0c5316 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,7 @@ v 8.5.0 (unreleased) - Update the ExternalIssue regex pattern (Blake Hitchcock) - Optimized performance of finding issues to be closed by a merge request - Revert "Add IP check against DNSBLs at account sign-up" + - Fix API to keep request parameters in Link header (Michael Potthoff) - Deprecate API "merge_request/:merge_request_id/comments". Use "merge_requests/:merge_request_id/notes" instead - Deprecate API "merge_request/:merge_request_id/...". Use "merge_requests/:merge_request_id/..." instead - Mark inline difference between old and new paths when a file is renamed diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 9dacf7c1e86..a72044e8058 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -30,7 +30,7 @@ module API end def sudo_identifier() - identifier ||= params[SUDO_PARAM] ||= env[SUDO_HEADER] + identifier ||= params[SUDO_PARAM] || env[SUDO_HEADER] # Regex for integers if !!(identifier =~ /^[0-9]+$/) @@ -344,12 +344,22 @@ module API def pagination_links(paginated_data) request_url = request.url.split('?').first + request_params = params.clone + request_params[:per_page] = paginated_data.limit_value links = [] - links << %(<#{request_url}?page=#{paginated_data.current_page - 1}&per_page=#{paginated_data.limit_value}>; rel="prev") unless paginated_data.first_page? - links << %(<#{request_url}?page=#{paginated_data.current_page + 1}&per_page=#{paginated_data.limit_value}>; rel="next") unless paginated_data.last_page? - links << %(<#{request_url}?page=1&per_page=#{paginated_data.limit_value}>; rel="first") - links << %(<#{request_url}?page=#{paginated_data.total_pages}&per_page=#{paginated_data.limit_value}>; rel="last") + + request_params[:page] = paginated_data.current_page - 1 + links << %(<#{request_url}?#{request_params.to_query}>; rel="prev") unless paginated_data.first_page? + + request_params[:page] = paginated_data.current_page + 1 + links << %(<#{request_url}?#{request_params.to_query}>; rel="next") unless paginated_data.last_page? + + request_params[:page] = 1 + links << %(<#{request_url}?#{request_params.to_query}>; rel="first") + + request_params[:page] = paginated_data.total_pages + links << %(<#{request_url}?#{request_params.to_query}>; rel="last") links.join(', ') end -- cgit v1.2.1 From 070a3079fc9115ec564bc48f6b4deec5cabd901d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 2 Feb 2016 14:34:46 +0100 Subject: Add a spec for the API pagination Link header --- spec/requests/api/issues_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 5e65ad18c0e..410e684ee3b 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -46,10 +46,10 @@ describe API::API, api: true do expect(json_response.first['title']).to eq(issue.title) end - it "should add pagination headers" do - get api("/issues?per_page=3", user) + it "should add pagination headers and keep query params" do + get api("/issues?state=closed&per_page=3", user) expect(response.headers['Link']).to eq( - '; rel="first", ; rel="last"' + '; rel="first", ; rel="last"' % [user.private_token, user.private_token] ) end -- cgit v1.2.1 From d716905743352de34bca8441706eef776f1cd6ce Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 2 Feb 2016 16:00:13 +0100 Subject: Use gitlab-workhorse 0.6.3 --- GITLAB_WORKHORSE_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index b6160487433..844f6a91acb 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -0.6.2 +0.6.3 -- cgit v1.2.1 From ea41d3607769b2b726a25d50ea23675bc5936227 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 2 Feb 2016 16:01:20 +0100 Subject: Use gitlab-workhorse 0.6.3 in installation guide --- doc/install/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 2cc2dbef41b..a2c23bd52e5 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -355,7 +355,7 @@ GitLab Shell is an SSH access and repository management software developed speci cd /home/git sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git cd gitlab-workhorse - sudo -u git -H git checkout 0.6.2 + sudo -u git -H git checkout 0.6.3 sudo -u git -H make ### Initialize Database and Activate Advanced Features -- cgit v1.2.1 From a12ac9c060018071d75c7b1e9d9ee3b90cb4d792 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 2 Feb 2016 14:50:14 -0500 Subject: Update CHANGELOG [ci skip] --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 7a9b51cf331..3469a1e026b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -32,6 +32,9 @@ v 8.4.3 - Fix highlighting in blame view - Update sentry-raven gem to prevent "Not a git repository" console output when running certain commands + - Add instrumentation to additional Gitlab::Git and Rugged methods for + performance monitoring + - Allow autosize textareas to also be manually resized v 8.4.2 - Bump required gitlab-workhorse version to bring in a fix for missing -- cgit v1.2.1 From acea6e1c507cf35123a8fe87ca708683719f4820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Bl=C3=A4ttermann?= Date: Tue, 26 Jan 2016 23:53:36 +0000 Subject: Documentation cleanup of artifacts section in Gitlab CI Readme - Added notice about build artifacts not beeing collected on failed builds. - Removed "introduced in 0.7.0" for artifacts section. - Made windows notice more precise --- doc/ci/yaml/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 4d280297dbb..194c8171bb9 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -393,8 +393,12 @@ The above script will: ### artifacts -_**Note:** Introduced in GitLab Runner v0.7.0. Also, the Windows shell executor - does not currently support artifact uploads._ +_**Note:** Introduced in GitLab Runner v0.7.0 for non-Windows platforms._ + +_**Note:** Limited Windows support was added in GitLab Runner v.1.0.0. +Currently not all executors are supported._ + +_**Note:** Build artifacts are only collected for successful builds._ `artifacts` is used to specify list of files and directories which should be attached to build after success. Below are some examples. -- cgit v1.2.1 From cbd550cfa68581127e344f31d8d7c624bdc52cbb Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Wed, 3 Feb 2016 13:18:37 +0200 Subject: Refactor OAuth provider documentation [ci skip] --- .../img/oauth_provider_admin_application.png | Bin 55533 -> 40579 bytes .../img/oauth_provider_application_form.png | Bin 25075 -> 27974 bytes .../img/oauth_provider_application_id_secret.png | Bin 0 -> 33901 bytes .../img/oauth_provider_authorized_application.png | Bin 17260 -> 32225 bytes .../img/oauth_provider_user_wide_applications.png | Bin 46238 -> 40632 bytes doc/integration/oauth_provider.md | 89 ++++++++++++++++----- 6 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 doc/integration/img/oauth_provider_application_id_secret.png diff --git a/doc/integration/img/oauth_provider_admin_application.png b/doc/integration/img/oauth_provider_admin_application.png index a5f34512aa8..a2d8e14c120 100644 Binary files a/doc/integration/img/oauth_provider_admin_application.png and b/doc/integration/img/oauth_provider_admin_application.png differ diff --git a/doc/integration/img/oauth_provider_application_form.png b/doc/integration/img/oauth_provider_application_form.png index ae135db2627..3a676b22393 100644 Binary files a/doc/integration/img/oauth_provider_application_form.png and b/doc/integration/img/oauth_provider_application_form.png differ diff --git a/doc/integration/img/oauth_provider_application_id_secret.png b/doc/integration/img/oauth_provider_application_id_secret.png new file mode 100644 index 00000000000..6d68df001af Binary files /dev/null and b/doc/integration/img/oauth_provider_application_id_secret.png differ diff --git a/doc/integration/img/oauth_provider_authorized_application.png b/doc/integration/img/oauth_provider_authorized_application.png index d3ce05be9cc..efc3b807d71 100644 Binary files a/doc/integration/img/oauth_provider_authorized_application.png and b/doc/integration/img/oauth_provider_authorized_application.png differ diff --git a/doc/integration/img/oauth_provider_user_wide_applications.png b/doc/integration/img/oauth_provider_user_wide_applications.png index 719e1974068..45ad8a6d468 100644 Binary files a/doc/integration/img/oauth_provider_user_wide_applications.png and b/doc/integration/img/oauth_provider_user_wide_applications.png differ diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md index f0c2a45b6ae..5f8bb57365c 100644 --- a/doc/integration/oauth_provider.md +++ b/doc/integration/oauth_provider.md @@ -1,35 +1,80 @@ -## GitLab as OAuth2 authentication service provider +# GitLab as OAuth2 authentication service provider -This document is about using GitLab as an OAuth authentication service provider to sign into other services. -If you want to use other OAuth authentication service providers to sign into GitLab please see the [OAuth2 client documentation](../api/oauth2.md) +This document is about using GitLab as an OAuth authentication service provider +to sign in to other services. -OAuth2 provides client applications a 'secure delegated access' to server resources on behalf of a resource owner. Or you can allow users to sign in to your application with their GitLab.com account. -In fact OAuth allows to issue access token to third-party clients by an authorization server, -with the approval of the resource owner, or end-user. -Mostly, OAuth2 is using for SSO (Single sign-on). But you can find a lot of different usages for this functionality. -For example, our feature 'GitLab Importer' is using OAuth protocol to give an access to repositories without sharing user credentials to GitLab.com account. -Also GitLab.com application can be used for authentication to your GitLab instance if needed [GitLab OmniAuth](gitlab.md). +If you want to use other OAuth authentication service providers to sign in to +GitLab, please see the [OAuth2 client documentation](../api/oauth2.md). -GitLab has two ways to add new OAuth2 application to an instance, you can add application as regular user and through admin area. So GitLab actually can have an instance-wide and a user-wide applications. There is no defferences between them except the different permission levels. +## Introduction to OAuth -### Adding application through profile -Go to your profile section 'Application' and press button 'New Application' +[OAuth] provides to client applications a 'secure delegated access' to server +resources on behalf of a resource owner. In fact, OAuth allows an authorization +server to issue access tokens to third-party clients with the approval of the +resource owner, or the end-user. -![applications](img/oauth_provider_user_wide_applications.png) +OAuth is mostly used as a Single Sign-On service (SSO), but you can find a +lot of different uses for this functionality. For example, you can allow users +to sign in to your application with their GitLab.com account, or GitLab.com +can be used for authentication to your GitLab instance +(see [GitLab OmniAuth](gitlab.md)). -After this you will see application form, where "Name" is arbitrary name, "Redirect URI" is URL in your app where users will be sent after authorization on GitLab.com. +The 'GitLab Importer' feature is also using the OAuth protocol to give access +to repositories without sharing user credentials to your GitLab.com account. -![application_form](img/oauth_provider_application_form.png) +--- -### Authorized application -Every application you authorized will be shown in your "Authorized application" sections. +GitLab supports two ways of adding a new OAuth2 application to an instance. You +can either add an application as a regular user or add it in the admin area. +What this means is that GitLab can actually have instance-wide and a user-wide +applications. There is no difference between them except for the different +permission levels they are set (user/admin). -![authorized_application](img/oauth_provider_authorized_application.png) +## Adding an application through the profile -As you can see we use default scope "api" here which is only scope we have so far. At any time you can revoke access just clicking button "Revoke". +In order to add a new application via your profile, navigate to +**Profile Settings > Applications** and select **New Application**. -### OAuth applications in admin area +![New OAuth application](img/oauth_provider_user_wide_applications.png) -If you want to create application that does not belong to certain user you can create it from admin area +--- -![admin_application](img/oauth_provider_admin_application.png) +In the application form, enter a **Name** (arbitrary), and make sure to set up +correctly the **Redirect URI** which is the URL where users will be sent after +they authorize with GitLab. + +![New OAuth application form](img/oauth_provider_application_form.png) + +--- + +When you hit **Submit** you will be provided with the application ID and +the application secret which you can then use with your application that +connects to GitLab. + +![OAuth application ID and secret](img/oauth_provider_application_id_secret.png) + +--- + +## OAuth applications in the admin area + +To create an application that does not belong to a certain user, you can create +it from the admin area. + +![OAuth admin_applications](img/oauth_provider_admin_application.png) + +--- + +## Authorized applications + +Every application you authorized to use your GitLab credentials will be shown +in the **Authorized applications** section under **Profile Settings > Applications**. + +![Authorized_applications](img/oauth_provider_authorized_application.png) + +--- + +As you can see, the default scope `api` is used, which is the only scope that +GitLab supports so far. At any time you can revoke any access by just clicking +**Revoke**. + +[oauth]: http://oauth.net/2/ "OAuth website" -- cgit v1.2.1 From ea14429b7e1de6d0a61bbdb8e8a198a6b0c28b23 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Wed, 3 Feb 2016 13:56:23 +0200 Subject: Clean up environment variables doc [ci skip] --- doc/administration/environment_variables.md | 65 ++++++++++++++++------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/doc/administration/environment_variables.md b/doc/administration/environment_variables.md index b0aa420e055..e49b3dc139b 100644 --- a/doc/administration/environment_variables.md +++ b/doc/administration/environment_variables.md @@ -1,56 +1,61 @@ # Environment Variables -## Introduction +GitLab exposes certain environment variables which can be used to override +their defaults values. -Commonly people configure GitLab via the `gitlab.rb` configuration file in the Omnibus package. +People usually configure GitLab via `/etc/gitlab/gitlab.rb` for Omnibus +installations, or `gitlab.yml` for installations from source. -But if you prefer to use environment variables we allow that too. +Below you will find the supported environment variables which you can use to +override certain values. ## Supported environment variables -Variable | Type | Explanation +Variable | Type | Description -------- | ---- | ----------- -`GITLAB_ROOT_PASSWORD` | string | Sets the password for the `root` user on installation -`GITLAB_HOST` | url | Hostname of the GitLab server includes http or https -`RAILS_ENV` | production / development / staging / test | Rails environment -`DATABASE_URL` | url | For example: postgresql://localhost/blog_development -`GITLAB_EMAIL_FROM` | email | Email address used in the "From" field in mails sent by GitLab -`GITLAB_EMAIL_DISPLAY_NAME` | string | Name used in the "From" field in mails sent by GitLab -`GITLAB_EMAIL_REPLY_TO` | email | Email address used in the "Reply-To" field in mails sent by GitLab -`GITLAB_UNICORN_MEMORY_MIN` | integer | The minimum memory threshold (in bytes) for the Unicorn worker killer -`GITLAB_UNICORN_MEMORY_MAX` | integer | The maximum memory threshold (in bytes) for the Unicorn worker killer +`GITLAB_ROOT_PASSWORD` | string | Sets the password for the `root` user on installation +`GITLAB_HOST` | string | The full URL of the GitLab server (including `http://` or `https://`) +`RAILS_ENV` | string | The Rails environment; can be one of `production`, `development`, `staging` or `test` +`DATABASE_URL` | string | The database URL; is of the form: `postgresql://localhost/blog_development` +`GITLAB_EMAIL_FROM` | string | The e-mail address used in the "From" field in e-mails sent by GitLab +`GITLAB_EMAIL_DISPLAY_NAME` | string | The name used in the "From" field in e-mails sent by GitLab +`GITLAB_EMAIL_REPLY_TO` | string | The e-mail address used in the "Reply-To" field in e-mails sent by GitLab +`GITLAB_UNICORN_MEMORY_MIN` | integer | The minimum memory threshold (in bytes) for the Unicorn worker killer (supported only in Omnibus) +`GITLAB_UNICORN_MEMORY_MAX` | integer | The maximum memory threshold (in bytes) for the Unicorn worker killer (supported only in Omnibus) ## Complete database variables The recommended way of specifying your database connection information is to set the `DATABASE_URL` environment variable. This variable only holds connection -information (adapter, database, username, password, host and port), but not -behavior information (encoding, pool). If you don't want to use `DATABASE_URL` -and/or want to set database behavior information, you will have to: +information (`adapter`, `database`, `username`, `password`, `host` and `port`), +but not behavior information (`encoding`, `pool`). If you don't want to use +`DATABASE_URL` and/or want to set database behavior information, you will have +to either: -- copy our template `config/database.yml` file: `cp config/database.yml.env config/database.yml` +- copy our template file: `cp config/database.yml.env config/database.yml`, or - set a value for some `GITLAB_DATABASE_XXX` variables -The list of `GITLAB_DATABASE_XXX` variables that you can set is as follow: +The list of `GITLAB_DATABASE_XXX` variables that you can set is: Variable | Default value | Overridden by `DATABASE_URL`? ---- | --- | --- -`GITLAB_DATABASE_ADAPTER` | `postgresql` | Yes -`GITLAB_DATABASE_DATABASE` | `gitlab_#{ENV['RAILS_ENV']` | Yes -`GITLAB_DATABASE_USERNAME` | `root` | Yes -`GITLAB_DATABASE_PASSWORD` | None | Yes -`GITLAB_DATABASE_HOST` | `localhost` | Yes -`GITLAB_DATABASE_PORT` | `5432` | Yes -`GITLAB_DATABASE_ENCODING` | `unicode` | No -`GITLAB_DATABASE_POOL` | `10` | No +-------- | ------------- | ----------------------------- +`GITLAB_DATABASE_ADAPTER` | `postgresql` (for MySQL use `mysql2`) | Yes +`GITLAB_DATABASE_DATABASE` | `gitlab_#{ENV['RAILS_ENV']` | Yes +`GITLAB_DATABASE_USERNAME` | `root` | Yes +`GITLAB_DATABASE_PASSWORD` | None | Yes +`GITLAB_DATABASE_HOST` | `localhost` | Yes +`GITLAB_DATABASE_PORT` | `5432` | Yes +`GITLAB_DATABASE_ENCODING` | `unicode` | No +`GITLAB_DATABASE_POOL` | `10` | No ## Adding more variables We welcome merge requests to make more settings configurable via variables. -Please make changes in the `config/initializers/1_settings.rb` file. -Please stick to the naming scheme `GITLAB_#{name in 1_settings.rb in upper case}`. +Please make changes in the `config/initializers/1_settings.rb` file and stick +to the naming scheme `GITLAB_#{name in 1_settings.rb in upper case}`. ## Omnibus configuration -It's possible to preconfigure the GitLab image by adding the environment variable: `GITLAB_OMNIBUS_CONFIG` to docker run command. +It's possible to preconfigure the GitLab docker image by adding the environment +variable `GITLAB_OMNIBUS_CONFIG` to the `docker run` command. For more information see the ['preconfigure-docker-container' section in the Omnibus documentation](http://doc.gitlab.com/omnibus/docker/#preconfigure-docker-container). -- cgit v1.2.1 From 9fbe9d97ed29288d065232687023edd74649d553 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Wed, 3 Feb 2016 14:18:51 +0200 Subject: Unicorn worker killer is not Omnibus specific [ci skip] --- doc/administration/environment_variables.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/administration/environment_variables.md b/doc/administration/environment_variables.md index e49b3dc139b..43ab153d76d 100644 --- a/doc/administration/environment_variables.md +++ b/doc/administration/environment_variables.md @@ -20,8 +20,8 @@ Variable | Type | Description `GITLAB_EMAIL_FROM` | string | The e-mail address used in the "From" field in e-mails sent by GitLab `GITLAB_EMAIL_DISPLAY_NAME` | string | The name used in the "From" field in e-mails sent by GitLab `GITLAB_EMAIL_REPLY_TO` | string | The e-mail address used in the "Reply-To" field in e-mails sent by GitLab -`GITLAB_UNICORN_MEMORY_MIN` | integer | The minimum memory threshold (in bytes) for the Unicorn worker killer (supported only in Omnibus) -`GITLAB_UNICORN_MEMORY_MAX` | integer | The maximum memory threshold (in bytes) for the Unicorn worker killer (supported only in Omnibus) +`GITLAB_UNICORN_MEMORY_MIN` | integer | The minimum memory threshold (in bytes) for the Unicorn worker killer +`GITLAB_UNICORN_MEMORY_MAX` | integer | The maximum memory threshold (in bytes) for the Unicorn worker killer ## Complete database variables -- cgit v1.2.1 From 531767175f0a364a332c74bf27c5f202732ce519 Mon Sep 17 00:00:00 2001 From: Josh Frye Date: Wed, 3 Feb 2016 09:21:37 -0500 Subject: Remove newrelic gem. Closes #12860 --- Gemfile | 2 -- Gemfile.lock | 2 -- config/newrelic.yml | 16 ---------------- 3 files changed, 20 deletions(-) delete mode 100644 config/newrelic.yml diff --git a/Gemfile b/Gemfile index 16a02da5bf9..a8f3619782d 100644 --- a/Gemfile +++ b/Gemfile @@ -303,8 +303,6 @@ group :production do gem "gitlab_meta", '7.0' end -gem "newrelic_rpm", '~> 3.14' - gem 'octokit', '~> 3.8.0' gem "mail_room", "~> 0.6.1" diff --git a/Gemfile.lock b/Gemfile.lock index 62937ab6fd2..6dd8b56fe7f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -479,7 +479,6 @@ GEM net-ldap (0.12.1) net-ssh (3.0.1) netrc (0.11.0) - newrelic_rpm (3.14.1.311) nokogiri (1.6.7.2) mini_portile2 (~> 2.0.0.rc2) nprogress-rails (0.1.6.7) @@ -960,7 +959,6 @@ DEPENDENCIES mysql2 (~> 0.3.16) nested_form (~> 0.3.2) net-ssh (~> 3.0.1) - newrelic_rpm (~> 3.14) nokogiri (= 1.6.7.2) nprogress-rails (~> 0.1.6.7) oauth2 (~> 1.0.0) diff --git a/config/newrelic.yml b/config/newrelic.yml deleted file mode 100644 index 9ef922a38d9..00000000000 --- a/config/newrelic.yml +++ /dev/null @@ -1,16 +0,0 @@ -# New Relic configuration file -# -# This file is here to make sure the New Relic gem stays -# quiet by default. -# -# To enable and configure New Relic, please use -# environment variables, e.g. NEW_RELIC_ENABLED=true - -production: - enabled: false - -development: - enabled: false - -test: - enabled: false -- cgit v1.2.1 From 7aa739ddc720dcba42a2f54934b10f369d4cf566 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 20 Jan 2016 12:00:28 -0800 Subject: Support download access by PRIVATE-TOKEN header Currently there is no way to download a raw file without embedding the token in the URL, which exposes the token in the URL. There should be an way of sending this information via the header as the API does. Closes https://github.com/gitlabhq/gitlabhq/issues/8137 --- CHANGELOG | 1 + app/controllers/application_controller.rb | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 7d7154487ad..4c9b00084d5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ v 8.5.0 (unreleased) - Add "visibility" flag to GET /projects api endpoint - Ignore binary files in code search to prevent Error 500 (Stan Hu) - Render sanitized SVG images (Stan Hu) + - Support download access by PRIVATE-TOKEN header (Stan Hu) - Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push - New UI for pagination - Don't prevent sign out when 2FA enforcement is enabled and user hasn't yet diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 824175c8a6c..7fa2f68ef07 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -60,6 +60,8 @@ class ApplicationController < ActionController::Base params[:authenticity_token].presence elsif params[:private_token].presence params[:private_token].presence + elsif request.headers['PRIVATE-TOKEN'].present? + request.headers['PRIVATE-TOKEN'] end user = user_token && User.find_by_authentication_token(user_token.to_s) -- cgit v1.2.1 From 639b25e34caa27191dc190c62b8d9ad59f9624ff Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 2 Feb 2016 23:31:46 +0100 Subject: Improve UI consistency between projects and groups lists Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 1 + app/assets/stylesheets/pages/groups.scss | 20 +++++++++++++++++++- app/views/dashboard/_groups_head.html.haml | 20 +++++++++++++------- app/views/dashboard/groups/index.html.haml | 9 --------- app/views/shared/groups/_group.html.haml | 19 ++++++++++++++++--- 5 files changed, 49 insertions(+), 20 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7d7154487ad..994e7a35b5f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -25,6 +25,7 @@ v 8.5.0 (unreleased) - Deprecate API "merge_request/:merge_request_id/...". Use "merge_requests/:merge_request_id/..." instead - Mark inline difference between old and new paths when a file is renamed - Support Akismet spam checking for creation of issues via API (Stan Hu) + - Improve UI consistency between projects and groups lists v 8.4.3 - Increase lfs_objects size column to 8-byte integer to allow files larger diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index fdd86979a36..ec6c099df5b 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -4,7 +4,7 @@ input[type='search'] { width: 225px; vertical-align: bottom; - + @media (max-width: $screen-xs-max) { width: 100px; vertical-align: bottom; @@ -21,3 +21,21 @@ height: 42px; } } + +.group-row { + &.no-description { + .group-name { + line-height: 44px; + } + } + + .stats { + float: right; + line-height: 44px; + color: $gl-gray; + + span { + margin-right: 15px; + } + } +} diff --git a/app/views/dashboard/_groups_head.html.haml b/app/views/dashboard/_groups_head.html.haml index 6ca97a692b4..15e423a3b29 100644 --- a/app/views/dashboard/_groups_head.html.haml +++ b/app/views/dashboard/_groups_head.html.haml @@ -1,7 +1,13 @@ -%ul.nav-links - = nav_link(page: dashboard_groups_path) do - = link_to dashboard_groups_path, title: 'Your groups', data: {placement: 'right'} do - Your Groups - = nav_link(page: explore_groups_path) do - = link_to explore_groups_path, title: 'Explore groups', data: {placement: 'bottom'} do - Explore Groups +.top-area + %ul.nav-links + = nav_link(page: dashboard_groups_path) do + = link_to dashboard_groups_path, title: 'Your groups', data: {placement: 'right'} do + Your Groups + = nav_link(page: explore_groups_path) do + = link_to explore_groups_path, title: 'Explore groups', data: {placement: 'bottom'} do + Explore Groups + - if current_user.can_create_group? + .projects-search-form + = link_to new_group_path, class: "btn btn-new" do + = icon('plus') + New Group diff --git a/app/views/dashboard/groups/index.html.haml b/app/views/dashboard/groups/index.html.haml index d5b7e729e7b..caca91af536 100644 --- a/app/views/dashboard/groups/index.html.haml +++ b/app/views/dashboard/groups/index.html.haml @@ -2,15 +2,6 @@ - header_title "Groups", dashboard_groups_path = render 'dashboard/groups_head' -.gray-content-block - - if current_user.can_create_group? - %span.pull-right.hidden-xs - = link_to new_group_path, class: "btn btn-new" do - %i.fa.fa-plus - New Group - .oneline - Group members have access to all group projects. - %ul.content-list - @group_members.each do |group_member| - group = group_member.group diff --git a/app/views/shared/groups/_group.html.haml b/app/views/shared/groups/_group.html.haml index 778b20fb4f2..aa2ece22485 100644 --- a/app/views/shared/groups/_group.html.haml +++ b/app/views/shared/groups/_group.html.haml @@ -1,5 +1,8 @@ - group_member = local_assigns[:group_member] -%li +- css_class = '' unless local_assigns[:css_class] +- css_class += " no-description" if group.description.blank? + +%li.group-row{ class: css_class } - if group_member .controls.hidden-xs - if can?(current_user, :admin_group, group) @@ -9,6 +12,15 @@ = link_to leave_group_group_members_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-sm btn btn-grouped", title: 'Leave this group' do %i.fa.fa-sign-out + .stats + %span + = icon('home') + = group.projects.count + + %span + = icon('users') + = group.users.count + = image_tag group_icon(group), class: "avatar s46 hidden-xs" = link_to group, class: 'group-name' do %span.item-title= group.name @@ -17,5 +29,6 @@ as %span #{group_member.human_access} - %div.light - #{pluralize(group.projects.count, "project")}, #{pluralize(group.users.count, "user")} + - if group.description.present? + .light + = markdown(group.description, pipeline: :description) -- cgit v1.2.1 From df922d811520f2b6459e84f1e595d3a0fcfc395c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Feb 2016 00:07:11 +0100 Subject: Add number_with_delimiter and remove unnecessary dara placement for groups page Signed-off-by: Dmitriy Zaporozhets --- app/views/dashboard/_groups_head.html.haml | 4 ++-- app/views/shared/groups/_group.html.haml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/dashboard/_groups_head.html.haml b/app/views/dashboard/_groups_head.html.haml index 15e423a3b29..e52070704d9 100644 --- a/app/views/dashboard/_groups_head.html.haml +++ b/app/views/dashboard/_groups_head.html.haml @@ -1,10 +1,10 @@ .top-area %ul.nav-links = nav_link(page: dashboard_groups_path) do - = link_to dashboard_groups_path, title: 'Your groups', data: {placement: 'right'} do + = link_to dashboard_groups_path, title: 'Your groups' do Your Groups = nav_link(page: explore_groups_path) do - = link_to explore_groups_path, title: 'Explore groups', data: {placement: 'bottom'} do + = link_to explore_groups_path, title: 'Explore groups' do Explore Groups - if current_user.can_create_group? .projects-search-form diff --git a/app/views/shared/groups/_group.html.haml b/app/views/shared/groups/_group.html.haml index aa2ece22485..f7fe6b02641 100644 --- a/app/views/shared/groups/_group.html.haml +++ b/app/views/shared/groups/_group.html.haml @@ -15,11 +15,11 @@ .stats %span = icon('home') - = group.projects.count + = number_with_delimiter(group.projects.count) %span = icon('users') - = group.users.count + = number_with_delimiter(group.users.count) = image_tag group_icon(group), class: "avatar s46 hidden-xs" = link_to group, class: 'group-name' do -- cgit v1.2.1 From 4beae990b37e3583485bb33f03e08e3cc798ff37 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Feb 2016 01:08:30 +0100 Subject: Refactor nav controls section (search and new project/group btn) Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/buttons.scss | 8 +-- app/assets/stylesheets/framework/nav.scss | 62 +++++++++++++++++++ app/assets/stylesheets/pages/projects.scss | 88 +-------------------------- app/views/dashboard/_groups_head.html.haml | 2 +- app/views/dashboard/_projects_head.html.haml | 6 +- app/views/groups/_projects.html.haml | 17 +++--- app/views/projects/forks/index.html.haml | 64 ++++++++++--------- 7 files changed, 107 insertions(+), 140 deletions(-) diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index c99292c3f83..11df4c24056 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -82,8 +82,7 @@ &.btn-success, &.btn-new, &.btn-create, - &.btn-save, - &.btn-green { + &.btn-save { @include btn-green; } @@ -159,7 +158,6 @@ .input-group-btn { .btn { - @include btn-gray; @include btn-middle; &:hover { @@ -186,8 +184,4 @@ border: 1px solid #c6cacf !important; background-color: #e4e7ed !important; } - - .btn-green { - @include btn-green - } } diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index c537d97fb24..1d042dfb439 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -37,3 +37,65 @@ } } } + +.top-area { + border-bottom: 1px solid #EEE; + + .nav-text { + padding-top: 16px; + padding-bottom: 11px; + display: inline-block; + width: 50%; + line-height: 28px; + } + + .nav-links { + display: inline-block; + width: 50%; + margin-bottom: 0px; + border-bottom: none; + } + + .nav-controls { + width: 50%; + display: inline-block; + float: right; + text-align: right; + padding: 11px 0; + margin-bottom: 0px; + + > .dropdown { + display: inline-block; + } + + input { + display: inline-block; + width: calc(100% - 151px); + + /* Small devices (tablets, 768px and up) */ + @media (min-width: $screen-sm-min) { width: 150px; } + + /* Medium devices (desktops, 992px and up) */ + @media (min-width: $screen-md-min) { width: 200px; } + + /* Large devices (large desktops, 1200px and up) */ + @media (min-width: $screen-lg-min) { width: 300px; } + } + + .btn-new { + width: 135px; + margin-left: 10px; + float: right; + } + + .dropdown-toggle.btn { + margin-top: -3px; + } + } + + @media (max-width: $screen-xs-max) { + .nav-controls { + padding-top: 15px; + } + } +} diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index e4ea47cc4a2..3d88746ddf7 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -281,36 +281,6 @@ margin-top: -1px; } -.top-area { - border-bottom: 1px solid #EEE; - - ul.nav-links { - display: inline-block; - width: 50%; - margin-bottom: 0px; - border-bottom: none; - } - - .projects-search-form { - width: 50%; - display: inline-block; - float: right; - padding-top: 11px; - text-align: right; - - .btn-green { - margin-left: 10px; - float: right; - } - } - - @media (max-width: $screen-xs-max) { - .projects-search-form { - padding-top: 15px; - } - } -} - .fork-namespaces { .fork-thumbnail { text-align: center; @@ -386,22 +356,6 @@ pre.light-well { border-color: #f1f1f1; } -.projects-search-form { - padding: $gl-padding 0; - padding-bottom: 0; - margin-bottom: 0px; - - input { - display: inline-block; - width: calc(100% - 151px); - } - - .btn { - display: inline-block; - width: 135px; - } -} - .git-empty { margin: 0 7px 0 7px; @@ -559,52 +513,12 @@ pre.light-well { } } -.cannot-be-merged, +.cannot-be-merged, .cannot-be-merged:hover { color: #E62958; margin-top: 2px; } -/* - * Forks list rendered on Project's forks page - */ - -.forks-top-block { - padding: 16px 0; -} - -.projects-search-form { - .dropdown-toggle.btn { - margin-top: -3px; - } - - &.fork-search-form { - margin: 0; - margin-top: -$gl-padding; - padding-bottom: 0; - - input { - /* Small devices (tablets, 768px and up) */ - @media (min-width: $screen-sm-min) { width: 180px; } - - /* Medium devices (desktops, 992px and up) */ - @media (min-width: $screen-md-min) { width: 350px; } - - /* Large devices (large desktops, 1200px and up) */ - @media (min-width: $screen-lg-min) { width: 400px; } - } - - .sort-forks { - width: 160px; - } - - .fork-link { - float: right; - margin-left: $gl-padding; - } - } -} - .private-forks-notice .private-fork-icon { i:nth-child(1) { color: #2AA056; diff --git a/app/views/dashboard/_groups_head.html.haml b/app/views/dashboard/_groups_head.html.haml index e52070704d9..3d17f74b709 100644 --- a/app/views/dashboard/_groups_head.html.haml +++ b/app/views/dashboard/_groups_head.html.haml @@ -7,7 +7,7 @@ = link_to explore_groups_path, title: 'Explore groups' do Explore Groups - if current_user.can_create_group? - .projects-search-form + .nav-controls = link_to new_group_path, class: "btn btn-new" do = icon('plus') New Group diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml index 5c4b58cd688..b6301f2238f 100644 --- a/app/views/dashboard/_projects_head.html.haml +++ b/app/views/dashboard/_projects_head.html.haml @@ -12,9 +12,9 @@ = link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do Explore Projects - .projects-search-form + .nav-controls = search_field_tag :filter_projects, nil, placeholder: 'Filter by name...', class: 'projects-list-filter form-control hidden-xs', spellcheck: false - if current_user.can_create_project? - = link_to new_project_path, class: 'btn btn-green' do - %i.fa.fa-plus + = link_to new_project_path, class: 'btn btn-new' do + = icon('plus') New Project diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml index bbafc08435a..a829479bb38 100644 --- a/app/views/groups/_projects.html.haml +++ b/app/views/groups/_projects.html.haml @@ -1,11 +1,10 @@ -.projects-list-holder - .projects-search-form - .input-group - = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false - - if can? current_user, :create_projects, @group - %span.input-group-btn - = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-green' do - %i.fa.fa-plus - New Project +.projects-list-holder.prepend-top-default + .input-group + = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false + - if can? current_user, :create_projects, @group + %span.input-group-btn + = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new' do + = icon('plus') + New Project = render 'shared/projects/list', projects: @projects, projects_limit: 20, stars: false, skip_namespace: true diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml index a362185210a..3fa7155bab7 100644 --- a/app/views/projects/forks/index.html.haml +++ b/app/views/projects/forks/index.html.haml @@ -1,44 +1,42 @@ -.gray-content-block.top-block.clearfix.white.forks-top-block - .pull-left +.top-area + .nav-text - public_count = @public_forks.size - protected_count = @protected_forks.size - full_count_title = "#{public_count} public and #{protected_count} private" == #{pluralize(@all_forks.size, 'fork')}: #{full_count_title} - .pull-right - .projects-search-form.fork-search-form - = search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter form-control', - spellcheck: false, data: { 'filter-selector' => 'span.namespace-name' } + .nav-controls + = search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter form-control', + spellcheck: false, data: { 'filter-selector' => 'span.namespace-name' } - .dropdown.inline.prepend-left-10 - %button.dropdown-toggle.btn.sort-forks{type: 'button', 'data-toggle' => 'dropdown'} - %span.light sort: - - if @sort.present? - = sort_options_hash[@sort] - - else + .dropdown.prepend-left-10 + %button.dropdown-toggle.btn.sort-forks{type: 'button', 'data-toggle' => 'dropdown'} + %span.light sort: + - if @sort.present? + = sort_options_hash[@sort] + - else + = sort_title_recently_created + %b.caret + %ul.dropdown-menu.dropdown-menu-align-right + %li + - excluded_filters = [:state, :scope, :label_name, :milestone_id, :assignee_id, :author_id] + = link_to page_filter_path(sort: sort_value_recently_created, without: excluded_filters) do = sort_title_recently_created - %b.caret - %ul.dropdown-menu.dropdown-menu-align-right - %li - - excluded_filters = [:state, :scope, :label_name, :milestone_id, :assignee_id, :author_id] - = link_to page_filter_path(sort: sort_value_recently_created, without: excluded_filters) do - = sort_title_recently_created - = link_to page_filter_path(sort: sort_value_oldest_created, without: excluded_filters) do - = sort_title_oldest_created - = link_to page_filter_path(sort: sort_value_recently_updated, without: excluded_filters) do - = sort_title_recently_updated - = link_to page_filter_path(sort: sort_value_oldest_updated, without: excluded_filters) do - = sort_title_oldest_updated + = link_to page_filter_path(sort: sort_value_oldest_created, without: excluded_filters) do + = sort_title_oldest_created + = link_to page_filter_path(sort: sort_value_recently_updated, without: excluded_filters) do + = sort_title_recently_updated + = link_to page_filter_path(sort: sort_value_oldest_updated, without: excluded_filters) do + = sort_title_oldest_updated - .fork-link.inline - - if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2 - = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'pull-right btn btn-new' do - = icon('code-fork fw') - Fork - - else - = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'pull-right btn btn-new' do - = icon('code-fork fw') - Fork + - if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2 + = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn btn-new' do + = icon('code-fork fw') + Fork + - else + = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn btn-new' do + = icon('code-fork fw') + Fork .projects-list-holder -- cgit v1.2.1 From ad5acec6e5aa1376e5711cdac531db8f9cca3d01 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Feb 2016 01:50:53 +0100 Subject: Make nav-controls responsive and hide on extra small screens Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/nav.scss | 54 +++++++++++++++++++++++-------- app/views/projects/forks/index.html.haml | 4 +-- 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index 1d042dfb439..6410656847f 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -39,6 +39,8 @@ } .top-area { + @include clearfix; + border-bottom: 1px solid #EEE; .nav-text { @@ -47,6 +49,11 @@ display: inline-block; width: 50%; line-height: 28px; + + /* Small devices (phones, tablets, 768px and lower) */ + @media (max-width: $screen-sm-min) { + width: 100%; + } } .nav-links { @@ -54,6 +61,11 @@ width: 50%; margin-bottom: 0px; border-bottom: none; + + /* Small devices (phones, tablets, 768px and lower) */ + @media (max-width: $screen-sm-min) { + width: 100%; + } } .nav-controls { @@ -65,37 +77,51 @@ margin-bottom: 0px; > .dropdown { + margin-left: 10px; display: inline-block; } - input { + > .btn { display: inline-block; - width: calc(100% - 151px); + margin-left: 10px; + margin-top: -3px; + } - /* Small devices (tablets, 768px and up) */ - @media (min-width: $screen-sm-min) { width: 150px; } + input { + display: inline-block; /* Medium devices (desktops, 992px and up) */ @media (min-width: $screen-md-min) { width: 200px; } /* Large devices (large desktops, 1200px and up) */ - @media (min-width: $screen-lg-min) { width: 300px; } - } + @media (min-width: $screen-lg-min) { width: 250px; } - .btn-new { - width: 135px; - margin-left: 10px; - float: right; + &.input-short { + /* Medium devices (desktops, 992px and up) */ + @media (min-width: $screen-md-min) { width: 170px; } + + /* Large devices (large desktops, 1200px and up) */ + @media (min-width: $screen-lg-min) { width: 210px; } + } } .dropdown-toggle.btn { margin-top: -3px; } - } - @media (max-width: $screen-xs-max) { - .nav-controls { - padding-top: 15px; + /* Hide on extra small devices (phones) */ + @media (max-width: $screen-xs-max) { + display: none; + } + + /* Small devices (tablets, 768px and lower) */ + @media (max-width: $screen-sm-max) { + width: 100%; + text-align: left; + + input { + width: 300px; + } } } } diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml index 3fa7155bab7..acb2353d3ca 100644 --- a/app/views/projects/forks/index.html.haml +++ b/app/views/projects/forks/index.html.haml @@ -6,10 +6,10 @@ == #{pluralize(@all_forks.size, 'fork')}: #{full_count_title} .nav-controls - = search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter form-control', + = search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter form-control input-short', spellcheck: false, data: { 'filter-selector' => 'span.namespace-name' } - .dropdown.prepend-left-10 + .dropdown %button.dropdown-toggle.btn.sort-forks{type: 'button', 'data-toggle' => 'dropdown'} %span.light sort: - if @sort.present? -- cgit v1.2.1 From faacb7853478704a37655361c23abffdfd47db6f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Feb 2016 02:01:33 +0100 Subject: Tried to align form input vertically with other elements for top nav Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/nav.scss | 8 +++----- app/views/dashboard/_projects_head.html.haml | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index 6410656847f..252f84a6b48 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -84,11 +84,13 @@ > .btn { display: inline-block; margin-left: 10px; - margin-top: -3px; } input { + height: 34px; display: inline-block; + position: relative; + top: 1px; /* Medium devices (desktops, 992px and up) */ @media (min-width: $screen-md-min) { width: 200px; } @@ -105,10 +107,6 @@ } } - .dropdown-toggle.btn { - margin-top: -3px; - } - /* Hide on extra small devices (phones) */ @media (max-width: $screen-xs-max) { display: none; diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml index b6301f2238f..726f669b1d2 100644 --- a/app/views/dashboard/_projects_head.html.haml +++ b/app/views/dashboard/_projects_head.html.haml @@ -8,7 +8,7 @@ = nav_link(page: starred_dashboard_projects_path) do = link_to starred_dashboard_projects_path, title: 'Starred Projects', data: {placement: 'right'} do Starred Projects - = nav_link(page: [explore_root_path, trending_explore_projects_path, starred_explore_projects_path, explore_projects_path], html_options: { class: 'hidden-xs' }) do + = nav_link(page: [explore_root_path, trending_explore_projects_path, starred_explore_projects_path, explore_projects_path]) do = link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do Explore Projects -- cgit v1.2.1 From 754538b99206a778ddf87e0d362fccb0ff2f6c15 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Feb 2016 02:10:33 +0100 Subject: Use right margin for componened other than button for top nav Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/nav.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index 252f84a6b48..e6c59f5a291 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -77,13 +77,12 @@ margin-bottom: 0px; > .dropdown { - margin-left: 10px; + margin-right: 10px; display: inline-block; } > .btn { display: inline-block; - margin-left: 10px; } input { @@ -91,6 +90,7 @@ display: inline-block; position: relative; top: 1px; + margin-right: 10px; /* Medium devices (desktops, 992px and up) */ @media (min-width: $screen-md-min) { width: 200px; } -- cgit v1.2.1 From ea7bdc78eed8db7ff4b5440b282678b1c5b021f7 Mon Sep 17 00:00:00 2001 From: Patricio Cano Date: Wed, 3 Feb 2016 11:17:14 -0500 Subject: Updated omniuath-saml to the latest version. --- Gemfile | 2 +- Gemfile.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 16a02da5bf9..a06dbe8e061 100644 --- a/Gemfile +++ b/Gemfile @@ -30,7 +30,7 @@ gem 'omniauth-github', '~> 1.1.1' gem 'omniauth-gitlab', '~> 1.0.0' gem 'omniauth-google-oauth2', '~> 0.2.0' gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos -gem 'omniauth-saml', '~> 1.4.0' +gem 'omniauth-saml', '~> 1.4.2' gem 'omniauth-shibboleth', '~> 1.2.0' gem 'omniauth-twitter', '~> 1.2.0' gem 'omniauth_crowd', '~> 2.2.0' diff --git a/Gemfile.lock b/Gemfile.lock index 62937ab6fd2..bd767016108 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -532,9 +532,9 @@ GEM omniauth-oauth2 (1.3.1) oauth2 (~> 1.0) omniauth (~> 1.2) - omniauth-saml (1.4.1) + omniauth-saml (1.4.2) omniauth (~> 1.1) - ruby-saml (~> 1.0.0) + ruby-saml (~> 1.1, >= 1.1.1) omniauth-shibboleth (1.2.1) omniauth (>= 1.0.0) omniauth-twitter (1.2.1) @@ -690,7 +690,7 @@ GEM ruby-fogbugz (0.2.1) crack (~> 0.4) ruby-progressbar (1.7.5) - ruby-saml (1.0.0) + ruby-saml (1.1.1) nokogiri (>= 1.5.10) uuid (~> 2.3) ruby2ruby (2.2.0) @@ -974,7 +974,7 @@ DEPENDENCIES omniauth-gitlab (~> 1.0.0) omniauth-google-oauth2 (~> 0.2.0) omniauth-kerberos (~> 0.3.0) - omniauth-saml (~> 1.4.0) + omniauth-saml (~> 1.4.2) omniauth-shibboleth (~> 1.2.0) omniauth-twitter (~> 1.2.0) omniauth_crowd (~> 2.2.0) -- cgit v1.2.1 From 6f8ae85567a360deafc6390e2a9ada6513a89fa3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Feb 2016 18:05:58 +0100 Subject: Fix missing space between fork and star icons Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/pages/projects.scss | 4 ++++ app/views/shared/projects/_project.html.haml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 3d88746ddf7..dd4ff39c5b8 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -415,6 +415,10 @@ pre.light-well { a:hover { text-decoration: none; } + + > span { + margin-left: 10px; + } } .project-description { diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml index 2aeeed63c95..e196fc51d2d 100644 --- a/app/views/shared/projects/_project.html.haml +++ b/app/views/shared/projects/_project.html.haml @@ -29,8 +29,8 @@ .project-controls - if ci_commit - = render_ci_status(ci_commit) -   + %span + = render_ci_status(ci_commit) - if forks %span = icon('code-fork') -- cgit v1.2.1 From 8cd25901d3de83d7d03c33361a61308effa13760 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Feb 2016 18:41:55 +0100 Subject: Use top-area component for top page navigation for pages that contains list of items Signed-off-by: Dmitriy Zaporozhets --- app/views/dashboard/milestones/index.html.haml | 8 ++++---- app/views/groups/milestones/index.html.haml | 16 +++++++--------- app/views/help/ui.html.haml | 24 ++++++++++++++++++++++++ app/views/projects/builds/index.html.haml | 23 +++++++++++------------ app/views/projects/labels/index.html.haml | 13 +++++++------ app/views/projects/milestones/index.html.haml | 12 ++++++------ app/views/projects/wikis/_nav.html.haml | 18 +++++++++--------- app/views/shared/_milestones_filter.html.haml | 21 ++++++++++----------- 8 files changed, 78 insertions(+), 57 deletions(-) diff --git a/app/views/dashboard/milestones/index.html.haml b/app/views/dashboard/milestones/index.html.haml index bec1692a4de..2ee167db911 100644 --- a/app/views/dashboard/milestones/index.html.haml +++ b/app/views/dashboard/milestones/index.html.haml @@ -1,12 +1,12 @@ - page_title "Milestones" - header_title "Milestones", dashboard_milestones_path -.project-issuable-filter - .controls - = render 'shared/new_project_item_select', path: 'milestones/new', label: "New Milestone", include_groups: true - +.top-area = render 'shared/milestones_filter' + .nav-controls + = render 'shared/new_project_item_select', path: 'milestones/new', label: "New Milestone", include_groups: true + .gray-content-block List all milestones from all projects you have access to. diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml index b221d3a89a4..ab307708b75 100644 --- a/app/views/groups/milestones/index.html.haml +++ b/app/views/groups/milestones/index.html.haml @@ -1,17 +1,15 @@ - page_title "Milestones" - header_title group_title(@group, "Milestones", group_milestones_path(@group)) -.project-issuable-filter - .controls - - if can?(current_user, :admin_milestones, @group) - .pull-right - %span.pull-right.hidden-xs - = link_to new_group_milestone_path(@group), class: "btn btn-new" do - = icon('plus') - New Milestone - +.top-area = render 'shared/milestones_filter' + .nav-controls + - if can?(current_user, :admin_milestones, @group) + = link_to new_group_milestone_path(@group), class: "btn btn-new" do + = icon('plus') + New Milestone + .gray-content-block Only milestones from %strong #{@group.name} diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index 7b45bd09050..746386cab58 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -138,8 +138,32 @@ %h2#navs Navigation + %h4 + %code .top-area + %p Holder for top page navigation. Includes navigation, search field, sorting and button + + .example + .top-area + %ul.nav-links + %li.active + %a Open + %li + %a Closed + .nav-controls + = text_field_tag 'sample', nil, class: 'form-control' + .dropdown + %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} + %span Sort by name + %b.caret + %ul.dropdown-menu + %li + %a Sort by date + + = link_to 'New issue', '#', class: 'btn btn-new' + %h4 %code .nav-links + %p Only nav links without button and search .example %ul.nav-links %li.active diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml index bbb6944a65a..630d0286f25 100644 --- a/app/views/projects/builds/index.html.haml +++ b/app/views/projects/builds/index.html.haml @@ -1,18 +1,7 @@ - page_title "Builds" = render "header_title" -.project-issuable-filter - .controls - - if can?(current_user, :manage_builds, @project) - .pull-left.hidden-xs - - if @all_builds.running_or_pending.any? - = link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project), - data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post - - = link_to ci_lint_path, class: 'btn btn-default' do - = icon('wrench') - %span CI Lint - +.top-area %ul.nav-links %li{class: ('active' if @scope.nil?)} = link_to project_builds_path(@project) do @@ -32,6 +21,16 @@ %span.badge.js-running-count = number_with_delimiter(@all_builds.finished.count(:id)) + .nav-controls + - if can?(current_user, :manage_builds, @project) + - if @all_builds.running_or_pending.any? + = link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project), + data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post + + = link_to ci_lint_path, class: 'btn btn-default' do + = icon('wrench') + %span CI Lint + .gray-content-block #{(@scope || 'running').capitalize} builds from this project diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml index 9081bcfe9b3..cc41130a9dc 100644 --- a/app/views/projects/labels/index.html.haml +++ b/app/views/projects/labels/index.html.haml @@ -1,13 +1,14 @@ - page_title "Labels" = render "header_title" -.gray-content-block.top-block - - if can? current_user, :admin_label, @project - = link_to new_namespace_project_label_path(@project.namespace, @project), class: "pull-right btn btn-new" do - = icon('plus') - New label - .oneline +.top-area + .nav-text Labels can be applied to issues and merge requests. + .nav-controls + - if can? current_user, :admin_label, @project + = link_to new_namespace_project_label_path(@project.namespace, @project), class: "btn btn-new" do + = icon('plus') + New label .labels - if @labels.present? diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml index 114b06457a5..49625b3534b 100644 --- a/app/views/projects/milestones/index.html.haml +++ b/app/views/projects/milestones/index.html.haml @@ -2,15 +2,15 @@ = render "header_title" -.project-issuable-filter - .controls +.top-area + = render 'shared/milestones_filter' + + .nav-controls - if can?(current_user, :admin_milestone, @project) - = link_to new_namespace_project_milestone_path(@project.namespace, @project), class: "pull-right btn btn-new", title: "New Milestone" do - %i.fa.fa-plus + = link_to new_namespace_project_milestone_path(@project.namespace, @project), class: "btn btn-new", title: "New Milestone" do + = icon('plus') New Milestone - = render 'shared/milestones_filter' - .gray-content-block Milestone allows you to group issues and set due date for it diff --git a/app/views/projects/wikis/_nav.html.haml b/app/views/projects/wikis/_nav.html.haml index 69ba301e231..56a53ffff2a 100644 --- a/app/views/projects/wikis/_nav.html.haml +++ b/app/views/projects/wikis/_nav.html.haml @@ -1,12 +1,4 @@ -.project-issuable-filter - .controls - - if can?(current_user, :create_wiki, @project) - = link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do - %i.fa.fa-plus - New Page - - = render 'projects/wikis/new' - +.top-area %ul.nav-links = nav_link(html_options: {class: params[:id] == 'home' ? 'active' : '' }) do = link_to 'Home', namespace_project_wiki_path(@project.namespace, @project, :home) @@ -17,3 +9,11 @@ = nav_link(path: 'wikis#git_access') do = link_to namespace_project_wikis_git_access_path(@project.namespace, @project) do Git Access + + .nav-controls + - if can?(current_user, :create_wiki, @project) + = link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do + = icon('plus') + New Page + + = render 'projects/wikis/new' diff --git a/app/views/shared/_milestones_filter.html.haml b/app/views/shared/_milestones_filter.html.haml index f77feeb79cd..cf16c203f9c 100644 --- a/app/views/shared/_milestones_filter.html.haml +++ b/app/views/shared/_milestones_filter.html.haml @@ -1,11 +1,10 @@ -.milestones-filters - %ul.nav-links - %li{class: ("active" if params[:state].blank? || params[:state] == 'opened')} - = link_to milestones_filter_path(state: 'opened') do - Open - %li{class: ("active" if params[:state] == 'closed')} - = link_to milestones_filter_path(state: 'closed') do - Closed - %li{class: ("active" if params[:state] == 'all')} - = link_to milestones_filter_path(state: 'all') do - All +%ul.nav-links + %li{class: ("active" if params[:state].blank? || params[:state] == 'opened')} + = link_to milestones_filter_path(state: 'opened') do + Open + %li{class: ("active" if params[:state] == 'closed')} + = link_to milestones_filter_path(state: 'closed') do + Closed + %li{class: ("active" if params[:state] == 'all')} + = link_to milestones_filter_path(state: 'all') do + All -- cgit v1.2.1 From a441658783c5cdcda64f4cbd55ffabe24b646b46 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Feb 2016 18:51:52 +0100 Subject: Remove useless text tips on commonly used pages Signed-off-by: Dmitriy Zaporozhets --- app/views/dashboard/issues.html.haml | 3 --- app/views/dashboard/merge_requests.html.haml | 3 --- app/views/dashboard/milestones/index.html.haml | 3 --- app/views/projects/milestones/index.html.haml | 3 --- 4 files changed, 12 deletions(-) diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml index 2d3da01178a..f363f035974 100644 --- a/app/views/dashboard/issues.html.haml +++ b/app/views/dashboard/issues.html.haml @@ -16,8 +16,5 @@ = render 'shared/issuable/filter', type: :issues -.gray-content-block.second-block - List all issues from all projects you have access to. - .prepend-top-default = render 'shared/issues' diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml index c5a5ec21f78..bbe4cc1f824 100644 --- a/app/views/dashboard/merge_requests.html.haml +++ b/app/views/dashboard/merge_requests.html.haml @@ -7,8 +7,5 @@ = render 'shared/issuable/filter', type: :merge_requests -.gray-content-block.second-block - List all merge requests from all projects you have access to. - .prepend-top-default = render 'shared/merge_requests' diff --git a/app/views/dashboard/milestones/index.html.haml b/app/views/dashboard/milestones/index.html.haml index bec1692a4de..eb2979fc13e 100644 --- a/app/views/dashboard/milestones/index.html.haml +++ b/app/views/dashboard/milestones/index.html.haml @@ -7,9 +7,6 @@ = render 'shared/milestones_filter' -.gray-content-block - List all milestones from all projects you have access to. - .milestones %ul.content-list - if @milestones.blank? diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml index 114b06457a5..aa185126b56 100644 --- a/app/views/projects/milestones/index.html.haml +++ b/app/views/projects/milestones/index.html.haml @@ -11,9 +11,6 @@ = render 'shared/milestones_filter' -.gray-content-block - Milestone allows you to group issues and set due date for it - .milestones %ul.content-list = render @milestones -- cgit v1.2.1 From 73bd729ecca27a293c47101dd399e628e221ce2d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Feb 2016 20:13:26 +0100 Subject: Add sort dropdown to dashboard projects page Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 1 + app/assets/stylesheets/pages/explore.scss | 8 -------- app/controllers/dashboard/projects_controller.rb | 1 + app/helpers/explore_helper.rb | 13 ++++++++++++- app/views/dashboard/_projects_head.html.haml | 3 ++- app/views/explore/projects/_dropdown.html.haml | 12 +++--------- app/views/explore/projects/_filter.html.haml | 2 +- app/views/explore/projects/_nav.html.haml | 10 ++++++++++ app/views/explore/projects/index.html.haml | 6 +++++- app/views/explore/projects/starred.html.haml | 12 +++--------- app/views/explore/projects/trending.html.haml | 10 ++-------- 11 files changed, 40 insertions(+), 38 deletions(-) create mode 100644 app/views/explore/projects/_nav.html.haml diff --git a/CHANGELOG b/CHANGELOG index 5f081236c10..481a0f8d243 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,6 +27,7 @@ v 8.5.0 (unreleased) - Mark inline difference between old and new paths when a file is renamed - Support Akismet spam checking for creation of issues via API (Stan Hu) - Improve UI consistency between projects and groups lists + - Add sort dropdown to dashboard projects page v 8.4.3 - Increase lfs_objects size column to 8-byte integer to allow files larger diff --git a/app/assets/stylesheets/pages/explore.scss b/app/assets/stylesheets/pages/explore.scss index da06fe9954e..9b92128624c 100644 --- a/app/assets/stylesheets/pages/explore.scss +++ b/app/assets/stylesheets/pages/explore.scss @@ -6,11 +6,3 @@ font-size: 30px; } } - -.explore-trending-block { - .lead { - line-height: 32px; - font-size: 18px; - margin-top: 10px; - } -} diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb index 0b7fcdf5e9e..721e2a6bcbd 100644 --- a/app/controllers/dashboard/projects_controller.rb +++ b/app/controllers/dashboard/projects_controller.rb @@ -3,6 +3,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController def index @projects = current_user.authorized_projects.sorted_by_activity.non_archived + @projects = @projects.sort(@sort = params[:sort]) @projects = @projects.includes(:namespace) @last_push = current_user.recent_push diff --git a/app/helpers/explore_helper.rb b/app/helpers/explore_helper.rb index 0d291f9a87e..3648757428b 100644 --- a/app/helpers/explore_helper.rb +++ b/app/helpers/explore_helper.rb @@ -10,8 +10,19 @@ module ExploreHelper options = exist_opts.merge(options) - path = explore_projects_path + path = if explore_controller? + explore_projects_path + elsif current_action?(:starred) + starred_dashboard_projects_path + else + dashboard_projects_path + end + path << "?#{options.to_param}" path end + + def explore_controller? + controller.class.name.split("::").first == "Explore" + end end diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml index 726f669b1d2..d865a2c6fae 100644 --- a/app/views/dashboard/_projects_head.html.haml +++ b/app/views/dashboard/_projects_head.html.haml @@ -13,7 +13,8 @@ Explore Projects .nav-controls - = search_field_tag :filter_projects, nil, placeholder: 'Filter by name...', class: 'projects-list-filter form-control hidden-xs', spellcheck: false + = search_field_tag :filter_projects, nil, placeholder: 'Filter by name...', class: 'projects-list-filter form-control hidden-xs input-short', spellcheck: false + = render 'explore/projects/dropdown' - if current_user.can_create_project? = link_to new_project_path, class: 'btn btn-new' do = icon('plus') diff --git a/app/views/explore/projects/_dropdown.html.haml b/app/views/explore/projects/_dropdown.html.haml index a988d4c8154..87c556adc7d 100644 --- a/app/views/explore/projects/_dropdown.html.haml +++ b/app/views/explore/projects/_dropdown.html.haml @@ -3,19 +3,13 @@ %span.light - if @sort.present? = sort_options_hash[@sort] - - elsif current_page?(trending_explore_projects_path) || current_page?(explore_root_path) - Trending projects - - elsif current_page?(starred_explore_projects_path) - Most stars - else - = sort_title_recently_created + = sort_title_recently_updated %b.caret %ul.dropdown-menu %li - = link_to trending_explore_projects_path do - Trending projects - = link_to starred_explore_projects_path do - Most stars + = link_to explore_projects_filter_path(sort: sort_value_name) do + = sort_title_name = link_to explore_projects_filter_path(sort: sort_value_recently_created) do = sort_title_recently_created = link_to explore_projects_filter_path(sort: sort_value_oldest_created) do diff --git a/app/views/explore/projects/_filter.html.haml b/app/views/explore/projects/_filter.html.haml index 28b12c8dca8..66a4b535ae5 100644 --- a/app/views/explore/projects/_filter.html.haml +++ b/app/views/explore/projects/_filter.html.haml @@ -2,6 +2,7 @@ = form_tag explore_projects_filter_path, method: :get, class: 'form-inline form-tiny' do |f| .form-group = search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input", id: "projects_search", spellcheck: false + = hidden_field_tag :sort, @sort .form-group = button_tag 'Search', class: "btn" @@ -46,4 +47,3 @@ = link_to explore_projects_filter_path(tag: tag.name) do %i.fa.fa-tag = tag.name - = render 'explore/projects/dropdown' diff --git a/app/views/explore/projects/_nav.html.haml b/app/views/explore/projects/_nav.html.haml new file mode 100644 index 00000000000..614b5431779 --- /dev/null +++ b/app/views/explore/projects/_nav.html.haml @@ -0,0 +1,10 @@ +%ul.nav-links + = nav_link(page: [trending_explore_projects_path, explore_root_path]) do + = link_to trending_explore_projects_path do + Trending + = nav_link(page: starred_explore_projects_path) do + = link_to starred_explore_projects_path do + Most stars + = nav_link(page: explore_projects_path) do + = link_to explore_projects_path do + All diff --git a/app/views/explore/projects/index.html.haml b/app/views/explore/projects/index.html.haml index b9a958fbe7b..bee8518d57a 100644 --- a/app/views/explore/projects/index.html.haml +++ b/app/views/explore/projects/index.html.haml @@ -6,7 +6,11 @@ - else = render 'explore/head' -.gray-content-block.clearfix.second-block +.top-area + = render 'explore/projects/nav' + +.gray-content-block.second-block.clearfix = render 'filter' + = render 'projects', projects: @projects = paginate @projects, theme: "gitlab" diff --git a/app/views/explore/projects/starred.html.haml b/app/views/explore/projects/starred.html.haml index 95d46e331f8..16f52f7a530 100644 --- a/app/views/explore/projects/starred.html.haml +++ b/app/views/explore/projects/starred.html.haml @@ -6,12 +6,6 @@ - else = render 'explore/head' -.explore-trending-block - .gray-content-block.second-block - .pull-right - = render 'explore/projects/dropdown' - .oneline - %i.fa.fa-star - See most starred projects - = render 'projects', projects: @starred_projects - = paginate @starred_projects, theme: 'gitlab' += render 'explore/projects/nav' += render 'projects', projects: @starred_projects += paginate @starred_projects, theme: 'gitlab' diff --git a/app/views/explore/projects/trending.html.haml b/app/views/explore/projects/trending.html.haml index fa0b718e48b..adcda810061 100644 --- a/app/views/explore/projects/trending.html.haml +++ b/app/views/explore/projects/trending.html.haml @@ -6,11 +6,5 @@ - else = render 'explore/head' -.explore-trending-block - .gray-content-block.second-block - .pull-right - = render 'explore/projects/dropdown' - .oneline - %i.fa.fa-comments-o - See most discussed projects for last month - = render 'projects', projects: @trending_projects += render 'explore/projects/nav' += render 'projects', projects: @trending_projects -- cgit v1.2.1 From f8a33707b7b0626c5f8e22289197d2054e86d918 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Feb 2016 20:21:26 +0100 Subject: Fix tests Signed-off-by: Dmitriy Zaporozhets --- spec/features/builds_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb index d37bd103714..5b6f3cb3f15 100644 --- a/spec/features/builds_spec.rb +++ b/spec/features/builds_spec.rb @@ -18,7 +18,7 @@ describe "Builds" do visit namespace_project_builds_path(@project.namespace, @project, scope: :running) end - it { expect(page).to have_selector('.project-issuable-filter li.active', text: 'Running') } + it { expect(page).to have_selector('.nav-links li.active', text: 'Running') } it { expect(page).to have_link 'Cancel running' } it { expect(page).to have_content @build.short_sha } it { expect(page).to have_content @build.ref } @@ -31,7 +31,7 @@ describe "Builds" do visit namespace_project_builds_path(@project.namespace, @project, scope: :finished) end - it { expect(page).to have_selector('.project-issuable-filter li.active', text: 'Finished') } + it { expect(page).to have_selector('.nav-links li.active', text: 'Finished') } it { expect(page).to have_content 'No builds to show' } it { expect(page).to have_link 'Cancel running' } end @@ -42,7 +42,7 @@ describe "Builds" do visit namespace_project_builds_path(@project.namespace, @project) end - it { expect(page).to have_selector('.project-issuable-filter li.active', text: 'All') } + it { expect(page).to have_selector('.nav-links li.active', text: 'All') } it { expect(page).to have_content @build.short_sha } it { expect(page).to have_content @build.ref } it { expect(page).to have_content @build.name } @@ -57,7 +57,7 @@ describe "Builds" do click_link "Cancel running" end - it { expect(page).to have_selector('.project-issuable-filter li.active', text: 'All') } + it { expect(page).to have_selector('.nav-links li.active', text: 'All') } it { expect(page).to have_content 'canceled' } it { expect(page).to have_content @build.short_sha } it { expect(page).to have_content @build.ref } -- cgit v1.2.1 From ccd99efe64b546a0f5e6bd774479cde2861287ef Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Feb 2016 22:48:21 +0100 Subject: Update test after changes build page css Signed-off-by: Dmitriy Zaporozhets --- features/steps/project/builds/summary.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/project/builds/summary.rb b/features/steps/project/builds/summary.rb index 036bc0a499e..4bc670fdfcb 100644 --- a/features/steps/project/builds/summary.rb +++ b/features/steps/project/builds/summary.rb @@ -13,7 +13,7 @@ class Spinach::Features::ProjectBuildsSummary < Spinach::FeatureSteps end step 'I see button to CI Lint' do - page.within('.controls') do + page.within('.nav-controls') do ci_lint_tool_link = page.find_link('CI Lint') expect(ci_lint_tool_link[:href]).to eq ci_lint_path end -- cgit v1.2.1 From 47982e50c4038ed6e56b1dd28b4d4888b33460eb Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 3 Feb 2016 17:19:54 -0500 Subject: Make Pipelines responsible for defining their custom whitelist This allows for future pipelines to more easily define a custom whitelist. --- lib/banzai/filter/sanitization_filter.rb | 9 +----- lib/banzai/pipeline/description_pipeline.rb | 13 +++++++- spec/lib/banzai/filter/sanitization_filter_spec.rb | 22 ------------- .../banzai/pipeline/description_pipeline_spec.rb | 37 ++++++++++++++++++++++ 4 files changed, 50 insertions(+), 31 deletions(-) create mode 100644 spec/lib/banzai/pipeline/description_pipeline_spec.rb diff --git a/lib/banzai/filter/sanitization_filter.rb b/lib/banzai/filter/sanitization_filter.rb index d1e11eedec3..04ddfe53ed6 100644 --- a/lib/banzai/filter/sanitization_filter.rb +++ b/lib/banzai/filter/sanitization_filter.rb @@ -8,14 +8,7 @@ module Banzai # Extends HTML::Pipeline::SanitizationFilter with a custom whitelist. class SanitizationFilter < HTML::Pipeline::SanitizationFilter def whitelist - # Descriptions are more heavily sanitized, allowing only a few elements. - # See http://git.io/vkuAN - if context[:inline_sanitization] - whitelist = LIMITED - whitelist[:elements] -= %w(pre code img ol ul li) - else - whitelist = super - end + whitelist = super customize_whitelist(whitelist) diff --git a/lib/banzai/pipeline/description_pipeline.rb b/lib/banzai/pipeline/description_pipeline.rb index 20e24ace352..f2395867658 100644 --- a/lib/banzai/pipeline/description_pipeline.rb +++ b/lib/banzai/pipeline/description_pipeline.rb @@ -4,9 +4,20 @@ module Banzai def self.transform_context(context) super(context).merge( # SanitizationFilter - inline_sanitization: true + whitelist: whitelist ) end + + private + + def self.whitelist + # Descriptions are more heavily sanitized, allowing only a few elements. + # See http://git.io/vkuAN + whitelist = Banzai::Filter::SanitizationFilter::LIMITED + whitelist[:elements] -= %w(pre code img ol ul li) + + whitelist + end end end end diff --git a/spec/lib/banzai/filter/sanitization_filter_spec.rb b/spec/lib/banzai/filter/sanitization_filter_spec.rb index 9c63d227044..e14a6dbf922 100644 --- a/spec/lib/banzai/filter/sanitization_filter_spec.rb +++ b/spec/lib/banzai/filter/sanitization_filter_spec.rb @@ -177,26 +177,4 @@ describe Banzai::Filter::SanitizationFilter, lib: true do expect(act.to_html).to eq exp end end - - context 'when inline_sanitization is true' do - it 'uses a stricter whitelist' do - doc = filter('

Description

', inline_sanitization: true) - expect(doc.to_html.strip).to eq 'Description' - end - - %w(pre code img ol ul li).each do |elem| - it "removes '#{elem}' elements" do - act = "<#{elem}>Description" - expect(filter(act, inline_sanitization: true).to_html.strip). - to eq 'Description' - end - end - - %w(b i strong em a ins del sup sub p).each do |elem| - it "still allows '#{elem}' elements" do - exp = act = "<#{elem}>Description" - expect(filter(act, inline_sanitization: true).to_html).to eq exp - end - end - end end diff --git a/spec/lib/banzai/pipeline/description_pipeline_spec.rb b/spec/lib/banzai/pipeline/description_pipeline_spec.rb new file mode 100644 index 00000000000..76f42071810 --- /dev/null +++ b/spec/lib/banzai/pipeline/description_pipeline_spec.rb @@ -0,0 +1,37 @@ +require 'rails_helper' + +describe Banzai::Pipeline::DescriptionPipeline do + def parse(html) + # When we pass HTML to Redcarpet, it gets wrapped in `p` tags... + # ...except when we pass it pre-wrapped text. Rabble rabble. + unwrap = !html.start_with?('

') + + output = described_class.to_html(html, project: spy) + + output.gsub!(%r{\A

(.*)

(.*)\z}, '\1\2') if unwrap + + output + end + + it 'uses a limited whitelist' do + doc = parse('# Description') + + expect(doc.strip).to eq 'Description' + end + + %w(pre code img ol ul li).each do |elem| + it "removes '#{elem}' elements" do + act = "<#{elem}>Description" + + expect(parse(act).strip).to eq 'Description' + end + end + + %w(b i strong em a ins del sup sub p).each do |elem| + it "still allows '#{elem}' elements" do + exp = act = "<#{elem}>Description" + + expect(parse(act).strip).to eq exp + end + end +end -- cgit v1.2.1 From de6f2884eaf096ff16062aa1fb3f8e518b69c2b5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Feb 2016 23:27:00 +0100 Subject: Sort projects by last activity for project switcher in header Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/api.js.coffee | 3 ++- app/assets/javascripts/project_select.js.coffee | 3 ++- app/helpers/projects_helper.rb | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee index 746fa3cea87..3e0fdb3f795 100644 --- a/app/assets/javascripts/api.js.coffee +++ b/app/assets/javascripts/api.js.coffee @@ -47,7 +47,7 @@ callback(namespaces) # Return projects list. Filtered by query - projects: (query, callback) -> + projects: (query, order, callback) -> url = Api.buildUrl(Api.projects_path) $.ajax( @@ -55,6 +55,7 @@ data: private_token: gon.api_token search: query + order_by: order per_page: 20 dataType: "json" ).done (projects) -> diff --git a/app/assets/javascripts/project_select.js.coffee b/app/assets/javascripts/project_select.js.coffee index 0ae274f3363..be8ab9b428d 100644 --- a/app/assets/javascripts/project_select.js.coffee +++ b/app/assets/javascripts/project_select.js.coffee @@ -3,6 +3,7 @@ class @ProjectSelect $('.ajax-project-select').each (i, select) -> @groupId = $(select).data('group-id') @includeGroups = $(select).data('include-groups') + @orderBy = $(select).data('order-by') || 'id' placeholder = "Search for project" placeholder += " or group" if @includeGroups @@ -28,7 +29,7 @@ class @ProjectSelect if @groupId Api.groupProjects @groupId, query.term, projectsCallback else - Api.projects query.term, projectsCallback + Api.projects query.term, @orderBy, projectsCallback id: (project) -> project.web_url diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index e7e472cbb5b..0aaa6774298 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -57,7 +57,10 @@ module ProjectsHelper link_output = simple_sanitize(project.name) link_output += content_tag :span, nil, { class: "fa fa-chevron-down dropdown-toggle-caret" } if current_user - link_output += project_select_tag :project_path, class: "project-item-select js-projects-dropdown", data: { include_groups: false } if current_user + if current_user + link_output += project_select_tag :project_path, class: "project-item-select js-projects-dropdown", + data: { include_groups: false, order_by: 'last_activity_at' } + end link_output end -- cgit v1.2.1 From 9f8acf8a8378741d00ed1f665c0f5f692057ac8d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 4 Feb 2016 09:57:17 +0100 Subject: Satisfy rubocop Signed-off-by: Dmitriy Zaporozhets --- 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 0aaa6774298..dc487a31d97 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -58,7 +58,8 @@ module ProjectsHelper link_output += content_tag :span, nil, { class: "fa fa-chevron-down dropdown-toggle-caret" } if current_user if current_user - link_output += project_select_tag :project_path, class: "project-item-select js-projects-dropdown", + link_output += project_select_tag :project_path, + class: "project-item-select js-projects-dropdown", data: { include_groups: false, order_by: 'last_activity_at' } end -- cgit v1.2.1 From c6e0228ca9937b10ad8e2620501d4fe221108d9a Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Thu, 4 Feb 2016 11:51:12 +0100 Subject: Hide remove source branch button when new commit is added to branch Fixes #3339 This MR hides the 'Remove source branch' button when a new commit is added to the source branch --- CHANGELOG | 1 + app/models/merge_request.rb | 3 ++- spec/models/merge_request_spec.rb | 8 +++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 481a0f8d243..a3c3fb67b19 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -28,6 +28,7 @@ v 8.5.0 (unreleased) - Support Akismet spam checking for creation of issues via API (Stan Hu) - Improve UI consistency between projects and groups lists - Add sort dropdown to dashboard projects page + - Hide remove source branch button when the MR is merged but new commits are pushed (Zeger-Jan van de Weg) v 8.4.3 - Increase lfs_objects size column to 8-byte integer to allow files larger diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 89b6c49b362..00362352508 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -284,7 +284,8 @@ class MergeRequest < ActiveRecord::Base def can_remove_source_branch?(current_user) !source_project.protected_branch?(source_branch) && !source_project.root_ref?(source_branch) && - Ability.abilities.allowed?(current_user, :push_code, source_project) + Ability.abilities.allowed?(current_user, :push_code, source_project) && + last_commit == source_project.commit(source_branch) end def mr_and_commit_notes diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 46f2f20b986..f9d0e1029d6 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -226,9 +226,15 @@ describe MergeRequest, models: true do expect(subject.can_remove_source_branch?(user2)).to be_falsey end - it "is can be removed in all other cases" do + it "can be removed if the last commit is the head of the source branch" do + allow(subject.source_project).to receive(:commit).and_return(subject.last_commit) + expect(subject.can_remove_source_branch?(user)).to be_truthy end + + it "cannot be removed if the last commit is not also the head of the source branch" do + expect(subject.can_remove_source_branch?(user)).to be_falsey + end end describe "#reset_merge_when_build_succeeds" do -- cgit v1.2.1 From ff5f0894adbabc9a70cb93af9126d8fc19c13d0b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 4 Feb 2016 12:23:44 +0100 Subject: Sort projects by last activity for new issue dropdown When creating new issue from dashboard page I want to see projects sorted by last activity instead of ID Signed-off-by: Dmitriy Zaporozhets --- app/views/shared/_new_project_item_select.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/_new_project_item_select.html.haml b/app/views/shared/_new_project_item_select.html.haml index 46095912821..1c58345278a 100644 --- a/app/views/shared/_new_project_item_select.html.haml +++ b/app/views/shared/_new_project_item_select.html.haml @@ -1,6 +1,6 @@ - if @projects.any? .prepend-left-10.project-item-select-holder - = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups] } + = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at' } %a.btn.btn-new.new-project-item-select-button = icon('plus') = local_assigns[:label] -- cgit v1.2.1 From 70e44d63f7f1af81ddb0527e3a084c6ab692ea58 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 4 Feb 2016 12:38:25 +0100 Subject: In search autocomplete show only groups and projects you are member of For big instances search autocomplet is flooded with groups you have no access to and insternal/public projects you don't care. It affects way how easily you can go to group/project you are actually member of Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 1 + app/helpers/search_helper.rb | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fc123b22b11..3f457b3fea8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -28,6 +28,7 @@ v 8.5.0 (unreleased) - Support Akismet spam checking for creation of issues via API (Stan Hu) - Improve UI consistency between projects and groups lists - Add sort dropdown to dashboard projects page + - In seach autocomplete show only groups and projects you are member of v 8.4.3 - Increase lfs_objects size column to 8-byte integer to allow files larger diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index d4f78258626..1eb790b1796 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -70,7 +70,7 @@ module SearchHelper # Autocomplete results for the current user's groups def groups_autocomplete(term, limit = 5) - Group.search(term).limit(limit).map do |group| + current_user.authorized_groups.search(term).limit(limit).map do |group| { label: "group: #{search_result_sanitize(group.name)}", url: group_path(group) @@ -80,7 +80,7 @@ module SearchHelper # Autocomplete results for the current user's projects def projects_autocomplete(term, limit = 5) - ProjectsFinder.new.execute(current_user).search_by_title(term). + current_user.authorized_projects.search_by_title(term). sorted_by_stars.non_archived.limit(limit).map do |p| { label: "project: #{search_result_sanitize(p.name_with_namespace)}", -- cgit v1.2.1