From 47e38e5c0e516c5c09017760f495c53155fe26c1 Mon Sep 17 00:00:00 2001 From: Ewan Edwards Date: Mon, 16 Feb 2015 11:16:23 -0800 Subject: [PATCH 001/143] The "GitLab buttons in Gmail" document was not linked from anywhere else. It is now linked. --- doc/integration/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/integration/README.md b/doc/integration/README.md index 1fc8ab997e..559a94533d 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -12,6 +12,8 @@ See the documentation below for details on how to configure these services. Jenkins support is [available in GitLab EE](http://doc.gitlab.com/ee/integration/jenkins.html). +GitLab can also integrate with [Gmail](gitlab_buttons_in_gmail.md). + ## Project services Integration with services such as Campfire, Flowdock, Gemnasium, HipChat, Pivotal Tracker, and Slack are available in the form of a Project Service. From cb65a3f1d965f226f19ac20c69435c3387eb39ed Mon Sep 17 00:00:00 2001 From: Sabba Petri Date: Mon, 23 Feb 2015 15:48:00 -0800 Subject: [PATCH 002/143] Changed button styles Styles for buttons are changed to match user expectations. --- app/views/profiles/accounts/show.html.haml | 2 +- app/views/profiles/notifications/show.html.haml | 2 +- app/views/profiles/passwords/edit.html.haml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index 53a50f6796..248c9137ca 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -57,7 +57,7 @@ %p.light = user_url(@user) %div - = f.submit 'Save username', class: "btn btn-save" + = f.submit 'Save username', class: "btn btn-create" - if show_profile_remove_tab? %fieldset.remove-account diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml index 28bc5a426a..516c4f8236 100644 --- a/app/views/profiles/notifications/show.html.haml +++ b/app/views/profiles/notifications/show.html.haml @@ -51,7 +51,7 @@ %p You will receive all notifications from projects in which you participate .form-actions - = f.submit 'Save changes', class: "btn btn-save" + = f.submit 'Save changes', class: "btn btn-create" .clearfix %hr diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml index 6b19db4eb5..3941fff5ea 100644 --- a/app/views/profiles/passwords/edit.html.haml +++ b/app/views/profiles/passwords/edit.html.haml @@ -35,4 +35,4 @@ .col-sm-10 = f.password_field :password_confirmation, required: true, class: 'form-control' .form-actions - = f.submit 'Save password', class: "btn btn-save" + = f.submit 'Save password', class: "btn btn-create" From 1e42cd2040c788774734e6621b426b3d99362123 Mon Sep 17 00:00:00 2001 From: Sabba Petri Date: Tue, 24 Feb 2015 10:09:38 -0800 Subject: [PATCH 003/143] Added a warning class to button Because changing username largely affects the application, it should not be green, but be more of a warning change, which is why it's now orange. --- app/views/profiles/accounts/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index 248c9137ca..268e652027 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -57,7 +57,7 @@ %p.light = user_url(@user) %div - = f.submit 'Save username', class: "btn btn-create" + = f.submit 'Save username', class: "btn btn-warning" - if show_profile_remove_tab? %fieldset.remove-account From 87da9185ff3b973afd0676ed375e7aa98a0fb233 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 25 Feb 2015 12:22:05 +0100 Subject: [PATCH 004/143] Autosave title and description of new issues/MRs. --- app/assets/javascripts/dispatcher.js.coffee | 4 +++ .../javascripts/issuable_form.js.coffee | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 app/assets/javascripts/issuable_form.js.coffee diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index ed1bdd6ca3..591a3749a9 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -33,12 +33,16 @@ class Dispatcher shortcut_handler = new ShortcutsNavigation() new ZenMode() new DropzoneInput($('.issue-form')) + if page == 'projects:issues:new' + new IssuableForm($('.issue-form')) when 'projects:merge_requests:new', 'projects:merge_requests:edit' GitLab.GfmAutoComplete.setup() new Diff() shortcut_handler = new ShortcutsNavigation() new ZenMode() new DropzoneInput($('.merge-request-form')) + if page == 'projects:merge_requests:new' + new IssuableForm($('.merge-request-form')) when 'projects:merge_requests:show' new Diff() shortcut_handler = new ShortcutsIssueable() diff --git a/app/assets/javascripts/issuable_form.js.coffee b/app/assets/javascripts/issuable_form.js.coffee new file mode 100644 index 0000000000..abd58bcf97 --- /dev/null +++ b/app/assets/javascripts/issuable_form.js.coffee @@ -0,0 +1,28 @@ +class @IssuableForm + constructor: (@form) -> + @titleField = @form.find("input[name*='[title]']") + @descriptionField = @form.find("textarea[name*='[description]']") + + return unless @titleField.length && @descriptionField.length + + @initAutosave() + + @form.on "submit", @resetAutosave + @form.on "click", ".btn-cancel", @resetAutosave + + initAutosave: -> + new Autosave @titleField, [ + document.location.pathname, + document.location.search, + "title" + ] + + new Autosave @descriptionField, [ + document.location.pathname, + document.location.search, + "description" + ] + + resetAutosave: => + @titleField.data("autosave").reset() + @descriptionField.data("autosave").reset() From 607f0c05feb2cde82493a36ac43ba5ecd6c71620 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 20 Feb 2015 17:43:28 +0100 Subject: [PATCH 005/143] Change EmailsOnPush subject to include namespace, repo and branch. See #1827. --- app/mailers/emails/projects.rb | 9 ++++++--- spec/mailers/notify_spec.rb | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 4bc40b35f2..f2e599ab28 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -23,21 +23,24 @@ module Emails @commits = Commit.decorate(compare.commits) @diffs = compare.diffs @branch = branch + + @subject = "[#{@project.path_with_namespace}][#{@branch}] " + if @commits.length > 1 @target_url = namespace_project_compare_url(@project.namespace, @project, from: @commits.first, to: @commits.last) - @subject = "#{@commits.length} new commits pushed to repository" + @subject << "#{@commits.length} commits: #{@commits.first.title}" else @target_url = namespace_project_commit_url(@project.namespace, @project, @commits.first) - @subject = @commits.first.title + @subject << @commits.first.title end mail(from: sender(author_id), to: recipient, - subject: subject(@subject)) + subject: @subject) end end end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 3b09c618f2..ae2b61262b 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -583,7 +583,7 @@ describe Notify do end it 'has the correct subject' do - is_expected.to have_subject /#{commits.length} new commits pushed to repository/ + is_expected.to have_subject /\[#{project.path_with_namespace}\]\[master\] #{commits.length} commits:/ end it 'includes commits list' do From 6afb03ee96a2f0c36e69a6da4e10dbe298c5b79f Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 20 Feb 2015 17:44:13 +0100 Subject: [PATCH 006/143] Remove incorrect footer from EmailsOnPush body. See #1754. --- app/mailers/emails/projects.rb | 2 ++ app/views/layouts/notify.html.haml | 2 +- spec/mailers/notify_spec.rb | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index f2e599ab28..f3a2ae14d3 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -38,6 +38,8 @@ module Emails @subject << @commits.first.title end + @disable_footer = true + mail(from: sender(author_id), to: recipient, subject: @subject) diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index 8cca80e524..eb5da47016 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -27,5 +27,5 @@ - if @target_url #{link_to "View it on GitLab", @target_url} = email_action @target_url - - if @project + - if @project && !@disable_footer You're receiving this notification because you are a member of the #{link_to_unless @target_url, @project.name_with_namespace, namespace_project_url(@project.namespace, @project)} project team. diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index ae2b61262b..41b0daacde 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -597,6 +597,10 @@ describe Notify do it 'contains a link to the diff' do is_expected.to have_body_text /#{diff_path}/ end + + it 'doesn not contain the misleading footer' do + is_expected.not_to have_body_text /you are a member of/ + end end describe 'email on push with a single commit' do From 7b34c9dc593c15ed60f397b1e43e34bab8702674 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 20 Feb 2015 17:55:23 +0100 Subject: [PATCH 007/143] Add list of changed files to EmailsOnPush. See #1906. --- app/views/layouts/notify.html.haml | 9 ++++ .../notify/repository_push_email.html.haml | 44 +++++++++++++++---- .../notify/repository_push_email.text.haml | 23 +++++++--- app/views/projects/diffs/_stats.html.haml | 2 +- 4 files changed, 64 insertions(+), 14 deletions(-) diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index eb5da47016..cd23fd3c28 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -16,6 +16,15 @@ font-size:small; color:#777 } + .file-stats a { + text-decoration: none; + } + .file-stats .new-file { + color: #090; + } + .file-stats .deleted-file { + color: #B00; + } #{add_email_highlight_css} %body %div.content diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml index a45d1dedcd..28b87812bc 100644 --- a/app/views/notify/repository_push_email.html.haml +++ b/app/views/notify/repository_push_email.html.haml @@ -11,16 +11,44 @@ %i at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")} %pre #{commit.safe_message} +%h4 #{pluralize @diffs.count, "changed file"}: + +%ul + - @diffs.each_with_index do |diff, i| + %li.file-stats + %a{href: "#diff-#{i}"} + - if diff.deleted_file + %span.deleted-file + − + = diff.old_path + - elsif diff.renamed_file + = diff.old_path + → + = diff.new_path + - elsif diff.new_file + %span.new-file + + + = diff.new_path + - else + = diff.new_path + %h4 Changes: -- @diffs.each do |diff| - %li - %strong - - if diff.old_path == diff.new_path - = diff.new_path - - elsif diff.new_path && diff.old_path - #{diff.old_path} → #{diff.new_path} +- @diffs.each_with_index do |diff, i| + %li{id: "diff-#{i}"} + %a{href: @target_url + "#diff-#{i}"} + - if diff.deleted_file + %strong + = diff.old_path + deleted + - elsif diff.renamed_file + %strong + = diff.old_path + → + %strong + = diff.new_path - else - = diff.new_path || diff.old_path + %strong + = diff.new_path %hr %pre = color_email_diff(diff.diff) diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml index fa355cb526..8ff7a8a99e 100644 --- a/app/views/notify/repository_push_email.text.haml +++ b/app/views/notify/repository_push_email.text.haml @@ -8,16 +8,29 @@ Commits: \- - - - - \ \ +#{pluralize @diffs.count, "changed file"}: +\ +- @diffs.each do |diff| + - if diff.deleted_file + \- − #{diff.old_path} + - elsif diff.renamed_file + \- #{diff.old_path} → #{diff.new_path} + - elsif diff.new_file + \- + #{diff.new_path} + - else + \- #{diff.new_path} +\ +\ Changes: - @diffs.each do |diff| \ \===================================== - - if diff.old_path == diff.new_path - = diff.new_path - - elsif diff.new_path && diff.old_path - #{diff.old_path} → #{diff.new_path} + - if diff.deleted_file + #{diff.old_path} deleted + - elsif diff.renamed_file + #{diff.old_path} → #{diff.new_path} - else - = diff.new_path || diff.old_path + = diff.new_path \===================================== != diff.diff \ diff --git a/app/views/projects/diffs/_stats.html.haml b/app/views/projects/diffs/_stats.html.haml index 20e51d18da..9b5eb84a86 100644 --- a/app/views/projects/diffs/_stats.html.haml +++ b/app/views/projects/diffs/_stats.html.haml @@ -26,7 +26,7 @@ %a{href: "#diff-#{i}"} %i.fa.fa-minus = diff.old_path - \-> + → = diff.new_path - elsif diff.new_file %span.new-file From 0e7d1fd44f057c83c5384618f4599271f9fdd006 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 25 Feb 2015 14:05:03 +0100 Subject: [PATCH 008/143] Add optional title field to service properties. --- app/views/admin/services/_form.html.haml | 3 ++- app/views/projects/services/_form.html.haml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml index 5df8849317..7394925f01 100644 --- a/app/views/admin/services/_form.html.haml +++ b/app/views/admin/services/_form.html.haml @@ -16,6 +16,7 @@ - @service.fields.each do |field| - name = field[:name] + - title = field[:title] || name.humanize - value = @service.send(name) unless field[:type] == 'password' - type = field[:type] - placeholder = field[:placeholder] @@ -23,7 +24,7 @@ - default_choice = field[:default_choice] .form-group - = f.label name, class: "control-label" + = f.label name, title, class: "control-label" .col-sm-10 - if type == 'text' = f.text_field name, class: "form-control", placeholder: placeholder diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index 8db6d67e06..8008fa2b4b 100644 --- a/app/views/projects/services/_form.html.haml +++ b/app/views/projects/services/_form.html.haml @@ -29,6 +29,7 @@ - @service.fields.each do |field| - name = field[:name] + - title = field[:title] || name.humanize - value = @service.send(name) unless field[:type] == 'password' - type = field[:type] - placeholder = field[:placeholder] @@ -36,7 +37,7 @@ - default_choice = field[:default_choice] .form-group - = f.label name, class: "control-label" + = f.label name, title, class: "control-label" .col-sm-10 - if type == 'text' = f.text_field name, class: "form-control", placeholder: placeholder From e0c186c35735a2dc9e05e88ad9975ae016c815d9 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 25 Feb 2015 14:05:45 +0100 Subject: [PATCH 009/143] Add option to send EmailsOnPush from committer email if domain matches. See #1809. --- app/controllers/admin/services_controller.rb | 3 +- .../projects/services_controller.rb | 3 +- app/mailers/emails/projects.rb | 6 ++-- app/mailers/notify.rb | 7 ++++- .../emails_on_push_service.rb | 8 ++++- app/workers/emails_on_push_worker.rb | 4 +-- spec/mailers/notify_spec.rb | 30 ++++++++++++++++++- 7 files changed, 51 insertions(+), 10 deletions(-) diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb index e80cabd6e1..88106b2418 100644 --- a/app/controllers/admin/services_controller.rb +++ b/app/controllers/admin/services_controller.rb @@ -45,7 +45,8 @@ class Admin::ServicesController < Admin::ApplicationController :room, :recipients, :project_url, :webhook, :user_key, :device, :priority, :sound, :bamboo_url, :username, :password, :build_key, :server, :teamcity_url, :build_type, - :description, :issues_url, :new_issue_url, :restrict_to_branch + :description, :issues_url, :new_issue_url, :restrict_to_branch, + :send_from_committer_email ]) end end diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index 5c29a6550f..dd3987605e 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -50,7 +50,8 @@ class Projects::ServicesController < Projects::ApplicationController :room, :recipients, :project_url, :webhook, :user_key, :device, :priority, :sound, :bamboo_url, :username, :password, :build_key, :server, :teamcity_url, :build_type, - :description, :issues_url, :new_issue_url, :restrict_to_branch + :description, :issues_url, :new_issue_url, :restrict_to_branch, + :send_from_committer_email ) end end diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index f3a2ae14d3..3b60aed6f9 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -16,13 +16,13 @@ module Emails subject: subject("Project was moved")) end - def repository_push_email(project_id, recipient, author_id, branch, compare) + def repository_push_email(project_id, recipient, author_id, branch, compare, send_from_committer_email = false) @project = Project.find(project_id) @author = User.find(author_id) @compare = compare @commits = Commit.decorate(compare.commits) @diffs = compare.diffs - @branch = branch + @branch = branch.gsub("refs/heads/", "") @subject = "[#{@project.path_with_namespace}][#{@branch}] " @@ -40,7 +40,7 @@ module Emails @disable_footer = true - mail(from: sender(author_id), + mail(from: sender(author_id, send_from_committer_email), to: recipient, subject: @subject) end diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 46ead62f75..00d609cd93 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -45,10 +45,15 @@ class Notify < ActionMailer::Base # Return an email address that displays the name of the sender. # Only the displayed name changes; the actual email address is always the same. - def sender(sender_id) + def sender(sender_id, send_from_user_email = false) if sender = User.find(sender_id) address = default_sender_address address.display_name = sender.name + + if send_from_user_email && sender.email.end_with?("@#{Gitlab.config.gitlab.host}") + address.address = sender.email + end + address.format end end diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb index 86693ad0c7..a5653665bf 100644 --- a/app/models/project_services/emails_on_push_service.rb +++ b/app/models/project_services/emails_on_push_service.rb @@ -14,6 +14,7 @@ # class EmailsOnPushService < Service + prop_accessor :send_from_committer_email prop_accessor :recipients validates :recipients, presence: true, if: :activated? @@ -29,12 +30,17 @@ class EmailsOnPushService < Service 'emails_on_push' end + def send_from_committer_email? + self.send_from_committer_email == "1" + end + def execute(push_data) - EmailsOnPushWorker.perform_async(project_id, recipients, push_data) + EmailsOnPushWorker.perform_async(project_id, recipients, push_data, self.send_from_committer_email?) end def fields [ + { type: 'checkbox', name: 'send_from_committer_email', title: "Send from committer email if domain matches" }, { type: 'textarea', name: 'recipients', placeholder: 'Emails separated by whitespace' }, ] end diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb index e3f6f3a6ae..3814b17a8a 100644 --- a/app/workers/emails_on_push_worker.rb +++ b/app/workers/emails_on_push_worker.rb @@ -1,7 +1,7 @@ class EmailsOnPushWorker include Sidekiq::Worker - def perform(project_id, recipients, push_data) + def perform(project_id, recipients, push_data, send_from_committer_email = false) project = Project.find(project_id) before_sha = push_data["before"] after_sha = push_data["after"] @@ -19,7 +19,7 @@ class EmailsOnPushWorker return false unless compare && compare.commits.present? recipients.split(" ").each do |recipient| - Notify.repository_push_email(project_id, recipient, author_id, branch, compare).deliver + Notify.repository_push_email(project_id, recipient, author_id, branch, compare, send_from_committer_email).deliver end ensure compare = nil diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 41b0daacde..ad2b7c11f8 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -569,8 +569,9 @@ describe Notify do let(:compare) { Gitlab::Git::Compare.new(project.repository.raw_repository, sample_image_commit.id, sample_commit.id) } let(:commits) { Commit.decorate(compare.commits) } let(:diff_path) { namespace_project_compare_path(project.namespace, project, from: commits.first, to: commits.last) } + let(:send_from_committer_email) { false } - subject { Notify.repository_push_email(project.id, 'devs@company.name', user.id, 'master', compare) } + subject { Notify.repository_push_email(project.id, 'devs@company.name', user.id, 'master', compare, send_from_committer_email) } it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -601,6 +602,33 @@ describe Notify do it 'doesn not contain the misleading footer' do is_expected.not_to have_body_text /you are a member of/ end + + context "when set to send from committer email if domain matches" do + + let(:send_from_committer_email) { true } + + context "when the committer email domain matches" do + + before do + allow(Gitlab.config.gitlab).to receive(:host).and_return("gitlab.dev") + user.update_attribute(:email, "user@#{Gitlab.config.gitlab.host}") + user.confirm! + end + + it "is sent from the committer email" do + sender = subject.header[:from].addrs[0] + expect(sender.address).to eq(user.email) + end + end + + context "when the committer email doesn't match" do + + it "is sent from the default email" do + sender = subject.header[:from].addrs[0] + expect(sender.address).to eq(gitlab_sender) + end + end + end end describe 'email on push with a single commit' do From 85af3e82bfe0ebd01e816ee7c5ee6a2c28ce8ff9 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 25 Feb 2015 14:29:49 +0100 Subject: [PATCH 010/143] Add option to disable code diffs to EmailOnPush. See #1950 --- app/controllers/admin/services_controller.rb | 2 +- .../projects/services_controller.rb | 2 +- app/mailers/emails/projects.rb | 3 +- .../emails_on_push_service.rb | 8 +++- .../notify/repository_push_email.html.haml | 45 ++++++++++--------- .../notify/repository_push_email.text.haml | 30 +++++++------ app/workers/emails_on_push_worker.rb | 12 ++++- 7 files changed, 60 insertions(+), 42 deletions(-) diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb index 88106b2418..44a3f1379d 100644 --- a/app/controllers/admin/services_controller.rb +++ b/app/controllers/admin/services_controller.rb @@ -46,7 +46,7 @@ class Admin::ServicesController < Admin::ApplicationController :user_key, :device, :priority, :sound, :bamboo_url, :username, :password, :build_key, :server, :teamcity_url, :build_type, :description, :issues_url, :new_issue_url, :restrict_to_branch, - :send_from_committer_email + :send_from_committer_email, :disable_diffs ]) end end diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index dd3987605e..b7fd5202f9 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -51,7 +51,7 @@ class Projects::ServicesController < Projects::ApplicationController :user_key, :device, :priority, :sound, :bamboo_url, :username, :password, :build_key, :server, :teamcity_url, :build_type, :description, :issues_url, :new_issue_url, :restrict_to_branch, - :send_from_committer_email + :send_from_committer_email, :disable_diffs ) end end diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 3b60aed6f9..30959ab6a1 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -16,13 +16,14 @@ module Emails subject: subject("Project was moved")) end - def repository_push_email(project_id, recipient, author_id, branch, compare, send_from_committer_email = false) + def repository_push_email(project_id, recipient, author_id, branch, compare, send_from_committer_email = false, disable_diffs = false) @project = Project.find(project_id) @author = User.find(author_id) @compare = compare @commits = Commit.decorate(compare.commits) @diffs = compare.diffs @branch = branch.gsub("refs/heads/", "") + @disable_diffs = disable_diffs @subject = "[#{@project.path_with_namespace}][#{@branch}] " diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb index a5653665bf..e5d6c29c64 100644 --- a/app/models/project_services/emails_on_push_service.rb +++ b/app/models/project_services/emails_on_push_service.rb @@ -15,6 +15,7 @@ class EmailsOnPushService < Service prop_accessor :send_from_committer_email + prop_accessor :disable_diffs prop_accessor :recipients validates :recipients, presence: true, if: :activated? @@ -34,13 +35,18 @@ class EmailsOnPushService < Service self.send_from_committer_email == "1" end + def disable_diffs? + self.disable_diffs == "1" + end + def execute(push_data) - EmailsOnPushWorker.perform_async(project_id, recipients, push_data, self.send_from_committer_email?) + EmailsOnPushWorker.perform_async(project_id, recipients, push_data, send_from_committer_email?, disable_diffs?) end def fields [ { type: 'checkbox', name: 'send_from_committer_email', title: "Send from committer email if domain matches" }, + { type: 'checkbox', name: 'disable_diffs', title: "Disable code diffs" }, { type: 'textarea', name: 'recipients', placeholder: 'Emails separated by whitespace' }, ] end diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml index 28b87812bc..49688470cc 100644 --- a/app/views/notify/repository_push_email.html.haml +++ b/app/views/notify/repository_push_email.html.haml @@ -16,7 +16,7 @@ %ul - @diffs.each_with_index do |diff, i| %li.file-stats - %a{href: "#diff-#{i}"} + %a{href: "#{@target_url if @disable_diffs}#diff-#{i}" } - if diff.deleted_file %span.deleted-file − @@ -32,27 +32,28 @@ - else = diff.new_path -%h4 Changes: -- @diffs.each_with_index do |diff, i| - %li{id: "diff-#{i}"} - %a{href: @target_url + "#diff-#{i}"} - - if diff.deleted_file - %strong - = diff.old_path - deleted - - elsif diff.renamed_file - %strong - = diff.old_path - → - %strong - = diff.new_path - - else - %strong - = diff.new_path - %hr - %pre - = color_email_diff(diff.diff) - %br +- unless @disable_diffs + %h4 Changes: + - @diffs.each_with_index do |diff, i| + %li{id: "diff-#{i}"} + %a{href: @target_url + "#diff-#{i}"} + - if diff.deleted_file + %strong + = diff.old_path + deleted + - elsif diff.renamed_file + %strong + = diff.old_path + → + %strong + = diff.new_path + - else + %strong + = diff.new_path + %hr + %pre + = color_email_diff(diff.diff) + %br - if @compare.timeout %h5 Huge diff. To prevent performance issues changes are hidden diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml index 8ff7a8a99e..b081121c53 100644 --- a/app/views/notify/repository_push_email.text.haml +++ b/app/views/notify/repository_push_email.text.haml @@ -19,20 +19,22 @@ Commits: \- + #{diff.new_path} - else \- #{diff.new_path} -\ -\ -Changes: -- @diffs.each do |diff| +- unless @disable_diffs \ - \===================================== - - if diff.deleted_file - #{diff.old_path} deleted - - elsif diff.renamed_file - #{diff.old_path} → #{diff.new_path} - - else - = diff.new_path - \===================================== - != diff.diff -\ + \ + Changes: + - @diffs.each do |diff| + \ + \===================================== + - if diff.deleted_file + #{diff.old_path} deleted + - elsif diff.renamed_file + #{diff.old_path} → #{diff.new_path} + - else + = diff.new_path + \===================================== + != diff.diff - if @compare.timeout + \ + \ Huge diff. To prevent performance issues it was hidden diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb index 3814b17a8a..309772cb5c 100644 --- a/app/workers/emails_on_push_worker.rb +++ b/app/workers/emails_on_push_worker.rb @@ -1,7 +1,7 @@ class EmailsOnPushWorker include Sidekiq::Worker - def perform(project_id, recipients, push_data, send_from_committer_email = false) + def perform(project_id, recipients, push_data, send_from_committer_email = false, disable_diffs = false) project = Project.find(project_id) before_sha = push_data["before"] after_sha = push_data["after"] @@ -19,7 +19,15 @@ class EmailsOnPushWorker return false unless compare && compare.commits.present? recipients.split(" ").each do |recipient| - Notify.repository_push_email(project_id, recipient, author_id, branch, compare, send_from_committer_email).deliver + Notify.repository_push_email( + project_id, + recipient, + author_id, + branch, + compare, + send_from_committer_email, + disable_diffs + ).deliver end ensure compare = nil From ae70a80fc202822a485cabf78da9774d14055617 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 25 Feb 2015 14:32:55 +0100 Subject: [PATCH 011/143] Fix links in EmailsOnPush text version. --- app/views/notify/repository_push_email.text.haml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml index b081121c53..7cb2814a49 100644 --- a/app/views/notify/repository_push_email.text.haml +++ b/app/views/notify/repository_push_email.text.haml @@ -1,9 +1,9 @@ -#{@author.name} pushed to #{@branch} at #{link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project)} +#{@author.name} pushed to #{@branch} at #{@project.name_with_namespace} \ Commits: - @commits.each do |commit| - #{link_to commit.short_id, namespace_project_commit_url(@project.namespace, @project, commit)} by #{commit.author_name} + #{commit.short_id} by #{commit.author_name} #{commit.safe_message} \- - - - - \ @@ -38,3 +38,6 @@ Commits: \ \ Huge diff. To prevent performance issues it was hidden +\ +\ +View it on GitLab: #{@target_url} From 769f137a5344dbc3748c2fea7c1d560392410ca4 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 25 Feb 2015 14:37:15 +0100 Subject: [PATCH 012/143] Wrap commit message in EmailsOnPush email. See #1867. --- app/views/layouts/notify.html.haml | 3 +++ app/views/notify/repository_push_email.html.haml | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index cd23fd3c28..7eec93abdf 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -16,6 +16,9 @@ font-size:small; color:#777 } + pre.commit-message { + white-space: pre-wrap; + } .file-stats a { text-decoration: none; } diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml index 49688470cc..1a617e2108 100644 --- a/app/views/notify/repository_push_email.html.haml +++ b/app/views/notify/repository_push_email.html.haml @@ -9,7 +9,8 @@ %div %span by #{commit.author_name} %i at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")} - %pre #{commit.safe_message} + %pre.commit-message + = commit.safe_message %h4 #{pluralize @diffs.count, "changed file"}: From 5d86332153838252384f9f87a0ae3e34c46eb266 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 25 Feb 2015 15:12:19 +0100 Subject: [PATCH 013/143] Send EmailsOnPush when deleting commits using force push. See #1924. --- app/mailers/emails/projects.rb | 6 +++++- app/views/notify/repository_push_email.html.haml | 8 +++++++- app/views/notify/repository_push_email.text.haml | 10 +++++++--- app/workers/emails_on_push_worker.rb | 12 ++++++++++-- spec/mailers/notify_spec.rb | 2 +- 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 30959ab6a1..5c38601c1b 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -16,9 +16,10 @@ module Emails subject: subject("Project was moved")) end - def repository_push_email(project_id, recipient, author_id, branch, compare, send_from_committer_email = false, disable_diffs = false) + def repository_push_email(project_id, recipient, author_id, branch, compare, reverse_compare = false, send_from_committer_email = false, disable_diffs = false) @project = Project.find(project_id) @author = User.find(author_id) + @reverse_compare = reverse_compare @compare = compare @commits = Commit.decorate(compare.commits) @diffs = compare.diffs @@ -32,10 +33,13 @@ module Emails @project, from: @commits.first, to: @commits.last) + @subject << "Deleted " if @reverse_compare @subject << "#{@commits.length} commits: #{@commits.first.title}" else @target_url = namespace_project_commit_url(@project.namespace, @project, @commits.first) + + @subject << "Deleted 1 commit: " if @reverse_compare @subject << @commits.first.title end diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml index 1a617e2108..039b92df2b 100644 --- a/app/views/notify/repository_push_email.html.haml +++ b/app/views/notify/repository_push_email.html.haml @@ -1,6 +1,12 @@ %h3 #{@author.name} pushed to #{@branch} at #{link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project)} -%h4 Commits: +- if @reverse_compare + %p + %strong WARNING: + The push did not contain any new commits, but force pushed to delete the commits and changes below. + +%h4 + = @reverse_compare ? "Deleted commits:" : "Commits:" %ul - @commits.each do |commit| diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml index 7cb2814a49..8d67a42234 100644 --- a/app/views/notify/repository_push_email.text.haml +++ b/app/views/notify/repository_push_email.text.haml @@ -1,9 +1,13 @@ #{@author.name} pushed to #{@branch} at #{@project.name_with_namespace} - \ -Commits: +\ +- if @reverse_compare + WARNING: The push did not contain any new commits, but force pushed to delete the commits and changes below. + \ + \ += @reverse_compare ? "Deleted commits:" : "Commits:" - @commits.each do |commit| - #{commit.short_id} by #{commit.author_name} + #{commit.short_id} by #{commit.author_name} at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")} #{commit.safe_message} \- - - - - \ diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb index 309772cb5c..2e78381482 100644 --- a/app/workers/emails_on_push_worker.rb +++ b/app/workers/emails_on_push_worker.rb @@ -15,8 +15,15 @@ class EmailsOnPushWorker compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha) - # Do not send emails if git compare failed - return false unless compare && compare.commits.present? + return false if compare.same + + if compare.commits.empty? + compare = Gitlab::Git::Compare.new(project.repository.raw_repository, after_sha, before_sha) + + reverse_compare = true + + return false if compare.commits.empty? + end recipients.split(" ").each do |recipient| Notify.repository_push_email( @@ -25,6 +32,7 @@ class EmailsOnPushWorker author_id, branch, compare, + reverse_compare, send_from_committer_email, disable_diffs ).deliver diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index ad2b7c11f8..9af1794261 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -571,7 +571,7 @@ describe Notify do let(:diff_path) { namespace_project_compare_path(project.namespace, project, from: commits.first, to: commits.last) } let(:send_from_committer_email) { false } - subject { Notify.repository_push_email(project.id, 'devs@company.name', user.id, 'master', compare, send_from_committer_email) } + subject { Notify.repository_push_email(project.id, 'devs@company.name', user.id, 'master', compare, false, send_from_committer_email) } it 'is sent as the author' do sender = subject.header[:from].addrs[0] From 969de4c15a876ab9096f163ef6182571ca199492 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 25 Feb 2015 15:49:40 +0100 Subject: [PATCH 014/143] Fix EmailsOnPush to allow sending from @company.com for GitLab at gitlab.corp.company.com. --- app/mailers/notify.rb | 17 ++++++++++++++++- spec/mailers/notify_spec.rb | 29 +++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 00d609cd93..65925b61e9 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -34,6 +34,20 @@ class Notify < ActionMailer::Base ) end + # Splits "gitlab.corp.company.com" up into "gitlab.corp.company.com", + # "corp.company.com" and "company.com". + # Respects set tld length so "company.co.uk" won't match "somethingelse.uk" + def self.allowed_email_domains + domain_parts = Gitlab.config.gitlab.host.split(".") + allowed_domains = [] + begin + allowed_domains << domain_parts.join(".") + domain_parts.shift + end while domain_parts.length > ActionDispatch::Http::URL.tld_length + + allowed_domains + end + private # The default email address to send emails from @@ -50,7 +64,8 @@ class Notify < ActionMailer::Base address = default_sender_address address.display_name = sender.name - if send_from_user_email && sender.email.end_with?("@#{Gitlab.config.gitlab.host}") + sender_domain = sender.email.split("@").last + if send_from_user_email && self.class.allowed_email_domains.include?(sender_domain) address.address = sender.email end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 9af1794261..534ab05942 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -607,11 +607,14 @@ describe Notify do let(:send_from_committer_email) { true } - context "when the committer email domain matches" do + before do + allow(Gitlab.config.gitlab).to receive(:host).and_return("gitlab.corp.company.com") + end + + context "when the committer email domain is within the GitLab domain" do before do - allow(Gitlab.config.gitlab).to receive(:host).and_return("gitlab.dev") - user.update_attribute(:email, "user@#{Gitlab.config.gitlab.host}") + user.update_attribute(:email, "user@company.com") user.confirm! end @@ -621,7 +624,25 @@ describe Notify do end end - context "when the committer email doesn't match" do + context "when the committer email domain is not completely within the GitLab domain" do + + before do + user.update_attribute(:email, "user@something.company.com") + user.confirm! + end + + it "is sent from the default email" do + sender = subject.header[:from].addrs[0] + expect(sender.address).to eq(gitlab_sender) + end + end + + context "when the committer email domain is outside the GitLab domain" do + + before do + user.update_attribute(:email, "user@mpany.com") + user.confirm! + end it "is sent from the default email" do sender = subject.header[:from].addrs[0] From f0b78a852933a54173bb9b4ceddba44b52dc3cfa Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 25 Feb 2015 15:56:42 +0100 Subject: [PATCH 015/143] Clarify EmailsOnPushService options. --- app/models/project_services/emails_on_push_service.rb | 7 +++++-- app/views/admin/services/_form.html.haml | 3 +++ app/views/projects/services/_form.html.haml | 3 +++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb index e5d6c29c64..ec0c55bfd9 100644 --- a/app/models/project_services/emails_on_push_service.rb +++ b/app/models/project_services/emails_on_push_service.rb @@ -44,9 +44,12 @@ class EmailsOnPushService < Service end def fields + domains = Notify.allowed_email_domains.map { |domain| "user@#{domain}" }.join(", ") [ - { type: 'checkbox', name: 'send_from_committer_email', title: "Send from committer email if domain matches" }, - { type: 'checkbox', name: 'disable_diffs', title: "Disable code diffs" }, + { type: 'checkbox', name: 'send_from_committer_email', title: "Send from committer", + help: "Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. #{domains})." }, + { type: 'checkbox', name: 'disable_diffs', title: "Disable code diffs", + help: "Don't include possibly sensitive code diffs in notification body." }, { type: 'textarea', name: 'recipients', placeholder: 'Emails separated by whitespace' }, ] end diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml index 7394925f01..1cd6b8e75b 100644 --- a/app/views/admin/services/_form.html.haml +++ b/app/views/admin/services/_form.html.haml @@ -22,6 +22,7 @@ - placeholder = field[:placeholder] - choices = field[:choices] - default_choice = field[:default_choice] + - help = field[:help] .form-group = f.label name, title, class: "control-label" @@ -36,6 +37,8 @@ = f.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" } - elsif type == 'password' = f.password_field name, class: 'form-control' + - if help + %span.help-block= help .form-actions = f.submit 'Save', class: 'btn btn-save' diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index 8008fa2b4b..1b7265d56e 100644 --- a/app/views/projects/services/_form.html.haml +++ b/app/views/projects/services/_form.html.haml @@ -35,6 +35,7 @@ - placeholder = field[:placeholder] - choices = field[:choices] - default_choice = field[:default_choice] + - help = field[:help] .form-group = f.label name, title, class: "control-label" @@ -49,6 +50,8 @@ = f.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" } - elsif type == 'password' = f.password_field name, class: 'form-control' + - if help + %span.help-block= help .form-actions = f.submit 'Save', class: 'btn btn-save' From 4658e554b7129c44221a73fe8ec3b73b4b9b8b24 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 25 Feb 2015 17:17:24 +0100 Subject: [PATCH 016/143] Fix EmailsOnPush comparison link to include first commit. --- app/mailers/emails/projects.rb | 4 ++-- spec/mailers/notify_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 5c38601c1b..9ea121d83a 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -31,8 +31,8 @@ module Emails if @commits.length > 1 @target_url = namespace_project_compare_url(@project.namespace, @project, - from: @commits.first, - to: @commits.last) + from: Commit.new(@compare.base), + to: Commit.new(@compare.head)) @subject << "Deleted " if @reverse_compare @subject << "#{@commits.length} commits: #{@commits.first.title}" else diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 534ab05942..4090fa4620 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -568,7 +568,7 @@ describe Notify do let(:user) { create(:user) } let(:compare) { Gitlab::Git::Compare.new(project.repository.raw_repository, sample_image_commit.id, sample_commit.id) } let(:commits) { Commit.decorate(compare.commits) } - let(:diff_path) { namespace_project_compare_path(project.namespace, project, from: commits.first, to: commits.last) } + let(:diff_path) { namespace_project_compare_path(project.namespace, project, from: Commit.new(compare.base), to: Commit.new(compare.head)) } let(:send_from_committer_email) { false } subject { Notify.repository_push_email(project.id, 'devs@company.name', user.id, 'master', compare, false, send_from_committer_email) } From 38c52b1be6ca05862db0f7e8c4931bebc873bf75 Mon Sep 17 00:00:00 2001 From: Vinnie Okada Date: Mon, 2 Mar 2015 16:11:39 -0700 Subject: [PATCH 017/143] Fix checkbox alignment in application settings Add the form-control CSS class to the feature checkboxes on the application settings page to fix the vertical alignment with their labels. Also add aria-describedby attributes to form controls that have a help text block. --- CHANGELOG | 1 + .../application_settings/_form.html.haml | 30 +++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index dae32953cd..7e5fd3940d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,7 @@ v 7.9.0 (unreleased) - Fix ordering of imported but unchanged projects (Marco Wessel) - Mobile UI improvements: make aside content expandable - Expose avatar_url in projects API + - Fix checkbox alignment on the application settings page. - Generalize image upload in drag and drop in markdown to all files (Hannes Rosenögger) - Fix mass-unassignment of issues (Robert Speicher) - Allow user confirmation to be skipped for new users via API diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index f528d69f43..ac64d26f9a 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -8,39 +8,39 @@ %fieldset %legend Features .form-group - = f.label :signup_enabled, class: 'control-label' + = f.label :signup_enabled, class: 'control-label col-sm-2' .col-sm-10 - = f.check_box :signup_enabled, class: 'checkbox' + = f.check_box :signup_enabled, class: 'checkbox form-control' .form-group - = f.label :signin_enabled, class: 'control-label' + = f.label :signin_enabled, class: 'control-label col-sm-2' .col-sm-10 - = f.check_box :signin_enabled, class: 'checkbox' + = f.check_box :signin_enabled, class: 'checkbox form-control' .form-group - = f.label :gravatar_enabled, class: 'control-label' + = f.label :gravatar_enabled, class: 'control-label col-sm-2' .col-sm-10 - = f.check_box :gravatar_enabled, class: 'checkbox' + = f.check_box :gravatar_enabled, class: 'checkbox form-control' .form-group - = f.label :twitter_sharing_enabled, "Twitter enabled", class: 'control-label' + = f.label :twitter_sharing_enabled, "Twitter enabled", class: 'control-label col-sm-2' .col-sm-10 - = f.check_box :twitter_sharing_enabled, class: 'checkbox' - %span.help-block Show users button to share their newly created public or internal projects on twitter + = f.check_box :twitter_sharing_enabled, class: 'checkbox form-control', :'aria-describedby' => 'twitter_help_block' + %span.help-block#twitter_help_block Show users a button to share their newly created public or internal projects on twitter %fieldset %legend Misc .form-group - = f.label :default_projects_limit, class: 'control-label' + = f.label :default_projects_limit, class: 'control-label col-sm-2' .col-sm-10 = f.number_field :default_projects_limit, class: 'form-control' .form-group - = f.label :default_branch_protection, class: 'control-label' + = f.label :default_branch_protection, class: 'control-label col-sm-2' .col-sm-10 = f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control' .form-group - = f.label :home_page_url, class: 'control-label' + = f.label :home_page_url, class: 'control-label col-sm-2' .col-sm-10 - = f.text_field :home_page_url, class: 'form-control', placeholder: 'http://company.example.com' - %span.help-block We will redirect non-logged in users to this page + = f.text_field :home_page_url, class: 'form-control', placeholder: 'http://company.example.com', :'aria-describedby' => 'home_help_block' + %span.help-block#home_help_block We will redirect non-logged in users to this page .form-group - = f.label :sign_in_text, class: 'control-label' + = f.label :sign_in_text, class: 'control-label col-sm-2' .col-sm-10 = f.text_area :sign_in_text, class: 'form-control', rows: 4 .help-block Markdown enabled From afe5d7d209a4088d71e35d6382e6523b89f94ebe Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 19 Feb 2015 05:02:57 +0000 Subject: [PATCH 018/143] Issue #595: Support Slack notifications upon issue and merge request events 1) Adds a DB migration for all services to toggle on push, issue, and merge events. 2) Upon an issue or merge request event, fire service hooks. 3) Slack service supports custom messages for each of these events. Other services not supported at the moment. 4) Label merge request hooks with their corresponding actions. --- CHANGELOG | 3 + .../projects/services_controller.rb | 3 +- app/models/project.rb | 5 +- app/models/project_services/asana_service.rb | 7 ++ .../project_services/assembla_service.rb | 11 +- app/models/project_services/bamboo_service.rb | 9 +- .../project_services/buildbox_service.rb | 7 ++ .../project_services/campfire_service.rb | 7 ++ app/models/project_services/ci_service.rb | 4 + .../emails_on_push_service.rb | 7 ++ .../project_services/flowdock_service.rb | 7 ++ .../project_services/gemnasium_service.rb | 7 ++ .../project_services/gitlab_ci_service.rb | 4 + .../gitlab_issue_tracker_service.rb | 4 + .../project_services/hipchat_service.rb | 7 ++ .../project_services/issue_tracker_service.rb | 7 ++ app/models/project_services/jira_service.rb | 4 + .../pivotaltracker_service.rb | 7 ++ .../project_services/pushover_service.rb | 7 ++ .../project_services/redmine_service.rb | 4 + app/models/project_services/slack_message.rb | 110 ------------------ .../slack_messages/slack_base_message.rb | 31 +++++ .../slack_messages/slack_issue_message.rb | 56 +++++++++ .../slack_messages/slack_merge_message.rb | 54 +++++++++ .../slack_messages/slack_push_message.rb | 110 ++++++++++++++++++ app/models/project_services/slack_service.rb | 38 +++++- .../project_services/teamcity_service.rb | 11 +- app/models/service.rb | 14 +++ app/services/git_push_service.rb | 2 +- app/services/issues/base_service.rb | 12 +- app/services/merge_requests/base_service.rb | 16 ++- app/views/projects/services/_form.html.haml | 32 +++++ .../20150219004514_add_events_to_services.rb | 8 ++ db/schema.rb | 8 +- lib/gitlab/push_data_builder.rb | 1 + .../project_services/assembla_service_spec.rb | 20 ++-- .../project_services/buildbox_service_spec.rb | 20 ++-- .../project_services/flowdock_service_spec.rb | 20 ++-- .../gemnasium_service_spec.rb | 20 ++-- .../gitlab_ci_service_spec.rb | 20 ++-- .../project_services/pushover_service_spec.rb | 20 ++-- .../slack_issue_message_spec.rb | 55 +++++++++ .../slack_merge_message_spec.rb | 50 ++++++++ .../slack_push_message_spec.rb} | 4 +- .../project_services/slack_service_spec.rb | 59 ++++++++-- spec/models/service_spec.rb | 4 + spec/services/git_push_service_spec.rb | 1 + 47 files changed, 722 insertions(+), 195 deletions(-) delete mode 100644 app/models/project_services/slack_message.rb create mode 100644 app/models/project_services/slack_messages/slack_base_message.rb create mode 100644 app/models/project_services/slack_messages/slack_issue_message.rb create mode 100644 app/models/project_services/slack_messages/slack_merge_message.rb create mode 100644 app/models/project_services/slack_messages/slack_push_message.rb create mode 100644 db/migrate/20150219004514_add_events_to_services.rb create mode 100644 spec/models/project_services/slack_messages/slack_issue_message_spec.rb create mode 100644 spec/models/project_services/slack_messages/slack_merge_message_spec.rb rename spec/models/project_services/{slack_message_spec.rb => slack_messages/slack_push_message_spec.rb} (94%) diff --git a/CHANGELOG b/CHANGELOG index 6a28772097..8011817d0a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. +v 7.9.0 (unreleased) + - Added issue and merge request events to Slack service (Stan Hu) + - Fix broken access control for note attachments (Hannes Rosenögger) v 7.9.0 (unreleased) - Move labels/milestones tabs to sidebar diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index 82aad329c1..087579de10 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -51,7 +51,8 @@ class Projects::ServicesController < Projects::ApplicationController :user_key, :device, :priority, :sound, :bamboo_url, :username, :password, :build_key, :server, :teamcity_url, :build_type, :description, :issues_url, :new_issue_url, :restrict_to_branch, :channel, - :colorize_messages, :channels + :colorize_messages, :channels, + :push_events, :issues_events, :merge_requests_events, :tag_push_events ) end end diff --git a/app/models/project.rb b/app/models/project.rb index 907f331d8f..c45338bf4e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -479,8 +479,9 @@ class Project < ActiveRecord::Base end end - def execute_services(data) - services.select(&:active).each do |service| + def execute_services(data, hooks_scope = :push_hooks) + # Call only service hooks that are active for this scope + services.send(hooks_scope).each do |service| service.async_execute(data) end end diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index 66b72572b9..2b530390ae 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require 'asana' @@ -62,6 +66,9 @@ automatically inspected. Leave blank to include all branches.' end def execute(push) + object_kind = push[:object_kind] + return unless object_kind == "push" + Asana.configure do |client| client.api_key = api_key end diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb index cf7598f35e..01c647c170 100644 --- a/app/models/project_services/assembla_service.rb +++ b/app/models/project_services/assembla_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class AssemblaService < Service @@ -38,8 +42,11 @@ class AssemblaService < Service ] end - def execute(push) + def execute(data) + object_kind = data[:object_kind] + return unless object_kind == "push" + url = "https://atlas.assembla.com/spaces/#{subdomain}/github_tool?secret_key=#{token}" - AssemblaService.post(url, body: { payload: push }.to_json, headers: { 'Content-Type' => 'application/json' }) + AssemblaService.post(url, body: { payload: data }.to_json, headers: { 'Content-Type' => 'application/json' }) end end diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb index df68803152..6ff52af040 100644 --- a/app/models/project_services/bamboo_service.rb +++ b/app/models/project_services/bamboo_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class BambooService < CiService @@ -118,7 +122,10 @@ class BambooService < CiService end end - def execute(_data) + def execute(data) + object_kind = data[:object_kind] + return unless object_kind == "push" + # Bamboo requires a GET and does not take any data. self.class.get("#{bamboo_url}/updateAndBuild.action?buildKey=#{build_key}", verify: false) diff --git a/app/models/project_services/buildbox_service.rb b/app/models/project_services/buildbox_service.rb index 058c890ae4..201bfc560a 100644 --- a/app/models/project_services/buildbox_service.rb +++ b/app/models/project_services/buildbox_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require "addressable/uri" @@ -33,6 +37,9 @@ class BuildboxService < CiService end def execute(data) + object_kind = data[:object_kind] + return unless object_kind == "push" + service_hook.execute(data) end diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb index 14b6b87a0b..41ab6c56ad 100644 --- a/app/models/project_services/campfire_service.rb +++ b/app/models/project_services/campfire_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class CampfireService < Service @@ -38,6 +42,9 @@ class CampfireService < Service end def execute(push_data) + object_kind = push_data[:object_kind] + return unless object_kind == "push" + room = gate.find_room_by_name(self.room) return true unless room diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb index 5a26c25b3c..e58d6d7a23 100644 --- a/app/models/project_services/ci_service.rb +++ b/app/models/project_services/ci_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # # Base class for CI services diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb index 86693ad0c7..28be15c3b3 100644 --- a/app/models/project_services/emails_on_push_service.rb +++ b/app/models/project_services/emails_on_push_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # class EmailsOnPushService < Service @@ -30,6 +34,9 @@ class EmailsOnPushService < Service end def execute(push_data) + object_kind = push_data[:object_kind] + return unless object_kind == "push" + EmailsOnPushWorker.perform_async(project_id, recipients, push_data) end diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb index 13e2dfceb1..9cc0e36788 100644 --- a/app/models/project_services/flowdock_service.rb +++ b/app/models/project_services/flowdock_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # require "flowdock-git-hook" @@ -38,6 +42,9 @@ class FlowdockService < Service end def execute(push_data) + object_kind = push_data[:object_kind] + return unless object_kind == "push" + Flowdock::Git.post( push_data[:ref], push_data[:before], diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb index a2c87ae88f..130c9eaeb4 100644 --- a/app/models/project_services/gemnasium_service.rb +++ b/app/models/project_services/gemnasium_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # require "gemnasium/gitlab_service" @@ -39,6 +43,9 @@ class GemnasiumService < Service end def execute(push_data) + object_kind = push_data[:object_kind] + return unless object_kind == "push" + Gemnasium::GitlabService.execute( ref: push_data[:ref], before: push_data[:before], diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb index f4b463e819..a64b24b5ef 100644 --- a/app/models/project_services/gitlab_ci_service.rb +++ b/app/models/project_services/gitlab_ci_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # class GitlabCiService < CiService diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb index 05c048e4e4..00f8d430fd 100644 --- a/app/models/project_services/gitlab_issue_tracker_service.rb +++ b/app/models/project_services/gitlab_issue_tracker_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class GitlabIssueTrackerService < IssueTrackerService diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 003e06a4c8..462478812a 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # class HipchatService < Service @@ -41,6 +45,9 @@ class HipchatService < Service end def execute(push_data) + object_kind = push_data.fetch(:object_kind) + return unless object_kind == "push" + gate[room].send('GitLab', create_message(push_data)) end diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb index c991a34ecd..0d9e5c1399 100644 --- a/app/models/project_services/issue_tracker_service.rb +++ b/app/models/project_services/issue_tracker_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class IssueTrackerService < Service @@ -66,6 +70,9 @@ class IssueTrackerService < Service end def execute(data) + object_kind = data[:object_kind] + return unless object_kind == "push" + message = "#{self.type} was unable to reach #{self.project_url}. Check the url and try again." result = false diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 4c056605ea..20611eeb60 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class JiraService < IssueTrackerService diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb index 287812c57a..4bb2a978ed 100644 --- a/app/models/project_services/pivotaltracker_service.rb +++ b/app/models/project_services/pivotaltracker_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class PivotaltrackerService < Service @@ -38,6 +42,9 @@ class PivotaltrackerService < Service end def execute(push) + object_kind = push[:object_kind] + return unless object_kind == "push" + url = 'https://www.pivotaltracker.com/services/v5/source_commits' push[:commits].each do |commit| message = { diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb index 3a3af59390..4aa7e0afa7 100644 --- a/app/models/project_services/pushover_service.rb +++ b/app/models/project_services/pushover_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class PushoverService < Service @@ -77,6 +81,9 @@ class PushoverService < Service end def execute(push_data) + object_kind = push_data[:object_kind] + return unless object_kind == "push" + ref = push_data[:ref].gsub('refs/heads/', '') before = push_data[:before] after = push_data[:after] diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb index e1dc10415e..f96eae2daa 100644 --- a/app/models/project_services/redmine_service.rb +++ b/app/models/project_services/redmine_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class RedmineService < IssueTrackerService diff --git a/app/models/project_services/slack_message.rb b/app/models/project_services/slack_message.rb deleted file mode 100644 index 6c6446db45..0000000000 --- a/app/models/project_services/slack_message.rb +++ /dev/null @@ -1,110 +0,0 @@ -require 'slack-notifier' - -class SlackMessage - attr_reader :after - attr_reader :before - attr_reader :commits - attr_reader :project_name - attr_reader :project_url - attr_reader :ref - attr_reader :username - - def initialize(params) - @after = params.fetch(:after) - @before = params.fetch(:before) - @commits = params.fetch(:commits, []) - @project_name = params.fetch(:project_name) - @project_url = params.fetch(:project_url) - @ref = params.fetch(:ref).gsub('refs/heads/', '') - @username = params.fetch(:user_name) - end - - def pretext - format(message) - end - - def attachments - return [] if new_branch? || removed_branch? - - commit_message_attachments - end - - private - - def message - if new_branch? - new_branch_message - elsif removed_branch? - removed_branch_message - else - push_message - end - end - - def format(string) - Slack::Notifier::LinkFormatter.format(string) - end - - def new_branch_message - "#{username} pushed new branch #{branch_link} to #{project_link}" - end - - def removed_branch_message - "#{username} removed branch #{ref} from #{project_link}" - end - - def push_message - "#{username} pushed to branch #{branch_link} of #{project_link} (#{compare_link})" - end - - def commit_messages - commits.each_with_object('') do |commit, str| - str << compose_commit_message(commit) - end.chomp - end - - def commit_message_attachments - [{ text: format(commit_messages), color: attachment_color }] - end - - def compose_commit_message(commit) - author = commit.fetch(:author).fetch(:name) - id = commit.fetch(:id)[0..8] - message = commit.fetch(:message) - url = commit.fetch(:url) - - "[#{id}](#{url}): #{message} - #{author}\n" - end - - def new_branch? - before.include?('000000') - end - - def removed_branch? - after.include?('000000') - end - - def branch_url - "#{project_url}/commits/#{ref}" - end - - def compare_url - "#{project_url}/compare/#{before}...#{after}" - end - - def branch_link - "[#{ref}](#{branch_url})" - end - - def project_link - "[#{project_name}](#{project_url})" - end - - def compare_link - "[Compare changes](#{compare_url})" - end - - def attachment_color - '#345' - end -end diff --git a/app/models/project_services/slack_messages/slack_base_message.rb b/app/models/project_services/slack_messages/slack_base_message.rb new file mode 100644 index 0000000000..c2fc27884b --- /dev/null +++ b/app/models/project_services/slack_messages/slack_base_message.rb @@ -0,0 +1,31 @@ +require 'slack-notifier' + +module SlackMessages + class SlackBaseMessage + def initialize(params) + raise NotImplementedError + end + + def pretext + format(message) + end + + def attachments + raise NotImplementedError + end + + private + + def message + raise NotImplementedError + end + + def format(string) + Slack::Notifier::LinkFormatter.format(string) + end + + def attachment_color + '#345' + end + end +end diff --git a/app/models/project_services/slack_messages/slack_issue_message.rb b/app/models/project_services/slack_messages/slack_issue_message.rb new file mode 100644 index 0000000000..0c3a492aae --- /dev/null +++ b/app/models/project_services/slack_messages/slack_issue_message.rb @@ -0,0 +1,56 @@ +module SlackMessages + class SlackIssueMessage < SlackBaseMessage + attr_reader :username + attr_reader :title + attr_reader :project_name + attr_reader :project_url + attr_reader :issue_iid + attr_reader :issue_url + attr_reader :action + attr_reader :state + attr_reader :description + + def initialize(params) + @username = params[:user][:username] + @project_name = params[:project_name] + @project_url = params[:project_url] + + obj_attr = params[:object_attributes] + obj_attr = HashWithIndifferentAccess.new(obj_attr) + @title = obj_attr[:title] + @issue_iid = obj_attr[:iid] + @issue_url = obj_attr[:url] + @action = obj_attr[:action] + @state = obj_attr[:state] + @description = obj_attr[:description] + end + + def attachments + return [] unless opened_issue? + + description_message + end + + private + + def message + "#{username} #{state} issue #{issue_link} in #{project_link}: #{title}" + end + + def opened_issue? + action == "open" + end + + def description_message + [{ text: format(description), color: attachment_color }] + end + + def project_link + "[#{project_name}](#{project_url})" + end + + def issue_link + "[##{issue_iid}](#{issue_url})" + end + end +end diff --git a/app/models/project_services/slack_messages/slack_merge_message.rb b/app/models/project_services/slack_messages/slack_merge_message.rb new file mode 100644 index 0000000000..bc49a963a9 --- /dev/null +++ b/app/models/project_services/slack_messages/slack_merge_message.rb @@ -0,0 +1,54 @@ +module SlackMessages + class SlackMergeMessage < SlackBaseMessage + attr_reader :username + attr_reader :project_name + attr_reader :project_url + attr_reader :merge_request_id + attr_reader :source_branch + attr_reader :target_branch + attr_reader :state + + def initialize(params) + @username = params[:user][:username] + @project_name = params[:project_name] + @project_url = params[:project_url] + + obj_attr = params[:object_attributes] + obj_attr = HashWithIndifferentAccess.new(obj_attr) + @merge_request_id = obj_attr[:iid] + @source_branch = obj_attr[:source_branch] + @target_branch = obj_attr[:target_branch] + @state = obj_attr[:state] + end + + def pretext + format(message) + end + + def attachments + [] + end + + private + + def message + merge_request_message + end + + def project_link + "[#{project_name}](#{project_url})" + end + + def merge_request_message + "#{username} #{state} merge request #{merge_request_link} in #{project_link}" + end + + def merge_request_link + "[##{merge_request_id}](#{merge_request_url})" + end + + def merge_request_url + "#{project_url}/merge_requests/#{merge_request_id}" + end + end +end diff --git a/app/models/project_services/slack_messages/slack_push_message.rb b/app/models/project_services/slack_messages/slack_push_message.rb new file mode 100644 index 0000000000..c7769bbeda --- /dev/null +++ b/app/models/project_services/slack_messages/slack_push_message.rb @@ -0,0 +1,110 @@ +require 'slack-notifier' + +module SlackMessages + class SlackPushMessage < SlackBaseMessage + attr_reader :after + attr_reader :before + attr_reader :commits + attr_reader :project_name + attr_reader :project_url + attr_reader :ref + attr_reader :username + + def initialize(params) + @after = params[:after] + @before = params[:before] + @commits = params.fetch(:commits, []) + @project_name = params[:project_name] + @project_url = params[:project_url] + @ref = params[:ref].gsub('refs/heads/', '') + @username = params[:user_name] + end + + def pretext + format(message) + end + + def attachments + return [] if new_branch? || removed_branch? + + commit_message_attachments + end + + private + + def message + if new_branch? + new_branch_message + elsif removed_branch? + removed_branch_message + else + push_message + end + end + + def format(string) + Slack::Notifier::LinkFormatter.format(string) + end + + def new_branch_message + "#{username} pushed new branch #{branch_link} to #{project_link}" + end + + def removed_branch_message + "#{username} removed branch #{ref} from #{project_link}" + end + + def push_message + "#{username} pushed to branch #{branch_link} of #{project_link} (#{compare_link})" + end + + def commit_messages + commits.map { |commit| compose_commit_message(commit) }.join("\n") + end + + def commit_message_attachments + [{ text: format(commit_messages), color: attachment_color }] + end + + def compose_commit_message(commit) + author = commit[:author][:name] + id = Commit.truncate_sha(commit[:id]) + message = commit[:message] + url = commit[:url] + + "[#{id}](#{url}): #{message} - #{author}" + end + + def new_branch? + before.include?('000000') + end + + def removed_branch? + after.include?('000000') + end + + def branch_url + "#{project_url}/commits/#{ref}" + end + + def compare_url + "#{project_url}/compare/#{before}...#{after}" + end + + def branch_link + "[#{ref}](#{branch_url})" + end + + def project_link + "[#{project_name}](#{project_url})" + end + + def compare_link + "[Compare changes](#{compare_url})" + end + + def attachment_color + '#345' + end + end +end diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index c7cbff63fe..1318a1ed1b 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -11,7 +11,14 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # +require "slack_messages/slack_issue_message" +require "slack_messages/slack_push_message" +require "slack_messages/slack_merge_message" class SlackService < Service prop_accessor :webhook, :username, :channel @@ -38,20 +45,37 @@ class SlackService < Service ] end - def execute(push_data) + def execute(data) return unless webhook.present? - message = SlackMessage.new(push_data.merge( + object_kind = data[:object_kind] + + data = data.merge( project_url: project_url, project_name: project_name - )) + ) + + # WebHook events often have an 'update' event that follows a 'open' or + # 'close' action. Ignore update events for now to prevent duplicate + # messages from arriving. + + message = case object_kind + when "push" + message = SlackMessages::SlackPushMessage.new(data) + when "issue" + message = SlackMessages::SlackIssueMessage.new(data) unless is_update?(data) + when "merge_request" + message = SlackMessages::SlackMergeMessage.new(data) unless is_update?(data) + end opt = {} opt[:channel] = channel if channel opt[:username] = username if username - notifier = Slack::Notifier.new(webhook, opt) - notifier.ping(message.pretext, attachments: message.attachments) + if message + notifier = Slack::Notifier.new(webhook, opt) + notifier.ping(message.pretext, attachments: message.attachments) + end end private @@ -63,4 +87,8 @@ class SlackService < Service def project_url project.web_url end + + def is_update?(data) + data[:object_attributes][:action] == 'update' + end end diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb index b6932f1c77..07facfb6d0 100644 --- a/app/models/project_services/teamcity_service.rb +++ b/app/models/project_services/teamcity_service.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class TeamcityService < CiService @@ -115,13 +119,16 @@ class TeamcityService < CiService end end - def execute(push) + def execute(data) + object_kind = data[:object_kind] + return unless object_kind == "push" + auth = { username: username, password: password, } - branch = push[:ref].gsub('refs/heads/', '') + branch = data[:ref].gsub('refs/heads/', '') self.class.post("#{teamcity_url}/httpAuth/app/rest/buildQueue", body: ""\ diff --git a/app/models/service.rb b/app/models/service.rb index f4e97da321..9d6866f26d 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -11,6 +11,11 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean +# # To add new service you should build a class inherited from Service # and implement a set of methods @@ -19,6 +24,10 @@ class Service < ActiveRecord::Base serialize :properties, JSON default_value_for :active, false + default_value_for :push_events, true + default_value_for :issues_events, true + default_value_for :merge_requests_events, true + default_value_for :tag_push_events, true after_initialize :initialize_properties @@ -29,6 +38,11 @@ class Service < ActiveRecord::Base scope :visible, -> { where.not(type: 'GitlabIssueTrackerService') } + scope :push_hooks, -> { where(push_events: true, active: true) } + scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) } + scope :issue_hooks, -> { where(issues_events: true, active: true) } + scope :merge_request_hooks, -> { where(merge_requests_events: true, active: true) } + def activated? active end diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index f21e6ac207..13def12776 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -54,7 +54,7 @@ class GitPushService @push_data = post_receive_data(oldrev, newrev, ref) EventCreateService.new.push(project, user, @push_data) project.execute_hooks(@push_data.dup, :push_hooks) - project.execute_services(@push_data.dup) + project.execute_services(@push_data.dup, :push_hooks) end end diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb index 755c0ef45a..c3ca04a434 100644 --- a/app/services/issues/base_service.rb +++ b/app/services/issues/base_service.rb @@ -1,13 +1,19 @@ module Issues class BaseService < ::IssuableBaseService + def hook_data(issue, action) + issue_data = issue.to_hook_data(current_user) + issue_url = Gitlab::UrlBuilder.new(:issue).build(issue.id) + issue_data[:object_attributes].merge!(url: issue_url, action: action) + issue_data + end + private def execute_hooks(issue, action = 'open') - issue_data = issue.to_hook_data(current_user) - issue_url = Gitlab::UrlBuilder.new(:issue).build(issue.id) - issue_data[:object_attributes].merge!(url: issue_url, action: action) + issue_data = hook_data(issue, action) issue.project.execute_hooks(issue_data, :issue_hooks) + issue.project.execute_services(issue_data, :issue_hooks) end end end diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index b4199d1c80..f6e1ae6f28 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -5,13 +5,19 @@ module MergeRequests Note.create_status_change_note(merge_request, merge_request.target_project, current_user, merge_request.state, nil) end + def hook_data(merge_request, action) + hook_data = merge_request.to_hook_data(current_user) + merge_request_url = Gitlab::UrlBuilder.new(:merge_request).build(merge_request.id) + hook_data[:object_attributes][:url] = merge_request_url + hook_data[:object_attributes][:action] = action + hook_data + end + def execute_hooks(merge_request, action = 'open') if merge_request.project - hook_data = merge_request.to_hook_data(current_user) - merge_request_url = Gitlab::UrlBuilder.new(:merge_request).build(merge_request.id) - hook_data[:object_attributes][:url] = merge_request_url - hook_data[:object_attributes][:action] = action - merge_request.project.execute_hooks(hook_data, :merge_request_hooks) + merge_data = hook_data(merge_request, action) + merge_request.project.execute_hooks(merge_data, :merge_request_hooks) + merge_request.project.execute_services(merge_data, :merge_request_hooks) end end end diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index 8db6d67e06..0519c8150e 100644 --- a/app/views/projects/services/_form.html.haml +++ b/app/views/projects/services/_form.html.haml @@ -27,6 +27,38 @@ .col-sm-10 = f.check_box :active + .form-group + = f.label :url, "Trigger", class: 'control-label' + .col-sm-10 + %div + = f.check_box :push_events, class: 'pull-left' + .prepend-left-20 + = f.label :push_events, class: 'list-label' do + %strong Push events + %p.light + This url will be triggered by a push to the repository + %div + = f.check_box :tag_push_events, class: 'pull-left' + .prepend-left-20 + = f.label :tag_push_events, class: 'list-label' do + %strong Tag push events + %p.light + This url will be triggered when a new tag is pushed to the repository + %div + = f.check_box :issues_events, class: 'pull-left' + .prepend-left-20 + = f.label :issues_events, class: 'list-label' do + %strong Issues events + %p.light + This url will be triggered when an issue is created + %div + = f.check_box :merge_requests_events, class: 'pull-left' + .prepend-left-20 + = f.label :merge_requests_events, class: 'list-label' do + %strong Merge Request events + %p.light + This url will be triggered when a merge request is created + - @service.fields.each do |field| - name = field[:name] - value = @service.send(name) unless field[:type] == 'password' diff --git a/db/migrate/20150219004514_add_events_to_services.rb b/db/migrate/20150219004514_add_events_to_services.rb new file mode 100644 index 0000000000..cf73a0174f --- /dev/null +++ b/db/migrate/20150219004514_add_events_to_services.rb @@ -0,0 +1,8 @@ +class AddEventsToServices < ActiveRecord::Migration + def change + add_column :services, :push_events, :boolean, :default => true + add_column :services, :issues_events, :boolean, :default => true + add_column :services, :merge_requests_events, :boolean, :default => true + add_column :services, :tag_push_events, :boolean, :default => true + end +end diff --git a/db/schema.rb b/db/schema.rb index 2659efe4df..1a9b512e15 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -364,9 +364,13 @@ ActiveRecord::Schema.define(version: 20150223022001) do t.integer "project_id" t.datetime "created_at" t.datetime "updated_at" - t.boolean "active", default: false, null: false + t.boolean "active", default: false, null: false t.text "properties" - t.boolean "template", default: false + t.boolean "template", default: false + t.boolean "push_events", default: true + t.boolean "issues_events", default: true + t.boolean "merge_requests_events", default: true + t.boolean "tag_push_events", default: true end add_index "services", ["created_at", "id"], name: "index_services_on_created_at_and_id", using: :btree diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb index 9aa5c8967a..9d8d3ea3d2 100644 --- a/lib/gitlab/push_data_builder.rb +++ b/lib/gitlab/push_data_builder.rb @@ -29,6 +29,7 @@ module Gitlab # Hash to be passed as post_receive_data data = { + object_kind: "push", before: oldrev, after: newrev, ref: ref, diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb index ee7f780c8f..cd34e006eb 100644 --- a/spec/models/project_services/assembla_service_spec.rb +++ b/spec/models/project_services/assembla_service_spec.rb @@ -2,14 +2,18 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # require 'spec_helper' diff --git a/spec/models/project_services/buildbox_service_spec.rb b/spec/models/project_services/buildbox_service_spec.rb index 050363e14c..c246e1c9d4 100644 --- a/spec/models/project_services/buildbox_service_spec.rb +++ b/spec/models/project_services/buildbox_service_spec.rb @@ -2,14 +2,18 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # require 'spec_helper' diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb index b34e36bc94..2ec167a733 100644 --- a/spec/models/project_services/flowdock_service_spec.rb +++ b/spec/models/project_services/flowdock_service_spec.rb @@ -2,14 +2,18 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # require 'spec_helper' diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb index fe5d62b2f5..5f665fadff 100644 --- a/spec/models/project_services/gemnasium_service_spec.rb +++ b/spec/models/project_services/gemnasium_service_spec.rb @@ -2,14 +2,18 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # require 'spec_helper' diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb index 0cd255f08e..fcb33b1173 100644 --- a/spec/models/project_services/gitlab_ci_service_spec.rb +++ b/spec/models/project_services/gitlab_ci_service_spec.rb @@ -2,14 +2,18 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # require 'spec_helper' diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb index 188626a7a2..bb2e72c3ac 100644 --- a/spec/models/project_services/pushover_service_spec.rb +++ b/spec/models/project_services/pushover_service_spec.rb @@ -2,14 +2,18 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # require 'spec_helper' diff --git a/spec/models/project_services/slack_messages/slack_issue_message_spec.rb b/spec/models/project_services/slack_messages/slack_issue_message_spec.rb new file mode 100644 index 0000000000..49a8eea0a5 --- /dev/null +++ b/spec/models/project_services/slack_messages/slack_issue_message_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' + +describe SlackMessages::SlackIssueMessage do + subject { SlackMessages::SlackIssueMessage.new(args) } + + let(:args) { + { + user: { + username: 'username' + }, + project_name: 'project_name', + project_url: 'somewhere.com', + + object_attributes: { + title: 'Issue title', + id: 10, + iid: 100, + assignee_id: 1, + url: 'url', + action: 'open', + state: 'opened', + description: 'issue description' + } + } + } + + let(:color) { '#345' } + + context 'open' do + it 'returns a message regarding opening of issues' do + expect(subject.pretext).to eq( + 'username opened issue in : '\ + 'Issue title') + expect(subject.attachments).to eq([ + { + text: "issue description", + color: color, + } + ]) + end + end + + context 'close' do + before do + args[:object_attributes][:action] = 'close' + args[:object_attributes][:state] = 'closed' + end + it 'returns a message regarding closing of issues' do + expect(subject.pretext). to eq( + 'username closed issue in : '\ + 'Issue title') + expect(subject.attachments).to be_empty + end + end +end diff --git a/spec/models/project_services/slack_messages/slack_merge_message_spec.rb b/spec/models/project_services/slack_messages/slack_merge_message_spec.rb new file mode 100644 index 0000000000..ef76c3312e --- /dev/null +++ b/spec/models/project_services/slack_messages/slack_merge_message_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +describe SlackMessages::SlackMergeMessage do + subject { SlackMessages::SlackMergeMessage.new(args) } + + let(:args) { + { + user: { + username: 'username' + }, + project_name: 'project_name', + project_url: 'somewhere.com', + + object_attributes: { + title: 'Issue title', + id: 10, + iid: 100, + assignee_id: 1, + url: 'url', + state: 'opened', + description: 'issue description', + source_branch: 'source_branch', + target_branch: 'target_branch', + } + } + } + + let(:color) { '#345' } + + context 'open' do + it 'returns a message regarding opening of merge requests' do + expect(subject.pretext).to eq( + 'username opened merge request '\ + 'in ') + expect(subject.attachments).to be_empty + end + end + + context 'close' do + before do + args[:object_attributes][:state] = 'closed' + end + it 'returns a message regarding closing of merge requests' do + expect(subject.pretext).to eq( + 'username closed merge request '\ + 'in ') + expect(subject.attachments).to be_empty + end + end +end diff --git a/spec/models/project_services/slack_message_spec.rb b/spec/models/project_services/slack_messages/slack_push_message_spec.rb similarity index 94% rename from spec/models/project_services/slack_message_spec.rb rename to spec/models/project_services/slack_messages/slack_push_message_spec.rb index 7197a94e53..f11614d692 100644 --- a/spec/models/project_services/slack_message_spec.rb +++ b/spec/models/project_services/slack_messages/slack_push_message_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -describe SlackMessage do - subject { SlackMessage.new(args) } +describe SlackMessages::SlackPushMessage do + subject { SlackMessages::SlackPushMessage.new(args) } let(:args) { { diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb index 8a75d8987a..49c48d0b65 100644 --- a/spec/models/project_services/slack_service_spec.rb +++ b/spec/models/project_services/slack_service_spec.rb @@ -2,14 +2,18 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # require 'spec_helper' @@ -34,7 +38,7 @@ describe SlackService do let(:slack) { SlackService.new } let(:user) { create(:user) } let(:project) { create(:project) } - let(:sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) } + let(:push_sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) } let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' } let(:username) { 'slack_username' } let(:channel) { 'slack_channel' } @@ -48,10 +52,43 @@ describe SlackService do ) WebMock.stub_request(:post, webhook_url) + + opts = { + title: 'Awesome issue', + description: 'please fix' + } + + issue_service = Issues::CreateService.new(project, user, opts) + @issue = issue_service.execute + @issues_sample_data = issue_service.hook_data(@issue, 'open') + + opts = { + title: 'Awesome merge_request', + description: 'please fix', + source_branch: 'stable', + target_branch: 'master' + } + merge_service = MergeRequests::CreateService.new(project, + user, opts) + @merge_request = merge_service.execute + @merge_sample_data = merge_service.hook_data(@merge_request, + 'open') end - it "should call Slack API" do - slack.execute(sample_data) + it "should call Slack API for pull requests" do + slack.execute(push_sample_data) + + WebMock.should have_requested(:post, webhook_url).once + end + + it "should call Slack API for issue events" do + slack.execute(@issues_sample_data) + + WebMock.should have_requested(:post, webhook_url).once + end + + it "should call Slack API for merge requests events" do + slack.execute(@merge_sample_data) expect(WebMock).to have_requested(:post, webhook_url).once end diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 9a1248055b..cc047a20dd 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -11,6 +11,10 @@ # active :boolean default(FALSE), not null # properties :text # template :boolean default(FALSE) +# push_events :boolean +# issues_events :boolean +# merge_requests_events :boolean +# tag_push_events :boolean # require 'spec_helper' diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index 9924935094..e264072b57 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -49,6 +49,7 @@ describe GitPushService do subject { @push_data } + it { is_expected.to include(object_kind: 'push') } it { is_expected.to include(before: @oldrev) } it { is_expected.to include(after: @newrev) } it { is_expected.to include(ref: @ref) } From d9ff616fd803c8bd9d208c22d01770acc8d58a38 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 20 Feb 2015 14:49:26 +0100 Subject: [PATCH 019/143] Code style, directory structure. --- app/models/project_services/asana_service.rb | 10 ++++---- .../project_services/campfire_service.rb | 6 ++--- .../emails_on_push_service.rb | 6 ++--- .../project_services/flowdock_service.rb | 10 ++++---- .../project_services/gemnasium_service.rb | 10 ++++---- .../project_services/hipchat_service.rb | 6 ++--- .../pivotaltracker_service.rb | 6 ++--- .../project_services/pushover_service.rb | 22 ++++++++--------- app/models/project_services/slack_service.rb | 24 ++++++++++--------- .../slack_base_message.rb | 4 ++-- .../slack_issue_message.rb | 4 ++-- .../slack_merge_message.rb | 4 ++-- .../slack_push_message.rb | 4 ++-- 13 files changed, 59 insertions(+), 57 deletions(-) rename app/models/project_services/{slack_messages => slack_service}/slack_base_message.rb (89%) rename app/models/project_services/{slack_messages => slack_service}/slack_issue_message.rb (94%) rename app/models/project_services/{slack_messages => slack_service}/slack_merge_message.rb (94%) rename app/models/project_services/{slack_messages => slack_service}/slack_push_message.rb (97%) diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index 2b530390ae..a5686c48bc 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -65,16 +65,16 @@ automatically inspected. Leave blank to include all branches.' ] end - def execute(push) - object_kind = push[:object_kind] + def execute(data) + object_kind = data[:object_kind] return unless object_kind == "push" Asana.configure do |client| client.api_key = api_key end - user = push[:user_name] - branch = push[:ref].gsub('refs/heads/', '') + user = data[:user_name] + branch = data[:ref].gsub('refs/heads/', '') branch_restriction = restrict_to_branch.to_s @@ -86,7 +86,7 @@ automatically inspected. Leave blank to include all branches.' project_name = project.name_with_namespace push_msg = user + ' pushed to branch ' + branch + ' of ' + project_name - push[:commits].each do |commit| + data[:commits].each do |commit| check_commit(' ( ' + commit[:url] + ' ): ' + commit[:message], push_msg) end end diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb index 41ab6c56ad..7af6882329 100644 --- a/app/models/project_services/campfire_service.rb +++ b/app/models/project_services/campfire_service.rb @@ -41,14 +41,14 @@ class CampfireService < Service ] end - def execute(push_data) - object_kind = push_data[:object_kind] + def execute(data) + object_kind = data[:object_kind] return unless object_kind == "push" room = gate.find_room_by_name(self.room) return true unless room - message = build_message(push_data) + message = build_message(data) room.speak(message) end diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb index 28be15c3b3..1b7ce481c1 100644 --- a/app/models/project_services/emails_on_push_service.rb +++ b/app/models/project_services/emails_on_push_service.rb @@ -33,11 +33,11 @@ class EmailsOnPushService < Service 'emails_on_push' end - def execute(push_data) - object_kind = push_data[:object_kind] + def execute(data) + object_kind = data[:object_kind] return unless object_kind == "push" - EmailsOnPushWorker.perform_async(project_id, recipients, push_data) + EmailsOnPushWorker.perform_async(project_id, recipients, data) end def fields diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb index 9cc0e36788..e4ea84cb61 100644 --- a/app/models/project_services/flowdock_service.rb +++ b/app/models/project_services/flowdock_service.rb @@ -41,14 +41,14 @@ class FlowdockService < Service ] end - def execute(push_data) - object_kind = push_data[:object_kind] + def execute(data) + object_kind = data[:object_kind] return unless object_kind == "push" Flowdock::Git.post( - push_data[:ref], - push_data[:before], - push_data[:after], + data[:ref], + data[:before], + data[:after], token: token, repo: project.repository.path_to_repo, repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}", diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb index 130c9eaeb4..ada61b7804 100644 --- a/app/models/project_services/gemnasium_service.rb +++ b/app/models/project_services/gemnasium_service.rb @@ -42,14 +42,14 @@ class GemnasiumService < Service ] end - def execute(push_data) - object_kind = push_data[:object_kind] + def execute(data) + object_kind = data[:object_kind] return unless object_kind == "push" Gemnasium::GitlabService.execute( - ref: push_data[:ref], - before: push_data[:before], - after: push_data[:after], + ref: data[:ref], + before: data[:before], + after: data[:after], token: token, api_key: api_key, repo: project.repository.path_to_repo diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 462478812a..965ecdc684 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -44,11 +44,11 @@ class HipchatService < Service ] end - def execute(push_data) - object_kind = push_data.fetch(:object_kind) + def execute(data) + object_kind = data[:object_kind] return unless object_kind == "push" - gate[room].send('GitLab', create_message(push_data)) + gate[room].send('GitLab', create_message(data)) end private diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb index 4bb2a978ed..dd9e7f35c1 100644 --- a/app/models/project_services/pivotaltracker_service.rb +++ b/app/models/project_services/pivotaltracker_service.rb @@ -41,12 +41,12 @@ class PivotaltrackerService < Service ] end - def execute(push) - object_kind = push[:object_kind] + def execute(data) + object_kind = data[:object_kind] return unless object_kind == "push" url = 'https://www.pivotaltracker.com/services/v5/source_commits' - push[:commits].each do |commit| + data[:commits].each do |commit| message = { 'source_commit' => { 'commit_id' => commit[:id], diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb index 4aa7e0afa7..a715e7b2cc 100644 --- a/app/models/project_services/pushover_service.rb +++ b/app/models/project_services/pushover_service.rb @@ -80,24 +80,24 @@ class PushoverService < Service ] end - def execute(push_data) - object_kind = push_data[:object_kind] + def execute(data) + object_kind = data[:object_kind] return unless object_kind == "push" - ref = push_data[:ref].gsub('refs/heads/', '') - before = push_data[:before] - after = push_data[:after] + ref = data[:ref].gsub('refs/heads/', '') + before = data[:before] + after = data[:after] if before.include?('000000') - message = "#{push_data[:user_name]} pushed new branch \"#{ref}\"." + message = "#{data[:user_name]} pushed new branch \"#{ref}\"." elsif after.include?('000000') - message = "#{push_data[:user_name]} deleted branch \"#{ref}\"." + message = "#{data[:user_name]} deleted branch \"#{ref}\"." else - message = "#{push_data[:user_name]} push to branch \"#{ref}\"." + message = "#{data[:user_name]} push to branch \"#{ref}\"." end - if push_data[:total_commits_count] > 0 - message << "\nTotal commits count: #{push_data[:total_commits_count]}" + if data[:total_commits_count] > 0 + message << "\nTotal commits count: #{data[:total_commits_count]}" end pushover_data = { @@ -107,7 +107,7 @@ class PushoverService < Service priority: priority, title: "#{project.name_with_namespace}", message: message, - url: push_data[:repository][:homepage], + url: data[:repository][:homepage], url_title: "See project #{project.name_with_namespace}" } diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index 1318a1ed1b..8289e47403 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -16,9 +16,6 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # -require "slack_messages/slack_issue_message" -require "slack_messages/slack_push_message" -require "slack_messages/slack_merge_message" class SlackService < Service prop_accessor :webhook, :username, :channel @@ -59,14 +56,15 @@ class SlackService < Service # 'close' action. Ignore update events for now to prevent duplicate # messages from arriving. - message = case object_kind - when "push" - message = SlackMessages::SlackPushMessage.new(data) - when "issue" - message = SlackMessages::SlackIssueMessage.new(data) unless is_update?(data) - when "merge_request" - message = SlackMessages::SlackMergeMessage.new(data) unless is_update?(data) - end + message = \ + case object_kind + when "push" + PushMessage.new(data) + when "issue" + IssueMessage.new(data) unless is_update?(data) + when "merge_request" + MergeMessage.new(data) unless is_update?(data) + end opt = {} opt[:channel] = channel if channel @@ -92,3 +90,7 @@ class SlackService < Service data[:object_attributes][:action] == 'update' end end + +require "slack_service/issue_message" +require "slack_service/push_message" +require "slack_service/merge_message" \ No newline at end of file diff --git a/app/models/project_services/slack_messages/slack_base_message.rb b/app/models/project_services/slack_service/slack_base_message.rb similarity index 89% rename from app/models/project_services/slack_messages/slack_base_message.rb rename to app/models/project_services/slack_service/slack_base_message.rb index c2fc27884b..aa00d6061a 100644 --- a/app/models/project_services/slack_messages/slack_base_message.rb +++ b/app/models/project_services/slack_service/slack_base_message.rb @@ -1,7 +1,7 @@ require 'slack-notifier' -module SlackMessages - class SlackBaseMessage +class SlackService + class BaseMessage def initialize(params) raise NotImplementedError end diff --git a/app/models/project_services/slack_messages/slack_issue_message.rb b/app/models/project_services/slack_service/slack_issue_message.rb similarity index 94% rename from app/models/project_services/slack_messages/slack_issue_message.rb rename to app/models/project_services/slack_service/slack_issue_message.rb index 0c3a492aae..cb2e3f7421 100644 --- a/app/models/project_services/slack_messages/slack_issue_message.rb +++ b/app/models/project_services/slack_service/slack_issue_message.rb @@ -1,5 +1,5 @@ -module SlackMessages - class SlackIssueMessage < SlackBaseMessage +module SlackService + class IssueMessage < BaseMessage attr_reader :username attr_reader :title attr_reader :project_name diff --git a/app/models/project_services/slack_messages/slack_merge_message.rb b/app/models/project_services/slack_service/slack_merge_message.rb similarity index 94% rename from app/models/project_services/slack_messages/slack_merge_message.rb rename to app/models/project_services/slack_service/slack_merge_message.rb index bc49a963a9..309983e9f1 100644 --- a/app/models/project_services/slack_messages/slack_merge_message.rb +++ b/app/models/project_services/slack_service/slack_merge_message.rb @@ -1,5 +1,5 @@ -module SlackMessages - class SlackMergeMessage < SlackBaseMessage +module SlackService + class MergeMessage < BaseMessage attr_reader :username attr_reader :project_name attr_reader :project_url diff --git a/app/models/project_services/slack_messages/slack_push_message.rb b/app/models/project_services/slack_service/slack_push_message.rb similarity index 97% rename from app/models/project_services/slack_messages/slack_push_message.rb rename to app/models/project_services/slack_service/slack_push_message.rb index c7769bbeda..ab2d48f9fb 100644 --- a/app/models/project_services/slack_messages/slack_push_message.rb +++ b/app/models/project_services/slack_service/slack_push_message.rb @@ -1,7 +1,7 @@ require 'slack-notifier' -module SlackMessages - class SlackPushMessage < SlackBaseMessage +module SlackService + class PushMessage < BaseMessage attr_reader :after attr_reader :before attr_reader :commits From 19f04cf989a75f425af09a8551957dae42b1ff31 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 20 Feb 2015 14:49:36 +0100 Subject: [PATCH 020/143] Execute services for tag push. --- app/services/git_tag_push_service.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb index 46d8987f12..5fd8f642fa 100644 --- a/app/services/git_tag_push_service.rb +++ b/app/services/git_tag_push_service.rb @@ -8,6 +8,7 @@ class GitTagPushService EventCreateService.new.push(project, user, @push_data) project.repository.expire_cache project.execute_hooks(@push_data.dup, :tag_push_hooks) + project.execute_services(@push_data.dup, :tag_push_hooks) if project.gitlab_ci? project.gitlab_ci_service.async_execute(@push_data) From d86c0cda24a76c9330b5fed59e857ce9e4150b9b Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 20 Feb 2015 16:05:40 +0100 Subject: [PATCH 021/143] Fix specs. --- app/models/project_services/slack_service.rb | 2 +- .../{slack_base_message.rb => base_message.rb} | 0 .../{slack_issue_message.rb => issue_message.rb} | 2 +- .../{slack_merge_message.rb => merge_message.rb} | 2 +- .../{slack_push_message.rb => push_message.rb} | 4 +--- .../issue_message_spec.rb} | 4 ++-- .../merge_message_spec.rb} | 4 ++-- .../push_message_spec.rb} | 8 ++++---- 8 files changed, 12 insertions(+), 14 deletions(-) rename app/models/project_services/slack_service/{slack_base_message.rb => base_message.rb} (100%) rename app/models/project_services/slack_service/{slack_issue_message.rb => issue_message.rb} (98%) rename app/models/project_services/slack_service/{slack_merge_message.rb => merge_message.rb} (98%) rename app/models/project_services/slack_service/{slack_push_message.rb => push_message.rb} (98%) rename spec/models/project_services/{slack_messages/slack_issue_message_spec.rb => slack_service/issue_message_spec.rb} (92%) rename spec/models/project_services/{slack_messages/slack_merge_message_spec.rb => slack_service/merge_message_spec.rb} (92%) rename spec/models/project_services/{slack_messages/slack_push_message_spec.rb => slack_service/push_message_spec.rb} (87%) diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index 8289e47403..279abad808 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -93,4 +93,4 @@ end require "slack_service/issue_message" require "slack_service/push_message" -require "slack_service/merge_message" \ No newline at end of file +require "slack_service/merge_message" diff --git a/app/models/project_services/slack_service/slack_base_message.rb b/app/models/project_services/slack_service/base_message.rb similarity index 100% rename from app/models/project_services/slack_service/slack_base_message.rb rename to app/models/project_services/slack_service/base_message.rb diff --git a/app/models/project_services/slack_service/slack_issue_message.rb b/app/models/project_services/slack_service/issue_message.rb similarity index 98% rename from app/models/project_services/slack_service/slack_issue_message.rb rename to app/models/project_services/slack_service/issue_message.rb index cb2e3f7421..e2fed0bb1b 100644 --- a/app/models/project_services/slack_service/slack_issue_message.rb +++ b/app/models/project_services/slack_service/issue_message.rb @@ -1,4 +1,4 @@ -module SlackService +class SlackService class IssueMessage < BaseMessage attr_reader :username attr_reader :title diff --git a/app/models/project_services/slack_service/slack_merge_message.rb b/app/models/project_services/slack_service/merge_message.rb similarity index 98% rename from app/models/project_services/slack_service/slack_merge_message.rb rename to app/models/project_services/slack_service/merge_message.rb index 309983e9f1..4dcce1d15a 100644 --- a/app/models/project_services/slack_service/slack_merge_message.rb +++ b/app/models/project_services/slack_service/merge_message.rb @@ -1,4 +1,4 @@ -module SlackService +class SlackService class MergeMessage < BaseMessage attr_reader :username attr_reader :project_name diff --git a/app/models/project_services/slack_service/slack_push_message.rb b/app/models/project_services/slack_service/push_message.rb similarity index 98% rename from app/models/project_services/slack_service/slack_push_message.rb rename to app/models/project_services/slack_service/push_message.rb index ab2d48f9fb..2e566bc317 100644 --- a/app/models/project_services/slack_service/slack_push_message.rb +++ b/app/models/project_services/slack_service/push_message.rb @@ -1,6 +1,4 @@ -require 'slack-notifier' - -module SlackService +class SlackService class PushMessage < BaseMessage attr_reader :after attr_reader :before diff --git a/spec/models/project_services/slack_messages/slack_issue_message_spec.rb b/spec/models/project_services/slack_service/issue_message_spec.rb similarity index 92% rename from spec/models/project_services/slack_messages/slack_issue_message_spec.rb rename to spec/models/project_services/slack_service/issue_message_spec.rb index 49a8eea0a5..a23a7cc068 100644 --- a/spec/models/project_services/slack_messages/slack_issue_message_spec.rb +++ b/spec/models/project_services/slack_service/issue_message_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -describe SlackMessages::SlackIssueMessage do - subject { SlackMessages::SlackIssueMessage.new(args) } +describe SlackService::IssueMessage do + subject { SlackService::IssueMessage.new(args) } let(:args) { { diff --git a/spec/models/project_services/slack_messages/slack_merge_message_spec.rb b/spec/models/project_services/slack_service/merge_message_spec.rb similarity index 92% rename from spec/models/project_services/slack_messages/slack_merge_message_spec.rb rename to spec/models/project_services/slack_service/merge_message_spec.rb index ef76c3312e..25d03cd873 100644 --- a/spec/models/project_services/slack_messages/slack_merge_message_spec.rb +++ b/spec/models/project_services/slack_service/merge_message_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -describe SlackMessages::SlackMergeMessage do - subject { SlackMessages::SlackMergeMessage.new(args) } +describe SlackService::MergeMessage do + subject { SlackService::MergeMessage.new(args) } let(:args) { { diff --git a/spec/models/project_services/slack_messages/slack_push_message_spec.rb b/spec/models/project_services/slack_service/push_message_spec.rb similarity index 87% rename from spec/models/project_services/slack_messages/slack_push_message_spec.rb rename to spec/models/project_services/slack_service/push_message_spec.rb index f11614d692..ef0e7a6ee3 100644 --- a/spec/models/project_services/slack_messages/slack_push_message_spec.rb +++ b/spec/models/project_services/slack_service/push_message_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -describe SlackMessages::SlackPushMessage do - subject { SlackMessages::SlackPushMessage.new(args) } +describe SlackService::PushMessage do + subject { SlackService::PushMessage.new(args) } let(:args) { { @@ -31,8 +31,8 @@ describe SlackMessages::SlackPushMessage do ) expect(subject.attachments).to eq([ { - text: ": message1 - author1\n"\ - ": message2 - author2", + text: ": message1 - author1\n"\ + ": message2 - author2", color: color, } ]) From f13567edc4b9ce68179d12562a711540c8994206 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 24 Feb 2015 14:29:21 +0100 Subject: [PATCH 022/143] Only execute GitlabCiService for push events. --- app/models/project_services/gitlab_ci_service.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb index a64b24b5ef..34a20f5579 100644 --- a/app/models/project_services/gitlab_ci_service.rb +++ b/app/models/project_services/gitlab_ci_service.rb @@ -22,8 +22,6 @@ class GitlabCiService < CiService validates :project_url, presence: true, if: :activated? validates :token, presence: true, if: :activated? - delegate :execute, to: :service_hook, prefix: nil - after_save :compose_service_hook, if: :activated? def compose_service_hook @@ -32,6 +30,13 @@ class GitlabCiService < CiService hook.save end + def execute(data) + object_kind = data[:object_kind] + return unless object_kind == "push" + + service_hook.execute(data) + end + def commit_status_path(sha) project_url + "/commits/#{sha}/status.json?token=#{token}" end From ca56d9ff9ff8b28172d5e3dae7e09b77e2e6b835 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 24 Feb 2015 14:29:41 +0100 Subject: [PATCH 023/143] Don't execute GitlabCiService twice for pushed tags. --- app/services/git_tag_push_service.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb index 5fd8f642fa..725ef01ff2 100644 --- a/app/services/git_tag_push_service.rb +++ b/app/services/git_tag_push_service.rb @@ -10,10 +10,6 @@ class GitTagPushService project.execute_hooks(@push_data.dup, :tag_push_hooks) project.execute_services(@push_data.dup, :tag_push_hooks) - if project.gitlab_ci? - project.gitlab_ci_service.async_execute(@push_data) - end - true end From bbcb12f2719d5d8747339ad1bcb3457217870dc2 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 24 Feb 2015 14:31:08 +0100 Subject: [PATCH 024/143] Execute tag_push services and hooks when tag is created through web UI. --- app/services/create_tag_service.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb index a735d3f7f2..850077006e 100644 --- a/app/services/create_tag_service.rb +++ b/app/services/create_tag_service.rb @@ -21,12 +21,12 @@ class CreateTagService < BaseService new_tag = repository.find_tag(tag_name) if new_tag - if project.gitlab_ci? - push_data = create_push_data(project, current_user, new_tag) - project.gitlab_ci_service.async_execute(push_data) - end - EventCreateService.new.push_ref(project, current_user, new_tag, 'add', 'refs/tags') + + push_data = create_push_data(project, current_user, new_tag) + project.execute_hooks(push_data.dup, :tag_push_hooks) + project.execute_services(push_data.dup, :tag_push_hooks) + success(new_tag) else error('Invalid reference name') From 85fa334eb6fd2069287a660e6ffa2295ea3a787f Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 24 Feb 2015 14:35:14 +0100 Subject: [PATCH 025/143] Execute GitlabCiService for both push and tag_push events. --- app/models/project_services/gitlab_ci_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb index 34a20f5579..bfc7a1fee3 100644 --- a/app/models/project_services/gitlab_ci_service.rb +++ b/app/models/project_services/gitlab_ci_service.rb @@ -32,7 +32,7 @@ class GitlabCiService < CiService def execute(data) object_kind = data[:object_kind] - return unless object_kind == "push" + return unless %w(push tag_push).include?(object_kind) service_hook.execute(data) end From d57e809cbd56aea8a49c6595663fc4b7250c5a34 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Sat, 28 Feb 2015 17:33:18 +0100 Subject: [PATCH 026/143] Set supported events per project service. --- app/models/project_services/asana_service.rb | 7 ++- .../project_services/assembla_service.rb | 7 ++- app/models/project_services/bamboo_service.rb | 7 ++- .../project_services/buildbox_service.rb | 7 ++- .../project_services/campfire_service.rb | 7 ++- app/models/project_services/ci_service.rb | 4 ++ .../emails_on_push_service.rb | 7 ++- .../project_services/flowdock_service.rb | 7 ++- .../project_services/gemnasium_service.rb | 7 ++- .../project_services/gitlab_ci_service.rb | 7 ++- .../project_services/hipchat_service.rb | 7 ++- .../project_services/issue_tracker_service.rb | 7 ++- .../pivotaltracker_service.rb | 7 ++- .../project_services/pushover_service.rb | 7 ++- app/models/project_services/slack_service.rb | 5 ++ .../project_services/teamcity_service.rb | 7 ++- app/models/service.rb | 6 ++ app/views/admin/services/_form.html.haml | 37 +++++++++++ app/views/projects/services/_form.html.haml | 63 ++++++++++--------- 19 files changed, 156 insertions(+), 57 deletions(-) diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index a5686c48bc..8ad1ad6267 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -65,9 +65,12 @@ automatically inspected. Leave blank to include all branches.' ] end + def supported_events + %w(push) + end + def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) Asana.configure do |client| client.api_key = api_key diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb index 01c647c170..02aa7c972e 100644 --- a/app/models/project_services/assembla_service.rb +++ b/app/models/project_services/assembla_service.rb @@ -42,9 +42,12 @@ class AssemblaService < Service ] end + def supported_events + %w(push) + end + def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) url = "https://atlas.assembla.com/spaces/#{subdomain}/github_tool?secret_key=#{token}" AssemblaService.post(url, body: { payload: data }.to_json, headers: { 'Content-Type' => 'application/json' }) diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb index 6ff52af040..6c6d74c615 100644 --- a/app/models/project_services/bamboo_service.rb +++ b/app/models/project_services/bamboo_service.rb @@ -73,6 +73,10 @@ class BambooService < CiService ] end + def supported_events + %w(push) + end + def build_info(sha) url = URI.parse("#{bamboo_url}/rest/api/latest/result?label=#{sha}") @@ -123,8 +127,7 @@ class BambooService < CiService end def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) # Bamboo requires a GET and does not take any data. self.class.get("#{bamboo_url}/updateAndBuild.action?buildKey=#{build_key}", diff --git a/app/models/project_services/buildbox_service.rb b/app/models/project_services/buildbox_service.rb index 201bfc560a..96428c9171 100644 --- a/app/models/project_services/buildbox_service.rb +++ b/app/models/project_services/buildbox_service.rb @@ -36,9 +36,12 @@ class BuildboxService < CiService hook.save end + def supported_events + %w(push) + end + def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) service_hook.execute(data) end diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb index 7af6882329..2f86fbe7a0 100644 --- a/app/models/project_services/campfire_service.rb +++ b/app/models/project_services/campfire_service.rb @@ -41,9 +41,12 @@ class CampfireService < Service ] end + def supported_events + %w(push) + end + def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) room = gate.find_room_by_name(self.room) return true unless room diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb index e58d6d7a23..646783c873 100644 --- a/app/models/project_services/ci_service.rb +++ b/app/models/project_services/ci_service.rb @@ -25,6 +25,10 @@ class CiService < Service :ci end + def supported_events + %w(push) + end + # Return complete url to build page # # Ex. diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb index 1b7ce481c1..21041e08a2 100644 --- a/app/models/project_services/emails_on_push_service.rb +++ b/app/models/project_services/emails_on_push_service.rb @@ -33,9 +33,12 @@ class EmailsOnPushService < Service 'emails_on_push' end + def supported_events + %w(push) + end + def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) EmailsOnPushWorker.perform_async(project_id, recipients, data) end diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb index e4ea84cb61..443dca72a8 100644 --- a/app/models/project_services/flowdock_service.rb +++ b/app/models/project_services/flowdock_service.rb @@ -41,9 +41,12 @@ class FlowdockService < Service ] end + def supported_events + %w(push) + end + def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) Flowdock::Git.post( data[:ref], diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb index ada61b7804..41eedc215d 100644 --- a/app/models/project_services/gemnasium_service.rb +++ b/app/models/project_services/gemnasium_service.rb @@ -42,9 +42,12 @@ class GemnasiumService < Service ] end + def supported_events + %w(push) + end + def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) Gemnasium::GitlabService.execute( ref: data[:ref], diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb index bfc7a1fee3..02bf305f8f 100644 --- a/app/models/project_services/gitlab_ci_service.rb +++ b/app/models/project_services/gitlab_ci_service.rb @@ -30,9 +30,12 @@ class GitlabCiService < CiService hook.save end + def supported_events + %w(push tag_push) + end + def execute(data) - object_kind = data[:object_kind] - return unless %w(push tag_push).include?(object_kind) + return unless supported_events.include?(data[:object_kind]) service_hook.execute(data) end diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 965ecdc684..b85863d2f0 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -44,9 +44,12 @@ class HipchatService < Service ] end + def supported_events + %w(push) + end + def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) gate[room].send('GitLab', create_message(data)) end diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb index 0d9e5c1399..bfc65b5379 100644 --- a/app/models/project_services/issue_tracker_service.rb +++ b/app/models/project_services/issue_tracker_service.rb @@ -69,9 +69,12 @@ class IssueTrackerService < Service end end + def supported_events + %w(push) + end + def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) message = "#{self.type} was unable to reach #{self.project_url}. Check the url and try again." result = false diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb index dd9e7f35c1..a2fa9788f1 100644 --- a/app/models/project_services/pivotaltracker_service.rb +++ b/app/models/project_services/pivotaltracker_service.rb @@ -41,9 +41,12 @@ class PivotaltrackerService < Service ] end + def supported_events + %w(push) + end + def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) url = 'https://www.pivotaltracker.com/services/v5/source_commits' data[:commits].each do |commit| diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb index a715e7b2cc..586d9e94a9 100644 --- a/app/models/project_services/pushover_service.rb +++ b/app/models/project_services/pushover_service.rb @@ -80,9 +80,12 @@ class PushoverService < Service ] end + def supported_events + %w(push) + end + def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) ref = data[:ref].gsub('refs/heads/', '') before = data[:before] diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index 279abad808..64d6f4327b 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -42,7 +42,12 @@ class SlackService < Service ] end + def supported_events + %w(push issue merge_request) + end + def execute(data) + return unless supported_events.include?(data[:object_kind]) return unless webhook.present? object_kind = data[:object_kind] diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb index 07facfb6d0..686e6225a2 100644 --- a/app/models/project_services/teamcity_service.rb +++ b/app/models/project_services/teamcity_service.rb @@ -61,6 +61,10 @@ class TeamcityService < CiService 'teamcity' end + def supported_events + %w(push) + end + def fields [ { type: 'text', name: 'teamcity_url', @@ -120,8 +124,7 @@ class TeamcityService < CiService end def execute(data) - object_kind = data[:object_kind] - return unless object_kind == "push" + return unless supported_events.include?(data[:object_kind]) auth = { username: username, diff --git a/app/models/service.rb b/app/models/service.rb index 9d6866f26d..98bd40ae95 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -80,6 +80,10 @@ class Service < ActiveRecord::Base [] end + def supported_events + %w(push tag_push issue merge_request) + end + def execute # implement inside child end @@ -105,6 +109,8 @@ class Service < ActiveRecord::Base end def async_execute(data) + return unless supported_events.include?(data[:object_kind]) + Sidekiq::Client.enqueue(ProjectServiceWorker, id, data) end diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml index 5df8849317..62f4001ca6 100644 --- a/app/views/admin/services/_form.html.haml +++ b/app/views/admin/services/_form.html.haml @@ -14,6 +14,43 @@ = preserve do = markdown @service.help + .form-group + = f.label :url, "Trigger", class: 'control-label' + - if @service.supported_events.length > 1 + .col-sm-10 + - if @service.supported_events.include?("push") + %div + = f.check_box :push_events, class: 'pull-left' + .prepend-left-20 + = f.label :push_events, class: 'list-label' do + %strong Push events + %p.light + This url will be triggered by a push to the repository + - if @service.supported_events.include?("tag_push") + %div + = f.check_box :tag_push_events, class: 'pull-left' + .prepend-left-20 + = f.label :tag_push_events, class: 'list-label' do + %strong Tag push events + %p.light + This url will be triggered when a new tag is pushed to the repository + - if @service.supported_events.include?("issue") + %div + = f.check_box :issues_events, class: 'pull-left' + .prepend-left-20 + = f.label :issues_events, class: 'list-label' do + %strong Issues events + %p.light + This url will be triggered when an issue is created + - if @service.supported_events.include?("merge_request") + %div + = f.check_box :merge_requests_events, class: 'pull-left' + .prepend-left-20 + = f.label :merge_requests_events, class: 'list-label' do + %strong Merge Request events + %p.light + This url will be triggered when a merge request is created + - @service.fields.each do |field| - name = field[:name] - value = @service.send(name) unless field[:type] == 'password' diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index 0519c8150e..55ac85c32b 100644 --- a/app/views/projects/services/_form.html.haml +++ b/app/views/projects/services/_form.html.haml @@ -29,35 +29,40 @@ .form-group = f.label :url, "Trigger", class: 'control-label' - .col-sm-10 - %div - = f.check_box :push_events, class: 'pull-left' - .prepend-left-20 - = f.label :push_events, class: 'list-label' do - %strong Push events - %p.light - This url will be triggered by a push to the repository - %div - = f.check_box :tag_push_events, class: 'pull-left' - .prepend-left-20 - = f.label :tag_push_events, class: 'list-label' do - %strong Tag push events - %p.light - This url will be triggered when a new tag is pushed to the repository - %div - = f.check_box :issues_events, class: 'pull-left' - .prepend-left-20 - = f.label :issues_events, class: 'list-label' do - %strong Issues events - %p.light - This url will be triggered when an issue is created - %div - = f.check_box :merge_requests_events, class: 'pull-left' - .prepend-left-20 - = f.label :merge_requests_events, class: 'list-label' do - %strong Merge Request events - %p.light - This url will be triggered when a merge request is created + - if @service.supported_events.length > 1 + .col-sm-10 + - if @service.supported_events.include?("push") + %div + = f.check_box :push_events, class: 'pull-left' + .prepend-left-20 + = f.label :push_events, class: 'list-label' do + %strong Push events + %p.light + This url will be triggered by a push to the repository + - if @service.supported_events.include?("tag_push") + %div + = f.check_box :tag_push_events, class: 'pull-left' + .prepend-left-20 + = f.label :tag_push_events, class: 'list-label' do + %strong Tag push events + %p.light + This url will be triggered when a new tag is pushed to the repository + - if @service.supported_events.include?("issue") + %div + = f.check_box :issues_events, class: 'pull-left' + .prepend-left-20 + = f.label :issues_events, class: 'list-label' do + %strong Issues events + %p.light + This url will be triggered when an issue is created + - if @service.supported_events.include?("merge_request") + %div + = f.check_box :merge_requests_events, class: 'pull-left' + .prepend-left-20 + = f.label :merge_requests_events, class: 'list-label' do + %strong Merge Request events + %p.light + This url will be triggered when a merge request is created - @service.fields.each do |field| - name = field[:name] From 5c910b94cef084fc1fae398fdf72a220f800e7ad Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Sat, 28 Feb 2015 17:41:01 +0100 Subject: [PATCH 027/143] Set correct object_kind on tag push data. --- app/services/create_tag_service.rb | 4 +++- app/services/git_tag_push_service.rb | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb index 850077006e..8cd65724cb 100644 --- a/app/services/create_tag_service.rb +++ b/app/services/create_tag_service.rb @@ -40,7 +40,9 @@ class CreateTagService < BaseService end def create_push_data(project, user, tag) - Gitlab::PushDataBuilder. + data = Gitlab::PushDataBuilder. build(project, user, Gitlab::Git::BLANK_SHA, tag.target, 'refs/tags/' + tag.name, []) + data[:object_kind] = "tag_push" + data end end diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb index 725ef01ff2..cd92f50b02 100644 --- a/app/services/git_tag_push_service.rb +++ b/app/services/git_tag_push_service.rb @@ -16,7 +16,8 @@ class GitTagPushService private def create_push_data(oldrev, newrev, ref) - Gitlab::PushDataBuilder. - build(project, user, oldrev, newrev, ref, []) + data = Gitlab::PushDataBuilder.build(project, user, oldrev, newrev, ref, []) + data[:object_kind] = "tag_push" + data end end From 2c7baed3946dcc724e091698978419a18c7d6930 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 3 Mar 2015 11:20:01 +0100 Subject: [PATCH 028/143] Fix changelog. --- CHANGELOG | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8011817d0a..50e18f1006 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,4 @@ Please view this file on the master branch, on stable branches it's out of date. -v 7.9.0 (unreleased) - - Added issue and merge request events to Slack service (Stan Hu) - - Fix broken access control for note attachments (Hannes Rosenögger) v 7.9.0 (unreleased) - Move labels/milestones tabs to sidebar @@ -19,6 +16,7 @@ v 7.9.0 (unreleased) - Allow user confirmation to be skipped for new users via API - Add a service to send updates to an Irker gateway (Romain Coltel) - Add brakeman (security scanner for Ruby on Rails) + - Added issue and merge request events to Slack service (Stan Hu) v 7.8.1 - Fix run of custom post receive hooks From fc6160816119504e1cea0954453cd557231341a1 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 3 Mar 2015 13:09:45 +0100 Subject: [PATCH 029/143] Fix specs. --- spec/models/project_services/slack_service_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb index 49c48d0b65..9024e53f0f 100644 --- a/spec/models/project_services/slack_service_spec.rb +++ b/spec/models/project_services/slack_service_spec.rb @@ -99,8 +99,8 @@ describe SlackService do with(webhook_url, username: username). and_return( double(:slack_service).as_null_object - ) - slack.execute(sample_data) + ) + slack.execute(push_sample_data) end it 'should use the channel as an option when it is configured' do @@ -110,7 +110,7 @@ describe SlackService do and_return( double(:slack_service).as_null_object ) - slack.execute(sample_data) + slack.execute(push_sample_data) end end end From fbc3cb69c327e52a002c7909c257c43c9a2f5ba5 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 3 Mar 2015 16:19:37 +0100 Subject: [PATCH 030/143] Add dashboard milestones. --- .../dashboard/milestones_controller.rb | 34 ++++++++ .../groups/milestones_controller.rb | 10 +-- app/helpers/milestones_helper.rb | 2 + .../dashboard/milestones/_issue.html.haml | 10 +++ .../dashboard/milestones/_issues.html.haml | 6 ++ .../milestones/_merge_request.html.haml | 10 +++ .../milestones/_merge_requests.html.haml | 6 ++ .../dashboard/milestones/index.html.haml | 39 +++++++++ app/views/dashboard/milestones/show.html.haml | 82 +++++++++++++++++++ app/views/groups/milestones/index.html.haml | 7 +- app/views/layouts/nav/_dashboard.html.haml | 5 ++ config/routes.rb | 6 +- 12 files changed, 208 insertions(+), 9 deletions(-) create mode 100644 app/controllers/dashboard/milestones_controller.rb create mode 100644 app/views/dashboard/milestones/_issue.html.haml create mode 100644 app/views/dashboard/milestones/_issues.html.haml create mode 100644 app/views/dashboard/milestones/_merge_request.html.haml create mode 100644 app/views/dashboard/milestones/_merge_requests.html.haml create mode 100644 app/views/dashboard/milestones/index.html.haml create mode 100644 app/views/dashboard/milestones/show.html.haml diff --git a/app/controllers/dashboard/milestones_controller.rb b/app/controllers/dashboard/milestones_controller.rb new file mode 100644 index 0000000000..386e283f3a --- /dev/null +++ b/app/controllers/dashboard/milestones_controller.rb @@ -0,0 +1,34 @@ +class Dashboard::MilestonesController < ApplicationController + before_filter :load_projects + + def index + project_milestones = case params[:state] + when 'all'; state + when 'closed'; state('closed') + else state('active') + end + @dashboard_milestones = Milestones::GroupService.new(project_milestones).execute + @dashboard_milestones = Kaminari.paginate_array(@dashboard_milestones).page(params[:page]).per(30) + end + + def show + project_milestones = Milestone.where(project_id: @projects).order("due_date ASC") + @dashboard_milestone = Milestones::GroupService.new(project_milestones).milestone(title) + end + + private + + def load_projects + @projects = current_user.authorized_projects.sorted_by_activity.non_archived + end + + def title + params[:title] + end + + def state(state = nil) + conditions = { project_id: @projects } + conditions.reverse_merge!(state: state) if state + Milestone.where(conditions).order("title ASC") + end +end diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb index 860d8e0392..6802e529b5 100644 --- a/app/controllers/groups/milestones_controller.rb +++ b/app/controllers/groups/milestones_controller.rb @@ -4,10 +4,10 @@ class Groups::MilestonesController < ApplicationController before_filter :authorize_group_milestone!, only: :update def index - project_milestones = case params[:status] - when 'all'; status - when 'closed'; status('closed') - else status('active') + project_milestones = case params[:state] + when 'all'; state + when 'closed'; state('closed') + else state('active') end @group_milestones = Milestones::GroupService.new(project_milestones).execute @group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(30) @@ -44,7 +44,7 @@ class Groups::MilestonesController < ApplicationController params[:title] end - def status(state = nil) + def state(state = nil) conditions = { project_id: group.projects } conditions.reverse_merge!(state: state) if state Milestone.where(conditions).order("title ASC") diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb index 47fa147dcc..3383b1ae5b 100644 --- a/app/helpers/milestones_helper.rb +++ b/app/helpers/milestones_helper.rb @@ -4,6 +4,8 @@ module MilestonesHelper namespace_project_milestones_path(@project.namespace, @project, opts) elsif @group group_milestones_path(@group, opts) + else + dashboard_milestones_path(opts) end end end diff --git a/app/views/dashboard/milestones/_issue.html.haml b/app/views/dashboard/milestones/_issue.html.haml new file mode 100644 index 0000000000..f689b9698e --- /dev/null +++ b/app/views/dashboard/milestones/_issue.html.haml @@ -0,0 +1,10 @@ +%li{ id: dom_id(issue, 'sortable'), class: 'issue-row', 'data-iid' => issue.iid } + %span.milestone-row + - project = issue.project + %strong #{project.name_with_namespace} · + = link_to [project.namespace.becomes(Namespace), project, issue] do + %span.cgray ##{issue.iid} + = link_to_gfm issue.title, [project.namespace.becomes(Namespace), project, issue], title: issue.title + .pull-right.assignee-icon + - if issue.assignee + = image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16" diff --git a/app/views/dashboard/milestones/_issues.html.haml b/app/views/dashboard/milestones/_issues.html.haml new file mode 100644 index 0000000000..9f350b772b --- /dev/null +++ b/app/views/dashboard/milestones/_issues.html.haml @@ -0,0 +1,6 @@ +.panel.panel-default + .panel-heading= title + %ul{ class: "well-list issues-sortable-list" } + - if issues + - issues.each do |issue| + = render 'issue', issue: issue diff --git a/app/views/dashboard/milestones/_merge_request.html.haml b/app/views/dashboard/milestones/_merge_request.html.haml new file mode 100644 index 0000000000..8f5c4cce52 --- /dev/null +++ b/app/views/dashboard/milestones/_merge_request.html.haml @@ -0,0 +1,10 @@ +%li{ id: dom_id(merge_request, 'sortable'), class: 'mr-row', 'data-iid' => merge_request.iid } + %span.milestone-row + - project = merge_request.project + %strong #{project.name_with_namespace} · + = link_to [project.namespace.becomes(Namespace), project, merge_request] do + %span.cgray ##{merge_request.iid} + = link_to_gfm merge_request.title, [project.namespace.becomes(Namespace), project, merge_request], title: merge_request.title + .pull-right.assignee-icon + - if merge_request.assignee + = image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16" diff --git a/app/views/dashboard/milestones/_merge_requests.html.haml b/app/views/dashboard/milestones/_merge_requests.html.haml new file mode 100644 index 0000000000..50057e2c63 --- /dev/null +++ b/app/views/dashboard/milestones/_merge_requests.html.haml @@ -0,0 +1,6 @@ +.panel.panel-default + .panel-heading= title + %ul{ class: "well-list merge_requests-sortable-list" } + - if merge_requests + - merge_requests.each do |merge_request| + = render 'merge_request', merge_request: merge_request diff --git a/app/views/dashboard/milestones/index.html.haml b/app/views/dashboard/milestones/index.html.haml new file mode 100644 index 0000000000..65fc589851 --- /dev/null +++ b/app/views/dashboard/milestones/index.html.haml @@ -0,0 +1,39 @@ +%h3.page-title + Milestones + %span.pull-right #{@dashboard_milestones.count} milestones + +%p.light + List all milestones from all projects you have access to. + +%hr + += render 'shared/milestones_filter' +.milestones + .panel.panel-default + %ul.well-list + - if @dashboard_milestones.blank? + %li + .nothing-here-block No milestones to show + - else + - @dashboard_milestones.each do |milestone| + %li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) } + %h4 + = link_to_gfm truncate(milestone.title, length: 100), dashboard_milestone_path(milestone.safe_title, title: milestone.title) + %div + %div + = link_to dashboard_milestone_path(milestone.safe_title, title: milestone.title) do + = pluralize milestone.issue_count, 'Issue' +   + = link_to dashboard_milestone_path(milestone.safe_title, title: milestone.title) do + = pluralize milestone.merge_requests_count, 'Merge Request' +   + %span.light #{milestone.percent_complete}% complete + .progress.progress-info + .progress-bar{style: "width: #{milestone.percent_complete}%;"} + %div + %br + - milestone.milestones.each do |milestone| + = link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone) do + %span.label.label-default + = milestone.project.name_with_namespace + = paginate @dashboard_milestones, theme: "gitlab" diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml new file mode 100644 index 0000000000..a45a52001b --- /dev/null +++ b/app/views/dashboard/milestones/show.html.haml @@ -0,0 +1,82 @@ +%h4.page-title + .issue-box{ class: "issue-box-#{@dashboard_milestone.closed? ? 'closed' : 'open'}" } + - if @dashboard_milestone.closed? + Closed + - else + Open + Milestone #{@dashboard_milestone.title} + +%hr +- if (@dashboard_milestone.total_items_count == @dashboard_milestone.closed_items_count) && @dashboard_milestone.active? + .alert.alert-success + %span All issues for this milestone are closed. You may close the milestone now. + +.description +%table.table + %thead + %tr + %th Project + %th Open issues + %th State + %th Due date + - @dashboard_milestone.milestones.each do |milestone| + %tr + %td + = link_to "#{milestone.project.name_with_namespace}", namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone) + %td + = milestone.issues.opened.count + %td + - if milestone.closed? + Closed + - else + Open + %td + = milestone.expires_at + +.context + %p.lead + Progress: + #{@dashboard_milestone.closed_items_count} closed + – + #{@dashboard_milestone.open_items_count} open + .progress.progress-info + .progress-bar{style: "width: #{@dashboard_milestone.percent_complete}%;"} + +%ul.nav.nav-tabs + %li.active + = link_to '#tab-issues', 'data-toggle' => 'tab' do + Issues + %span.badge= @dashboard_milestone.issue_count + %li + = link_to '#tab-merge-requests', 'data-toggle' => 'tab' do + Merge Requests + %span.badge= @dashboard_milestone.merge_requests_count + %li + = link_to '#tab-participants', 'data-toggle' => 'tab' do + Participants + %span.badge= @dashboard_milestone.participants.count + +.tab-content + .tab-pane.active#tab-issues + .row + .col-md-6 + = render 'issues', title: "Open", issues: @dashboard_milestone.opened_issues + .col-md-6 + = render 'issues', title: "Closed", issues: @dashboard_milestone.closed_issues + + .tab-pane#tab-merge-requests + .row + .col-md-6 + = render 'merge_requests', title: "Open", merge_requests: @dashboard_milestone.opened_merge_requests + .col-md-6 + = render 'merge_requests', title: "Closed", merge_requests: @dashboard_milestone.closed_merge_requests + + .tab-pane#tab-participants + %ul.bordered-list + - @dashboard_milestone.participants.each do |user| + %li + = link_to user, title: user.name, class: "darken" do + = image_tag avatar_icon(user.email, 32), class: "avatar s32" + %strong= truncate(user.name, lenght: 40) + %br + %small.cgray= user.username diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml index 7f0b2832ca..fcbcb309aa 100644 --- a/app/views/groups/milestones/index.html.haml +++ b/app/views/groups/milestones/index.html.haml @@ -40,7 +40,8 @@ .progress-bar{style: "width: #{milestone.percent_complete}%;"} %div %br - - milestone.projects.each do |project| - %span.label.label-default - = project.name + - milestone.milestones.each do |milestone| + = link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone) do + %span.label.label-default + = milestone.project.name = paginate @group_milestones, theme: "gitlab" diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index 48c7c99942..304744ba25 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -9,6 +9,11 @@ %i.fa.fa-cube %span Projects + = nav_link(controller: :milestones) do + = link_to dashboard_milestones_path, title: 'Milestones' do + %i.fa.fa-clock-o + %span + Milestones = nav_link(path: 'dashboard#issues') do = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues' do %i.fa.fa-exclamation-circle diff --git a/config/routes.rb b/config/routes.rb index 6329917693..5348c86ea9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -220,6 +220,10 @@ Gitlab::Application.routes.draw do get :issues get :merge_requests end + + scope module: :dashboard do + resources :milestones, only: [:index, :show] + end end # @@ -236,7 +240,7 @@ Gitlab::Application.routes.draw do scope module: :groups do resources :group_members, only: [:create, :update, :destroy] resource :avatar, only: [:destroy] - resources :milestones + resources :milestones, only: [:index, :show, :update] end end From 4ecfcb4a1e05189372a72547103f1c2e9a23ab3b Mon Sep 17 00:00:00 2001 From: Ewan Edwards Date: Tue, 3 Mar 2015 07:38:38 -0800 Subject: [PATCH 031/143] Moved the Gmail integration line into the list of available integrations. --- doc/integration/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/integration/README.md b/doc/integration/README.md index 559a94533d..8f14c9d8b9 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -9,11 +9,10 @@ See the documentation below for details on how to configure these services. - [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab, and Google via OAuth. - [Slack](slack.md) Integrate with the Slack chat service - [OAuth2 provider](oauth_provider.md) OAuth2 application creation +- [Gmail](gitlab_buttons_in_gmail.md) Adds GitLab actions to messages Jenkins support is [available in GitLab EE](http://doc.gitlab.com/ee/integration/jenkins.html). -GitLab can also integrate with [Gmail](gitlab_buttons_in_gmail.md). - ## Project services Integration with services such as Campfire, Flowdock, Gemnasium, HipChat, Pivotal Tracker, and Slack are available in the form of a Project Service. From 443cf9723192b821b95960f91c3ce0350d77edab Mon Sep 17 00:00:00 2001 From: Sabba Petri Date: Tue, 3 Mar 2015 14:47:10 -0800 Subject: [PATCH 032/143] Changed to 'View Build Page' --- app/views/projects/merge_requests/show/_mr_ci.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/projects/merge_requests/show/_mr_ci.html.haml b/app/views/projects/merge_requests/show/_mr_ci.html.haml index ee7fd0ef15..982d04d3e3 100644 --- a/app/views/projects/merge_requests/show/_mr_ci.html.haml +++ b/app/views/projects/merge_requests/show/_mr_ci.html.haml @@ -3,21 +3,21 @@ %i.fa.fa-check %span CI build passed for #{@merge_request.last_commit_short_sha}. - = link_to "Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" + = link_to "View Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" .ci_widget.ci-failed{style: "display:none"} %i.fa.fa-times %span CI build failed for #{@merge_request.last_commit_short_sha}. - = link_to "Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" + = link_to "View Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" - [:running, :pending].each do |status| .ci_widget{class: "ci-#{status}", style: "display:none"} %i.fa.fa-clock-o %span CI build #{status} for #{@merge_request.last_commit_short_sha}. - = link_to "Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" + = link_to "View Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" .ci_widget %i.fa.fa-spinner From dc7c90f132321497d9a914734f902762d2022a3a Mon Sep 17 00:00:00 2001 From: Sabba Petri Date: Tue, 3 Mar 2015 14:50:02 -0800 Subject: [PATCH 033/143] Changed casing --- app/views/projects/merge_requests/show/_mr_ci.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/projects/merge_requests/show/_mr_ci.html.haml b/app/views/projects/merge_requests/show/_mr_ci.html.haml index 982d04d3e3..85a7103f3b 100644 --- a/app/views/projects/merge_requests/show/_mr_ci.html.haml +++ b/app/views/projects/merge_requests/show/_mr_ci.html.haml @@ -3,21 +3,21 @@ %i.fa.fa-check %span CI build passed for #{@merge_request.last_commit_short_sha}. - = link_to "View Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" + = link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" .ci_widget.ci-failed{style: "display:none"} %i.fa.fa-times %span CI build failed for #{@merge_request.last_commit_short_sha}. - = link_to "View Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" + = link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" - [:running, :pending].each do |status| .ci_widget{class: "ci-#{status}", style: "display:none"} %i.fa.fa-clock-o %span CI build #{status} for #{@merge_request.last_commit_short_sha}. - = link_to "View Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" + = link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" .ci_widget %i.fa.fa-spinner From b5ec0d6d450b32fa00d95d864fa797f64e9ca17e Mon Sep 17 00:00:00 2001 From: Sabba Petri Date: Tue, 3 Mar 2015 14:05:31 -0800 Subject: [PATCH 034/143] Spelling change Commit Statistics --- app/views/projects/graphs/commits.html.haml | 2 +- features/steps/project/graph.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml index a189a48713..4a5d09b950 100644 --- a/app/views/projects/graphs/commits.html.haml +++ b/app/views/projects/graphs/commits.html.haml @@ -1,7 +1,7 @@ = render 'head' %p.lead - Commits statistic for + Commit statistics for %strong #{@repository.root_ref} #{@commits_graph.start_date.strftime('%b %d')} - #{@commits_graph.end_date.strftime('%b %d')} diff --git a/features/steps/project/graph.rb b/features/steps/project/graph.rb index bc07c3d413..a2807c340f 100644 --- a/features/steps/project/graph.rb +++ b/features/steps/project/graph.rb @@ -17,7 +17,7 @@ class Spinach::Features::ProjectGraph < Spinach::FeatureSteps end step 'page should have commits graphs' do - page.should have_content "Commits statistic for master" + page.should have_content "Commit statistics for master" page.should have_content "Commits per day of month" end end From f24e46b8f01624bffc37f2f800cb03bcafc43591 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 3 Mar 2015 21:59:43 -0800 Subject: [PATCH 035/143] Remove pull-review badge since we dont use it --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index b4f28a41be..0563ceca40 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,6 @@ The source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab. - [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master) -- [![PullReview stats](https://www.pullreview.com/gitlab/gitlab-org/gitlab-ce/badges/master.svg?)](https://www.pullreview.com/gitlab.gitlab.com/gitlab-org/gitlab-ce/reviews/master) - ## Website On [about.gitlab.com](https://about.gitlab.com/) you can find more information about: From 53aec08d0295c8c33286f634c1f4ece81271c04d Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 4 Mar 2015 10:13:16 +0100 Subject: [PATCH 036/143] Add changelog entry. --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 6a28772097..d088174ad7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ v 7.9.0 (unreleased) - Allow user confirmation to be skipped for new users via API - Add a service to send updates to an Irker gateway (Romain Coltel) - Add brakeman (security scanner for Ruby on Rails) + - Add grouped milestones from all projects to dashboard. v 7.8.1 - Fix run of custom post receive hooks From af522ede14cad4605bc7f0137ddf6950974eccce Mon Sep 17 00:00:00 2001 From: fabien Date: Wed, 4 Mar 2015 16:22:26 +0100 Subject: [PATCH 037/143] Update gemnasium-gitlab-service gem --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 102d1a2887..b8b8de08f1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -190,7 +190,7 @@ GEM dotenv (>= 0.7) thor (>= 0.13.6) formatador (0.2.4) - gemnasium-gitlab-service (0.2.4) + gemnasium-gitlab-service (0.2.5) rugged (~> 0.21) gherkin-ruby (0.3.1) racc From f04847a3c70c96c008498179f58db6aceb0c5d09 Mon Sep 17 00:00:00 2001 From: Ewan Edwards Date: Mon, 16 Feb 2015 11:16:23 -0800 Subject: [PATCH 038/143] The "GitLab buttons in Gmail" document was not linked from anywhere else. It is now linked. --- doc/integration/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/integration/README.md b/doc/integration/README.md index e5f33d8dee..d66467c4b1 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -11,6 +11,8 @@ See the documentation below for details on how to configure these services. GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html) and [advanced Jenkins support](http://doc.gitlab.com/ee/integration/jenkins.html). +GitLab can also integrate with [Gmail](gitlab_buttons_in_gmail.md). + ## Project services Integration with services such as Campfire, Flowdock, Gemnasium, HipChat, Pivotal Tracker, and Slack are available in the form of a Project Service. From fe6fb32fe6cc9836f92e169f3e1f5bb3dae8ffc8 Mon Sep 17 00:00:00 2001 From: Ewan Edwards Date: Tue, 3 Mar 2015 07:38:38 -0800 Subject: [PATCH 039/143] Moved the Gmail integration line into the list of available integrations. --- doc/integration/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/integration/README.md b/doc/integration/README.md index d66467c4b1..286bd34a0b 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -8,11 +8,11 @@ See the documentation below for details on how to configure these services. - [LDAP](ldap.md) Set up sign in via LDAP - [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab, and Google via OAuth. - [Slack](slack.md) Integrate with the Slack chat service +- [OAuth2 provider](oauth_provider.md) OAuth2 application creation +- [Gmail](gitlab_buttons_in_gmail.md) Adds GitLab actions to messages GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html) and [advanced Jenkins support](http://doc.gitlab.com/ee/integration/jenkins.html). -GitLab can also integrate with [Gmail](gitlab_buttons_in_gmail.md). - ## Project services Integration with services such as Campfire, Flowdock, Gemnasium, HipChat, Pivotal Tracker, and Slack are available in the form of a Project Service. From 890f14786a49cb715d8856c1a6917003649796c5 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Tue, 3 Mar 2015 15:35:07 -0800 Subject: [PATCH 040/143] Add link to smtp documentation. --- config/initializers/smtp_settings.rb.sample | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config/initializers/smtp_settings.rb.sample b/config/initializers/smtp_settings.rb.sample index e00923e7e0..f0fe2fdfa4 100644 --- a/config/initializers/smtp_settings.rb.sample +++ b/config/initializers/smtp_settings.rb.sample @@ -3,6 +3,9 @@ # 2. Edit settings inside this file # 3. Restart GitLab instance # +# For full list of options and their values see http://api.rubyonrails.org/classes/ActionMailer/Base.html +# + if Rails.env.production? Gitlab::Application.config.action_mailer.delivery_method = :smtp @@ -14,6 +17,6 @@ if Rails.env.production? domain: "gitlab.company.com", authentication: :login, enable_starttls_auto: true, - openssl_verify_mode: 'none' + openssl_verify_mode: 'peer' # See ActionMailer documentation for other possible options } end From 3d9a766d9f465ef97b259be860891ce35bd04d0b Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Wed, 4 Mar 2015 20:24:34 +0200 Subject: [PATCH 041/143] Web Hook sends email of pusher --- CHANGELOG | 1 + doc/web_hooks/web_hooks.md | 1 + lib/gitlab/push_data_builder.rb | 2 ++ 3 files changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 3b3baf5670..3d322aadb0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,7 @@ v 7.9.0 (unreleased) - Add a service to send updates to an Irker gateway (Romain Coltel) - Add brakeman (security scanner for Ruby on Rails) - Slack username and channel options + - Web hook sends pusher email as well as commiter v 7.8.1 - Fix run of custom post receive hooks diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md index 29ef5b59ba..3cccd84b06 100644 --- a/doc/web_hooks/web_hooks.md +++ b/doc/web_hooks/web_hooks.md @@ -21,6 +21,7 @@ Triggered when you push to the repository except when pushing tags. "ref": "refs/heads/master", "user_id": 4, "user_name": "John Smith", + "user_email": "john@example.com", "project_id": 15, "repository": { "name": "Diaspora", diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb index 9aa5c8967a..6a72efa722 100644 --- a/lib/gitlab/push_data_builder.rb +++ b/lib/gitlab/push_data_builder.rb @@ -9,6 +9,7 @@ module Gitlab # ref: String, # user_id: String, # user_name: String, + # user_email: String # project_id: String, # repository: { # name: String, @@ -35,6 +36,7 @@ module Gitlab checkout_sha: checkout_sha(project.repository, newrev, ref), user_id: user.id, user_name: user.name, + user_email: user.email, project_id: project.id, repository: { name: project.name, From 61acaff5a1e4db254c92854e639aa0cb8c2d3cff Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 4 Mar 2015 10:49:48 -0800 Subject: [PATCH 042/143] Bump gitlab_git to rc15 --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 01c02b5c8d..d711efe621 100644 --- a/Gemfile +++ b/Gemfile @@ -39,7 +39,7 @@ gem "browser" # Extracting information from a git repository # Provide access to Gitlab::Git library -gem "gitlab_git", '7.0.0.rc14' +gem "gitlab_git", '7.0.0.rc15' # Ruby/Rack Git Smart-HTTP Server Handler gem 'gitlab-grack', '~> 2.0.0.rc2', require: 'grack' diff --git a/Gemfile.lock b/Gemfile.lock index 102d1a2887..1413e96741 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -212,7 +212,7 @@ GEM mime-types (~> 1.19) gitlab_emoji (0.0.1.1) emoji (~> 1.0.1) - gitlab_git (7.0.0.rc14) + gitlab_git (7.0.0.rc15) activesupport (~> 4.0) charlock_holmes (~> 0.6) gitlab-linguist (~> 3.0) @@ -701,7 +701,7 @@ DEPENDENCIES gitlab-grack (~> 2.0.0.rc2) gitlab-linguist (~> 3.0.1) gitlab_emoji (~> 0.0.1.1) - gitlab_git (= 7.0.0.rc14) + gitlab_git (= 7.0.0.rc15) gitlab_meta (= 7.0) gitlab_omniauth-ldap (= 1.2.0) gollum-lib (~> 4.0.0) From c842c452838423f82c3e9aecdfecc236b2675002 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Wed, 4 Mar 2015 11:24:14 -0800 Subject: [PATCH 043/143] Advise on how to help others. --- CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f3d4d8ea9b..73a8f9eb49 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,6 +20,13 @@ Please treat our volunteers with courtesy and respect, it will go a long way tow Issues and merge requests should be in English and contain appropriate language for audiences of all ages. +## Helping others + +Please help other GitLab users when you can. +The channnels people will reach out on can be found on the [getting help page](https://about.gitlab.com/getting-help/). +Sign up for the mailinglist, answer GitLab questions on StackOverflow or respond in the irc channel. +You can also sign up on [CodeTriage](http://www.codetriage.com/gitlabhq/gitlabhq) to help with one issue every day. + ## Issue tracker To get support for your particular problem please use the channels as detailed in the [getting help section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#getting-help). Professional [support subscriptions](http://about.gitlab.com/subscription/) and [consulting services](http://about.gitlab.com/consultancy/) are available from [GitLab.com](http://about.gitlab.com/). From 52211ea72a345c32f7bd4389c83d70dfa796f99c Mon Sep 17 00:00:00 2001 From: Patricio Cano Date: Wed, 4 Mar 2015 12:00:53 -0800 Subject: [PATCH 044/143] Added Service Templates to CHANGELOG and fixed typo. --- CHANGELOG | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 37aee53bc0..924959e5e6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -48,7 +48,8 @@ v 7.8.0 - Add notes for label changes in issue and merge requests - Show tags in commit view (Hannes Rosenögger) - Only count a user's vote once on a merge request or issue (Michael Clarke) - - Increate font size when browse source files and diffs + - Increase font size when browse source files and diffs + - Service Templates now let you set default values for all services - Create new file in empty repository using GitLab UI - Ability to clone project using oauth2 token - Upgrade Sidekiq gem to version 3.3.0 From 6fd06006856bd7f06c5bf15db2ef064cba043a58 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Mar 2015 19:56:41 +0200 Subject: [PATCH 045/143] Bugfix #1096 --- app/assets/javascripts/blob/edit_blob.js.coffee | 2 +- app/assets/javascripts/blob/new_blob.js.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/blob/edit_blob.js.coffee b/app/assets/javascripts/blob/edit_blob.js.coffee index 6914ca759f..2e91a06daa 100644 --- a/app/assets/javascripts/blob/edit_blob.js.coffee +++ b/app/assets/javascripts/blob/edit_blob.js.coffee @@ -15,7 +15,7 @@ class @EditBlob $(".js-commit-button").click -> $("#file-content").val editor.getValue() $(".file-editor form").submit() - return + return false editModePanes = $(".js-edit-mode-pane") editModeLinks = $(".js-edit-mode a") diff --git a/app/assets/javascripts/blob/new_blob.js.coffee b/app/assets/javascripts/blob/new_blob.js.coffee index a6e27116b4..ab8f98715e 100644 --- a/app/assets/javascripts/blob/new_blob.js.coffee +++ b/app/assets/javascripts/blob/new_blob.js.coffee @@ -15,7 +15,7 @@ class @NewBlob $(".js-commit-button").click -> $("#file-content").val editor.getValue() $(".file-editor form").submit() - return + return false editor: -> return @editor From 46f94173248ed143a78fb9c3e2951501cd553d27 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Wed, 4 Mar 2015 09:51:30 -0800 Subject: [PATCH 046/143] Update the Changelog. --- CHANGELOG | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 062aa7718c..a610f79058 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -21,6 +21,12 @@ v 7.9.0 (unreleased) - Slack username and channel options - Add grouped milestones from all projects to dashboard. - Web hook sends pusher email as well as commiter +v 7.8.2 + - Fix service migration issue when upgrading from versions prior to 7.3 + - Fix setting of the default use project limit via admin UI + - Fix showing of already imported projects for GitLab and Gitorious importers + - Fix response of push to repository to return "Not found" if user doesn't have access + - Fix check if user is allowed to view the file attachment v 7.8.1 - Fix run of custom post receive hooks From 02f17ce1b3233e5a35d68493b9f3cc03fb8d7c9f Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Wed, 4 Mar 2015 10:16:13 -0800 Subject: [PATCH 047/143] Update changelog. --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index a610f79058..95d176677f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,6 +27,7 @@ v 7.8.2 - Fix showing of already imported projects for GitLab and Gitorious importers - Fix response of push to repository to return "Not found" if user doesn't have access - Fix check if user is allowed to view the file attachment + - Fix import check for case sensetive namespaces v 7.8.1 - Fix run of custom post receive hooks From 00778c073130789e9f65e02e6fa6e8b987506c9e Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Wed, 4 Mar 2015 13:45:27 -0800 Subject: [PATCH 048/143] Move items to the correct version in the changelog. --- CHANGELOG | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 95d176677f..5270a81dfe 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -20,7 +20,11 @@ v 7.9.0 (unreleased) - Add brakeman (security scanner for Ruby on Rails) - Slack username and channel options - Add grouped milestones from all projects to dashboard. - - Web hook sends pusher email as well as commiter + - Web hook sends pusher email as well as commiter + - Add Bitbucket omniauth provider. + - Add Bitbucket importer. + - Support referencing issues to a project whose name starts with a digit + v 7.8.2 - Fix service migration issue when upgrading from versions prior to 7.3 - Fix setting of the default use project limit via admin UI @@ -35,9 +39,6 @@ v 7.8.1 - Fix the warning for LDAP users about need to set password - Fix avatars which were not shown for non logged in users - Fix urls for the issues when relative url was enabled - - Add Bitbucket omniauth provider. - - Add Bitbucket importer. - - Support referencing issues to a project whose name starts with a digit v 7.8.0 - Fix access control and protection against XSS for note attachments and other uploads. From 66c61f023b5c0f492cda561d31848da159c1bd00 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 4 Mar 2015 14:14:00 -0800 Subject: [PATCH 049/143] Re-annotate models --- app/models/application_setting.rb | 22 ++--- app/models/identity.rb | 2 + app/models/project_services/asana_service.rb | 18 ++-- .../project_services/assembla_service.rb | 18 ++-- app/models/project_services/bamboo_service.rb | 18 ++-- .../project_services/buildbox_service.rb | 19 ++-- .../project_services/campfire_service.rb | 18 ++-- app/models/project_services/ci_service.rb | 26 +++--- .../custom_issue_tracker_service.rb | 22 +++-- .../emails_on_push_service.rb | 26 +++--- .../project_services/flowdock_service.rb | 26 +++--- .../project_services/gemnasium_service.rb | 26 +++--- .../project_services/gitlab_ci_service.rb | 26 +++--- .../gitlab_issue_tracker_service.rb | 18 ++-- .../project_services/hipchat_service.rb | 26 +++--- app/models/project_services/irker_service.rb | 23 +++-- .../project_services/issue_tracker_service.rb | 18 ++-- app/models/project_services/jira_service.rb | 18 ++-- .../pivotaltracker_service.rb | 18 ++-- .../project_services/pushover_service.rb | 18 ++-- .../project_services/redmine_service.rb | 18 ++-- app/models/project_services/slack_service.rb | 18 ++-- .../project_services/teamcity_service.rb | 18 ++-- app/models/service.rb | 26 +++--- app/models/user.rb | 92 ++++++++++--------- spec/models/application_setting_spec.rb | 21 +++-- spec/models/asana_service_spec.rb | 21 +++-- .../project_services/assembla_service_spec.rb | 11 ++- .../project_services/buildbox_service_spec.rb | 11 ++- .../project_services/flowdock_service_spec.rb | 11 ++- .../gemnasium_service_spec.rb | 11 ++- .../gitlab_ci_service_spec.rb | 11 ++- .../gitlab_issue_tracker_service_spec.rb | 23 +++-- .../project_services/irker_service_spec.rb | 21 +++-- .../project_services/jira_service_spec.rb | 21 +++-- .../project_services/pushover_service_spec.rb | 11 ++- .../project_services/slack_service_spec.rb | 11 ++- spec/models/service_spec.rb | 26 +++--- spec/models/user_spec.rb | 88 +++++++++--------- 39 files changed, 462 insertions(+), 414 deletions(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index f1d918e545..588668b3d1 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -2,17 +2,17 @@ # # Table name: application_settings # -# id :integer not null, primary key -# default_projects_limit :integer -# default_branch_protection :integer -# signup_enabled :boolean -# signin_enabled :boolean -# gravatar_enabled :boolean -# twitter_sharing_enabled :boolean -# sign_in_text :text -# created_at :datetime -# updated_at :datetime -# home_page_url :string(255) +# id :integer not null, primary key +# default_projects_limit :integer +# signup_enabled :boolean +# signin_enabled :boolean +# gravatar_enabled :boolean +# sign_in_text :text +# created_at :datetime +# updated_at :datetime +# home_page_url :string(255) +# default_branch_protection :integer default(2) +# twitter_sharing_enabled :boolean default(TRUE) # class ApplicationSetting < ActiveRecord::Base diff --git a/app/models/identity.rb b/app/models/identity.rb index b2c3792d1c..440fcd0d05 100644 --- a/app/models/identity.rb +++ b/app/models/identity.rb @@ -6,6 +6,8 @@ # extern_uid :string(255) # provider :string(255) # user_id :integer +# created_at :datetime +# updated_at :datetime # class Identity < ActiveRecord::Base diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index 8ad1ad6267..8dce33e670 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -2,15 +2,15 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb index 02aa7c972e..6dc2500e77 100644 --- a/app/models/project_services/assembla_service.rb +++ b/app/models/project_services/assembla_service.rb @@ -2,15 +2,15 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb index 6c6d74c615..50b7cb795d 100644 --- a/app/models/project_services/bamboo_service.rb +++ b/app/models/project_services/bamboo_service.rb @@ -2,15 +2,15 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) diff --git a/app/models/project_services/buildbox_service.rb b/app/models/project_services/buildbox_service.rb index 96428c9171..1270484ff6 100644 --- a/app/models/project_services/buildbox_service.rb +++ b/app/models/project_services/buildbox_service.rb @@ -2,20 +2,21 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # + require "addressable/uri" class BuildboxService < CiService diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb index 2f86fbe7a0..21e1ca603b 100644 --- a/app/models/project_services/campfire_service.rb +++ b/app/models/project_services/campfire_service.rb @@ -2,15 +2,15 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb index 646783c873..c6f6b4952c 100644 --- a/app/models/project_services/ci_service.rb +++ b/app/models/project_services/ci_service.rb @@ -2,19 +2,19 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # # Base class for CI services diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb index b29d1c8688..8d25f62787 100644 --- a/app/models/project_services/custom_issue_tracker_service.rb +++ b/app/models/project_services/custom_issue_tracker_service.rb @@ -2,15 +2,19 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class CustomIssueTrackerService < IssueTrackerService diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb index 21041e08a2..d894d2913d 100644 --- a/app/models/project_services/emails_on_push_service.rb +++ b/app/models/project_services/emails_on_push_service.rb @@ -2,19 +2,19 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class EmailsOnPushService < Service diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb index 443dca72a8..99e361dd6e 100644 --- a/app/models/project_services/flowdock_service.rb +++ b/app/models/project_services/flowdock_service.rb @@ -2,19 +2,19 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require "flowdock-git-hook" diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb index 41eedc215d..4e75bdfc95 100644 --- a/app/models/project_services/gemnasium_service.rb +++ b/app/models/project_services/gemnasium_service.rb @@ -2,19 +2,19 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require "gemnasium/gitlab_service" diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb index 02bf305f8f..d81623625c 100644 --- a/app/models/project_services/gitlab_ci_service.rb +++ b/app/models/project_services/gitlab_ci_service.rb @@ -2,19 +2,19 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class GitlabCiService < CiService diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb index 00f8d430fd..90be1e42b2 100644 --- a/app/models/project_services/gitlab_issue_tracker_service.rb +++ b/app/models/project_services/gitlab_issue_tracker_service.rb @@ -2,15 +2,15 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index b85863d2f0..4fb80a98d2 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -2,19 +2,19 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # class HipchatService < Service diff --git a/app/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb index a0203a5bb1..deb210c61e 100644 --- a/app/models/project_services/irker_service.rb +++ b/app/models/project_services/irker_service.rb @@ -2,15 +2,20 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) +# require 'uri' diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb index bfc65b5379..7fe1326890 100644 --- a/app/models/project_services/issue_tracker_service.rb +++ b/app/models/project_services/issue_tracker_service.rb @@ -2,15 +2,15 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 20611eeb60..4a76f23c69 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -2,15 +2,15 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb index a2fa9788f1..13cbb9bdbc 100644 --- a/app/models/project_services/pivotaltracker_service.rb +++ b/app/models/project_services/pivotaltracker_service.rb @@ -2,15 +2,15 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb index 586d9e94a9..a67abb3483 100644 --- a/app/models/project_services/pushover_service.rb +++ b/app/models/project_services/pushover_service.rb @@ -2,15 +2,15 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb index f96eae2daa..7d7d7d7660 100644 --- a/app/models/project_services/redmine_service.rb +++ b/app/models/project_services/redmine_service.rb @@ -2,15 +2,15 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index 64d6f4327b..c529a78401 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -2,15 +2,15 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb index 686e6225a2..cd9388de87 100644 --- a/app/models/project_services/teamcity_service.rb +++ b/app/models/project_services/teamcity_service.rb @@ -2,15 +2,15 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) diff --git a/app/models/service.rb b/app/models/service.rb index 98bd40ae95..8f6a9d57d3 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -2,19 +2,19 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # # To add new service you should build a class inherited from Service diff --git a/app/models/user.rb b/app/models/user.rb index 55768a351e..51dd6332fd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,51 +2,53 @@ # # Table name: users # -# id :integer not null, primary key -# email :string(255) default(""), not null -# encrypted_password :string(255) default(""), not null -# reset_password_token :string(255) -# reset_password_sent_at :datetime -# remember_created_at :datetime -# sign_in_count :integer default(0) -# current_sign_in_at :datetime -# last_sign_in_at :datetime -# current_sign_in_ip :string(255) -# last_sign_in_ip :string(255) -# created_at :datetime -# updated_at :datetime -# name :string(255) -# admin :boolean default(FALSE), not null -# projects_limit :integer default(10) -# skype :string(255) default(""), not null -# linkedin :string(255) default(""), not null -# twitter :string(255) default(""), not null -# authentication_token :string(255) -# theme_id :integer default(1), not null -# bio :string(255) -# failed_attempts :integer default(0) -# locked_at :datetime -# username :string(255) -# can_create_group :boolean default(TRUE), not null -# can_create_team :boolean default(TRUE), not null -# state :string(255) -# color_scheme_id :integer default(1), not null -# notification_level :integer default(1), not null -# password_expires_at :datetime -# created_by_id :integer -# avatar :string(255) -# confirmation_token :string(255) -# confirmed_at :datetime -# confirmation_sent_at :datetime -# unconfirmed_email :string(255) -# hide_no_ssh_key :boolean default(FALSE) -# hide_no_password :boolean default(FALSE) -# website_url :string(255) default(""), not null -# last_credential_check_at :datetime -# github_access_token :string(255) -# notification_email :string(255) -# password_automatically_set :boolean default(FALSE) -# bitbucket_access_token :string(255) +# id :integer not null, primary key +# email :string(255) default(""), not null +# encrypted_password :string(255) default(""), not null +# reset_password_token :string(255) +# reset_password_sent_at :datetime +# remember_created_at :datetime +# sign_in_count :integer default(0) +# current_sign_in_at :datetime +# last_sign_in_at :datetime +# current_sign_in_ip :string(255) +# last_sign_in_ip :string(255) +# created_at :datetime +# updated_at :datetime +# name :string(255) +# admin :boolean default(FALSE), not null +# projects_limit :integer default(10) +# skype :string(255) default(""), not null +# linkedin :string(255) default(""), not null +# twitter :string(255) default(""), not null +# authentication_token :string(255) +# theme_id :integer default(1), not null +# bio :string(255) +# failed_attempts :integer default(0) +# locked_at :datetime +# username :string(255) +# can_create_group :boolean default(TRUE), not null +# can_create_team :boolean default(TRUE), not null +# state :string(255) +# color_scheme_id :integer default(1), not null +# notification_level :integer default(1), not null +# password_expires_at :datetime +# created_by_id :integer +# last_credential_check_at :datetime +# avatar :string(255) +# confirmation_token :string(255) +# confirmed_at :datetime +# confirmation_sent_at :datetime +# unconfirmed_email :string(255) +# hide_no_ssh_key :boolean default(FALSE) +# website_url :string(255) default(""), not null +# github_access_token :string(255) +# gitlab_access_token :string(255) +# notification_email :string(255) +# hide_no_password :boolean default(FALSE) +# password_automatically_set :boolean default(FALSE) +# bitbucket_access_token :string(255) +# bitbucket_access_token_secret :string(255) # require 'carrierwave/orm/activerecord' diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index cb43fdb7fc..d1027f64d1 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -2,16 +2,17 @@ # # Table name: application_settings # -# id :integer not null, primary key -# default_projects_limit :integer -# default_branch_protection :integer -# signup_enabled :boolean -# signin_enabled :boolean -# gravatar_enabled :boolean -# sign_in_text :text -# created_at :datetime -# updated_at :datetime -# home_page_url :string(255) +# id :integer not null, primary key +# default_projects_limit :integer +# signup_enabled :boolean +# signin_enabled :boolean +# gravatar_enabled :boolean +# sign_in_text :text +# created_at :datetime +# updated_at :datetime +# home_page_url :string(255) +# default_branch_protection :integer default(2) +# twitter_sharing_enabled :boolean default(TRUE) # require 'spec_helper' diff --git a/spec/models/asana_service_spec.rb b/spec/models/asana_service_spec.rb index 83e39f87f3..13c8d54a2a 100644 --- a/spec/models/asana_service_spec.rb +++ b/spec/models/asana_service_spec.rb @@ -2,14 +2,19 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require 'spec_helper' diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb index cd34e006eb..91730da1ee 100644 --- a/spec/models/project_services/assembla_service_spec.rb +++ b/spec/models/project_services/assembla_service_spec.rb @@ -5,15 +5,16 @@ # id :integer not null, primary key # type :string(255) # title :string(255) -# project_id :integer not null +# project_id :integer # created_at :datetime # updated_at :datetime # active :boolean default(FALSE), not null # properties :text -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require 'spec_helper' diff --git a/spec/models/project_services/buildbox_service_spec.rb b/spec/models/project_services/buildbox_service_spec.rb index c246e1c9d4..39d7df54cf 100644 --- a/spec/models/project_services/buildbox_service_spec.rb +++ b/spec/models/project_services/buildbox_service_spec.rb @@ -5,15 +5,16 @@ # id :integer not null, primary key # type :string(255) # title :string(255) -# project_id :integer not null +# project_id :integer # created_at :datetime # updated_at :datetime # active :boolean default(FALSE), not null # properties :text -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require 'spec_helper' diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb index 2ec167a733..73f68301a3 100644 --- a/spec/models/project_services/flowdock_service_spec.rb +++ b/spec/models/project_services/flowdock_service_spec.rb @@ -5,15 +5,16 @@ # id :integer not null, primary key # type :string(255) # title :string(255) -# project_id :integer not null +# project_id :integer # created_at :datetime # updated_at :datetime # active :boolean default(FALSE), not null # properties :text -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require 'spec_helper' diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb index 5f665fadff..d44064bbe6 100644 --- a/spec/models/project_services/gemnasium_service_spec.rb +++ b/spec/models/project_services/gemnasium_service_spec.rb @@ -5,15 +5,16 @@ # id :integer not null, primary key # type :string(255) # title :string(255) -# project_id :integer not null +# project_id :integer # created_at :datetime # updated_at :datetime # active :boolean default(FALSE), not null # properties :text -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require 'spec_helper' diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb index fcb33b1173..8bfb19e524 100644 --- a/spec/models/project_services/gitlab_ci_service_spec.rb +++ b/spec/models/project_services/gitlab_ci_service_spec.rb @@ -5,15 +5,16 @@ # id :integer not null, primary key # type :string(255) # title :string(255) -# project_id :integer not null +# project_id :integer # created_at :datetime # updated_at :datetime # active :boolean default(FALSE), not null # properties :text -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require 'spec_helper' diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb index c474f4a2d9..959044dc72 100644 --- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb +++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb @@ -2,16 +2,21 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # + require 'spec_helper' describe GitlabIssueTrackerService do diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb index bbd5245ad3..d55399bc36 100644 --- a/spec/models/project_services/irker_service_spec.rb +++ b/spec/models/project_services/irker_service_spec.rb @@ -2,14 +2,19 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require 'spec_helper' diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 6ef4d036c3..355911e637 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -2,14 +2,19 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require 'spec_helper' diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb index bb2e72c3ac..5a18fd09bf 100644 --- a/spec/models/project_services/pushover_service_spec.rb +++ b/spec/models/project_services/pushover_service_spec.rb @@ -5,15 +5,16 @@ # id :integer not null, primary key # type :string(255) # title :string(255) -# project_id :integer not null +# project_id :integer # created_at :datetime # updated_at :datetime # active :boolean default(FALSE), not null # properties :text -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require 'spec_helper' diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb index 9024e53f0f..4e8a96ec73 100644 --- a/spec/models/project_services/slack_service_spec.rb +++ b/spec/models/project_services/slack_service_spec.rb @@ -5,15 +5,16 @@ # id :integer not null, primary key # type :string(255) # title :string(255) -# project_id :integer not null +# project_id :integer # created_at :datetime # updated_at :datetime # active :boolean default(FALSE), not null # properties :text -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require 'spec_helper' diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index cc047a20dd..735652aea7 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -2,19 +2,19 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean -# issues_events :boolean -# merge_requests_events :boolean -# tag_push_events :boolean +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) # require 'spec_helper' diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 29d0c24e87..10e90cae14 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -2,47 +2,53 @@ # # Table name: users # -# id :integer not null, primary key -# email :string(255) default(""), not null -# encrypted_password :string(255) default(""), not null -# reset_password_token :string(255) -# reset_password_sent_at :datetime -# remember_created_at :datetime -# sign_in_count :integer default(0) -# current_sign_in_at :datetime -# last_sign_in_at :datetime -# current_sign_in_ip :string(255) -# last_sign_in_ip :string(255) -# created_at :datetime -# updated_at :datetime -# name :string(255) -# admin :boolean default(FALSE), not null -# projects_limit :integer default(10) -# skype :string(255) default(""), not null -# linkedin :string(255) default(""), not null -# twitter :string(255) default(""), not null -# authentication_token :string(255) -# theme_id :integer default(1), not null -# bio :string(255) -# failed_attempts :integer default(0) -# locked_at :datetime -# username :string(255) -# can_create_group :boolean default(TRUE), not null -# can_create_team :boolean default(TRUE), not null -# state :string(255) -# color_scheme_id :integer default(1), not null -# notification_level :integer default(1), not null -# password_expires_at :datetime -# created_by_id :integer -# avatar :string(255) -# confirmation_token :string(255) -# confirmed_at :datetime -# confirmation_sent_at :datetime -# unconfirmed_email :string(255) -# hide_no_ssh_key :boolean default(FALSE) -# website_url :string(255) default(""), not null -# last_credential_check_at :datetime -# github_access_token :string(255) +# id :integer not null, primary key +# email :string(255) default(""), not null +# encrypted_password :string(255) default(""), not null +# reset_password_token :string(255) +# reset_password_sent_at :datetime +# remember_created_at :datetime +# sign_in_count :integer default(0) +# current_sign_in_at :datetime +# last_sign_in_at :datetime +# current_sign_in_ip :string(255) +# last_sign_in_ip :string(255) +# created_at :datetime +# updated_at :datetime +# name :string(255) +# admin :boolean default(FALSE), not null +# projects_limit :integer default(10) +# skype :string(255) default(""), not null +# linkedin :string(255) default(""), not null +# twitter :string(255) default(""), not null +# authentication_token :string(255) +# theme_id :integer default(1), not null +# bio :string(255) +# failed_attempts :integer default(0) +# locked_at :datetime +# username :string(255) +# can_create_group :boolean default(TRUE), not null +# can_create_team :boolean default(TRUE), not null +# state :string(255) +# color_scheme_id :integer default(1), not null +# notification_level :integer default(1), not null +# password_expires_at :datetime +# created_by_id :integer +# last_credential_check_at :datetime +# avatar :string(255) +# confirmation_token :string(255) +# confirmed_at :datetime +# confirmation_sent_at :datetime +# unconfirmed_email :string(255) +# hide_no_ssh_key :boolean default(FALSE) +# website_url :string(255) default(""), not null +# github_access_token :string(255) +# gitlab_access_token :string(255) +# notification_email :string(255) +# hide_no_password :boolean default(FALSE) +# password_automatically_set :boolean default(FALSE) +# bitbucket_access_token :string(255) +# bitbucket_access_token_secret :string(255) # require 'spec_helper' From 516bcabbf42d60db2ac989dce4c7187b2a1e5de9 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 3 Mar 2015 13:07:14 +0100 Subject: [PATCH 050/143] Increase timeout for Git-over-HTTP requests. --- CHANGELOG | 1 + Gemfile | 3 +++ Gemfile.lock | 8 ++++++++ config/initializers/timeout.rb | 8 ++++++++ config/unicorn.rb.example | 20 ++++---------------- lib/gitlab/middleware/timeout.rb | 13 +++++++++++++ public/503.html | 13 +++++++++++++ 7 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 config/initializers/timeout.rb create mode 100644 lib/gitlab/middleware/timeout.rb create mode 100644 public/503.html diff --git a/CHANGELOG b/CHANGELOG index 6a28772097..7985a811f1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ v 7.9.0 (unreleased) - Allow user confirmation to be skipped for new users via API - Add a service to send updates to an Irker gateway (Romain Coltel) - Add brakeman (security scanner for Ruby on Rails) + - Increase timeout for Git-over-HTTP requests to 1 hour since large pulls/pushes can take a long time. v 7.8.1 - Fix run of custom post receive hooks diff --git a/Gemfile b/Gemfile index 01c02b5c8d..f2517c6faa 100644 --- a/Gemfile +++ b/Gemfile @@ -177,6 +177,9 @@ gem 'ace-rails-ap' # Keyboard shortcuts gem 'mousetrap-rails' +# Shutting down requests that take too long +gem "slowpoke" + gem "sass-rails", '~> 4.0.2' gem "coffee-rails" gem "uglifier" diff --git a/Gemfile.lock b/Gemfile.lock index 102d1a2887..7fde0011d3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -149,6 +149,7 @@ GEM enumerize (0.7.0) activesupport (>= 3.2) equalizer (0.0.8) + errbase (0.0.2) erubis (2.7.0) escape_utils (0.2.4) eventmachine (1.0.4) @@ -428,6 +429,7 @@ GEM rack rack-test (0.6.3) rack (>= 1.0) + rack-timeout (0.2.0) rails (4.1.9) actionmailer (= 4.1.9) actionpack (= 4.1.9) @@ -481,6 +483,8 @@ GEM rest-client (1.6.7) mime-types (>= 1.16) rinku (1.7.3) + robustly (0.0.3) + errbase rouge (1.7.4) rspec (2.99.0) rspec-core (~> 2.99.0) @@ -563,6 +567,9 @@ GEM temple (~> 0.6.6) tilt (>= 1.3.3, < 2.1) slop (3.6.0) + slowpoke (0.0.5) + rack-timeout (>= 0.1.0) + robustly spinach (0.8.7) colorize (= 0.5.8) gherkin-ruby (>= 0.3.1) @@ -772,6 +779,7 @@ DEPENDENCIES six slack-notifier (~> 1.0.0) slim + slowpoke spinach-rails spring (= 1.3.1) spring-commands-rspec (= 1.0.4) diff --git a/config/initializers/timeout.rb b/config/initializers/timeout.rb new file mode 100644 index 0000000000..bc88595cf2 --- /dev/null +++ b/config/initializers/timeout.rb @@ -0,0 +1,8 @@ +# Slowpoke extends Rack::Timeout to gracefully kill Unicorn workers so they can clean up state. +Slowpoke.timeout = 60 + +# The `Rack::Timeout` middleware kills requests after 60 seconds (as set above). +# We're replacing it with our `Gitlab::Middleware::Timeout` that does the same, +# except ignoring Git-over-HTTP requests, letting those take as long as they need. + +Rails.application.config.middleware.swap(Rack::Timeout, Gitlab::Middleware::Timeout) diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example index d8b4f5c7c3..29253b71f4 100644 --- a/config/unicorn.rb.example +++ b/config/unicorn.rb.example @@ -35,22 +35,10 @@ working_directory "/home/git/gitlab" # available in 0.94.0+ listen "/home/git/gitlab/tmp/sockets/gitlab.socket", :backlog => 1024 listen "127.0.0.1:8080", :tcp_nopush => true -# nuke workers after 30 seconds instead of 60 seconds (the default) -# -# NOTICE: git push over http depends on this value. -# If you want be able to push huge amount of data to git repository over http -# you will have to increase this value too. -# -# Example of output if you try to push 1GB repo to GitLab over http. -# -> git push http://gitlab.... master -# -# error: RPC failed; result=18, HTTP code = 200 -# fatal: The remote end hung up unexpectedly -# fatal: The remote end hung up unexpectedly -# -# For more information see http://stackoverflow.com/a/21682112/752049 -# -timeout 60 +# Kill workers after 1 hour. +# A shorter timeout of 60 seconds is enforced by rack-timeout for web requests. +# Git-over-HTTP only has the below timeout since large pulls/pushes can take a long time. +timeout 60 * 60 # feel free to point this anywhere accessible on the filesystem pid "/home/git/gitlab/tmp/pids/unicorn.pid" diff --git a/lib/gitlab/middleware/timeout.rb b/lib/gitlab/middleware/timeout.rb new file mode 100644 index 0000000000..015600392b --- /dev/null +++ b/lib/gitlab/middleware/timeout.rb @@ -0,0 +1,13 @@ +module Gitlab + module Middleware + class Timeout < Rack::Timeout + GRACK_REGEX = /[-\/\w\.]+\.git\//.freeze + + def call(env) + return @app.call(env) if env['PATH_INFO'] =~ GRACK_REGEX + + super + end + end + end +end diff --git a/public/503.html b/public/503.html new file mode 100644 index 0000000000..efdae0f512 --- /dev/null +++ b/public/503.html @@ -0,0 +1,13 @@ + + + + Page took too long to load (503) + + + +

503

+

Page took too long to load.

+
+

Please contact your GitLab administrator if this problem persists.

+ + From 94229f24c7507c64786cd511ccf994e4fea83765 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 4 Mar 2015 15:10:31 -0800 Subject: [PATCH 051/143] Update spring to 1.3.3 --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index d711efe621..38e1c031d2 100644 --- a/Gemfile +++ b/Gemfile @@ -250,7 +250,7 @@ group :development, :test do gem 'jasmine', '2.0.2' - gem "spring", '1.3.1' + gem "spring", '~> 1.3.1' gem "spring-commands-rspec", '1.0.4' gem "spring-commands-spinach", '1.0.0' end diff --git a/Gemfile.lock b/Gemfile.lock index 1413e96741..88ae8ac01b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -570,7 +570,7 @@ GEM capybara (>= 2.0.0) railties (>= 3) spinach (>= 0.4) - spring (1.3.1) + spring (1.3.3) spring-commands-rspec (1.0.4) spring (>= 0.9.1) spring-commands-spinach (1.0.0) @@ -773,7 +773,7 @@ DEPENDENCIES slack-notifier (~> 1.0.0) slim spinach-rails - spring (= 1.3.1) + spring (~> 1.3.1) spring-commands-rspec (= 1.0.4) spring-commands-spinach (= 1.0.0) stamp From 65105ff3bbe66363d4c922913dbc8c9514f1485c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 4 Mar 2015 17:22:55 -0800 Subject: [PATCH 052/143] Improve projects list * Add search filtering for group projects * Show all user projects on dashboard * Refactor projects list into one view * Hide big list of projects with 'Show all' button --- app/assets/javascripts/dashboard.js.coffee | 17 +--------- app/assets/javascripts/dispatcher.js.coffee | 6 +++- .../javascripts/projects_list.js.coffee | 24 ++++++++++++++ app/assets/javascripts/user.js.coffee | 1 + app/controllers/dashboard_controller.rb | 8 ++--- app/views/dashboard/_projects.html.haml | 19 ++---------- app/views/groups/_projects.html.haml | 31 ++++++------------- .../{dashboard => shared}/_project.html.haml | 14 ++++++--- app/views/shared/_projects_list.html.haml | 17 ++++++++++ app/views/users/_projects.html.haml | 20 ++++-------- 10 files changed, 77 insertions(+), 80 deletions(-) create mode 100644 app/assets/javascripts/projects_list.js.coffee rename app/views/{dashboard => shared}/_project.html.haml (56%) create mode 100644 app/views/shared/_projects_list.html.haml diff --git a/app/assets/javascripts/dashboard.js.coffee b/app/assets/javascripts/dashboard.js.coffee index 6ef5a539b8..3bdb9469d0 100644 --- a/app/assets/javascripts/dashboard.js.coffee +++ b/app/assets/javascripts/dashboard.js.coffee @@ -1,22 +1,7 @@ class @Dashboard constructor: -> @initSidebarTab() - - $(".dash-filter").keyup -> - terms = $(this).val() - uiBox = $(this).parents('.panel').first() - if terms == "" || terms == undefined - uiBox.find(".dash-list li").show() - else - uiBox.find(".dash-list li").each (index) -> - name = $(this).find(".filter-title").text() - - if name.toLowerCase().search(terms.toLowerCase()) == -1 - $(this).hide() - else - $(this).show() - - + new ProjectsList() initSidebarTab: -> key = "dashboard_sidebar_filter" diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index 591a3749a9..bf94fa3aaa 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -62,9 +62,13 @@ class Dispatcher shortcut_handler = new ShortcutsNavigation() when 'projects:commits:show' shortcut_handler = new ShortcutsNavigation() - when 'groups:show', 'projects:show' + when 'projects:show' new Activities() shortcut_handler = new ShortcutsNavigation() + when 'groups:show' + new Activities() + shortcut_handler = new ShortcutsNavigation() + new ProjectsList() when 'groups:members' new GroupMembers() new UsersSelect() diff --git a/app/assets/javascripts/projects_list.js.coffee b/app/assets/javascripts/projects_list.js.coffee new file mode 100644 index 0000000000..c0e36d1ccc --- /dev/null +++ b/app/assets/javascripts/projects_list.js.coffee @@ -0,0 +1,24 @@ +class @ProjectsList + constructor: -> + $(".projects-list .js-expand").on 'click', (e) -> + e.preventDefault() + list = $(this).closest('.projects-list') + list.find("li").show() + list.find("li.bottom").hide() + + $(".projects-list-filter").keyup -> + terms = $(this).val() + uiBox = $(this).closest('.panel') + if terms == "" || terms == undefined + uiBox.find(".projects-list li").show() + else + uiBox.find(".projects-list li").each (index) -> + name = $(this).find(".filter-title").text() + + if name.toLowerCase().search(terms.toLowerCase()) == -1 + $(this).hide() + else + $(this).show() + uiBox.find(".projects-list li.bottom").hide() + + diff --git a/app/assets/javascripts/user.js.coffee b/app/assets/javascripts/user.js.coffee index 8a2e2421c2..d0d81f9692 100644 --- a/app/assets/javascripts/user.js.coffee +++ b/app/assets/javascripts/user.js.coffee @@ -1,3 +1,4 @@ class @User constructor: -> $('.profile-groups-avatars').tooltip("placement": "top") + new ProjectsList() diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 4930029e16..8f06a67358 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -5,15 +5,11 @@ class DashboardController < ApplicationController before_filter :event_filter, only: :show def show - # Fetch only 30 projects. - # If user needs more - point to Dashboard#projects page - @projects_limit = 30 - + @projects_limit = 20 @groups = current_user.authorized_groups.order_name_asc @has_authorized_projects = @projects.count > 0 @projects_count = @projects.count - @projects = @projects.includes(:namespace).limit(@projects_limit) - + @projects = @projects.includes(:namespace) @last_push = current_user.recent_push @publicish_project_count = Project.publicish(current_user).count diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml index 0596738342..3634b2bfd7 100644 --- a/app/views/dashboard/_projects.html.haml +++ b/app/views/dashboard/_projects.html.haml @@ -1,25 +1,10 @@ .panel.panel-default .panel-heading.clearfix .input-group - = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'dash-filter form-control' + = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control' - if current_user.can_create_project? .input-group-addon.dash-new-project = link_to new_project_path do %strong New project - %ul.well-list.dash-list - - projects.each do |project| - %li.project-row - = render "project", project: project - - - if projects.blank? - %li - .nothing-here-block There are no projects here. - - if @projects_count > @projects_limit - %li.bottom - %span.light - #{@projects_limit} of #{pluralize(@projects_count, 'project')} displayed. - .pull-right - = link_to projects_dashboard_path do - Show all - %i.fa.fa-angle-right + = render 'shared/projects_list', projects: @projects, projects_limit: 20 diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml index b505760fa8..0dfd398f54 100644 --- a/app/views/groups/_projects.html.haml +++ b/app/views/groups/_projects.html.haml @@ -1,23 +1,10 @@ .panel.panel-default - .panel-heading - Projects (#{projects.count}) - - if can? current_user, :create_projects, @group - .panel-head-actions - = link_to new_project_path(namespace_id: @group.id), class: "btn btn-new" do - %i.fa.fa-plus - New project - %ul.well-list - - if projects.blank? - .nothing-here-block This group has no projects yet - - projects.each do |project| - %li.project-row - = link_to project_path(project), class: dom_class(project) do - .dash-project-avatar - = project_icon(project, alt: '', class: 'avatar s40') - .dash-project-access-icon - = visibility_level_icon(project.visibility_level) - %span.str-truncated - %span.project-name - = project.name - %span.arrow - %i.fa.fa-angle-right + .panel-heading.clearfix + .input-group + = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control' + - if current_user.can_create_project? + .input-group-addon.dash-new-project + = link_to new_project_path(namespace_id: @group.id) do + %strong New project + + = render 'shared/projects_list', projects: @projects, projects_limit: 20 diff --git a/app/views/dashboard/_project.html.haml b/app/views/shared/_project.html.haml similarity index 56% rename from app/views/dashboard/_project.html.haml rename to app/views/shared/_project.html.haml index fa9179cb24..d9ae045986 100644 --- a/app/views/dashboard/_project.html.haml +++ b/app/views/shared/_project.html.haml @@ -1,6 +1,7 @@ = link_to project_path(project), class: dom_class(project) do - .dash-project-avatar - = project_icon(project, alt: '', class: 'avatar project-avatar s40') + - if avatar + .dash-project-avatar + = project_icon(project, alt: '', class: 'avatar project-avatar s40') .dash-project-access-icon = visibility_level_icon(project.visibility_level) %span.str-truncated @@ -10,5 +11,10 @@ \/ %span.project-name.filter-title = project.name - %span.arrow - %i.fa.fa-angle-right + - if stars + %span.pull-right.light + %i.fa.fa-star + = project.star_count + - else + %span.arrow + %i.fa.fa-angle-right diff --git a/app/views/shared/_projects_list.html.haml b/app/views/shared/_projects_list.html.haml new file mode 100644 index 0000000000..4c58092af4 --- /dev/null +++ b/app/views/shared/_projects_list.html.haml @@ -0,0 +1,17 @@ +- projects_limit = 20 unless local_assigns[:projects_limit] +- avatar = true unless local_assigns[:avatar] == false +- stars = false unless local_assigns[:stars] == true +%ul.well-list.projects-list + - projects.each_with_index do |project, i| + %li{class: (i >= projects_limit) ? 'project-row hide' : 'project-row'} + = render "shared/project", project: project, avatar: avatar, stars: stars + - if projects.blank? + %li + .nothing-here-block There are no projects here. + - if projects.count > projects_limit + %li.bottom + %span.light + #{projects_limit} of #{pluralize(projects.count, 'project')} displayed. + %span + = link_to '#', class: 'js-expand' do + Show all diff --git a/app/views/users/_projects.html.haml b/app/views/users/_projects.html.haml index c925a48f55..6c7779be30 100644 --- a/app/views/users/_projects.html.haml +++ b/app/views/users/_projects.html.haml @@ -1,21 +1,13 @@ - if @contributed_projects.present? .panel.panel-default .panel-heading Projects contributed to - %ul.well-list - - @contributed_projects.sort_by(&:star_count).reverse.each do |project| - %li - = link_to_project project - %span.pull-right.light - %i.fa.fa-star - = project.star_count + = render 'shared/projects_list', + projects: @contributed_projects.sort_by(&:star_count).reverse, + projects_limit: 5, stars: true, avatar: false - if @projects.present? .panel.panel-default .panel-heading Personal projects - %ul.well-list - - @projects.sort_by(&:star_count).reverse.each do |project| - %li - = link_to_project project - %span.pull-right.light - %i.fa.fa-star - = project.star_count + = render 'shared/projects_list', + projects: @projects.sort_by(&:star_count).reverse, + projects_limit: 10, stars: true, avatar: false From 7b9b9f704eb1a14d6f943cc4d37d493a6cb8fde3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 4 Mar 2015 18:26:49 -0800 Subject: [PATCH 053/143] Fix project create link on group page --- app/views/groups/_projects.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml index 0dfd398f54..6f53e125c4 100644 --- a/app/views/groups/_projects.html.haml +++ b/app/views/groups/_projects.html.haml @@ -2,7 +2,7 @@ .panel-heading.clearfix .input-group = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control' - - if current_user.can_create_project? + - if can? current_user, :create_projects, @group .input-group-addon.dash-new-project = link_to new_project_path(namespace_id: @group.id) do %strong New project From 730a49afc29d291287d5eae511c6e27e1a04ab72 Mon Sep 17 00:00:00 2001 From: Stefan Tatschner Date: Thu, 5 Mar 2015 11:06:06 +0100 Subject: [PATCH 054/143] Update rugments, fixes #8900 --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index fa33a714a0..19c71bd08c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -520,7 +520,7 @@ GEM rubyntlm (0.4.0) rubypants (0.2.0) rugged (0.21.4) - rugments (1.0.0.beta3) + rugments (1.0.0.beta4) safe_yaml (0.9.7) sanitize (2.1.0) nokogiri (>= 1.4.4) From f12ec5f4e80bee7690a2ec72cd65e72e62b21a18 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 5 Mar 2015 01:54:28 -0800 Subject: [PATCH 055/143] Add merge and issue event notification for HipChat --- CHANGELOG | 1 + .../project_services/hipchat_service.rb | 87 ++++++++++++++- .../project_services/hipchat_service_spec.rb | 102 ++++++++++++++++++ 3 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 spec/models/project_services/hipchat_service_spec.rb diff --git a/CHANGELOG b/CHANGELOG index f6853f6e11..68680bb7be 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 7.9.0 (unreleased) + - Added issue and merge request events to HipChat and Slack service (Stan Hu) - Fix merge request URL passed to Webhooks. (Stan Hu) - Fix bug that caused a server error when editing a comment to "+1" or "-1" (Stan Hu) - Move labels/milestones tabs to sidebar diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 4fb80a98d2..9d094eaf14 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -45,7 +45,7 @@ class HipchatService < Service end def supported_events - %w(push) + %w(push issue merge_request) end def execute(data) @@ -62,7 +62,21 @@ class HipchatService < Service @gate ||= HipChat::Client.new(token, options) end - def create_message(push) + def create_message(data) + object_kind = data[:object_kind] + + message = \ + case object_kind + when "push" + create_push_message(data) + when "issue" + create_issue_message(data) unless is_update?(data) + when "merge_request" + create_merge_request_message(data) unless is_update?(data) + end + end + + def create_push_message(push) ref = push[:ref].gsub("refs/heads/", "") before = push[:before] after = push[:after] @@ -71,9 +85,9 @@ class HipchatService < Service message << "#{push[:user_name]} " if before.include?('000000') message << "pushed new branch #{ref}"\ - " to "\ - "#{project.name_with_namespace.gsub!(/\s/, "")}\n" + "#{project_url}/commits/#{URI.escape(ref)}\">#{ref}"\ + " to "\ + "#{project_url}\n" elsif after.include?('000000') message << "removed branch #{ref} from #{project.name_with_namespace.gsub!(/\s/,'')} \n" else @@ -93,4 +107,67 @@ class HipchatService < Service message end + + def create_issue_message(data) + username = data[:user][:username] + + obj_attr = data[:object_attributes] + obj_attr = HashWithIndifferentAccess.new(obj_attr) + title = obj_attr[:title] + state = obj_attr[:state] + issue_iid = obj_attr[:iid] + issue_url = obj_attr[:url] + description = obj_attr[:description] + + issue_link = "##{issue_iid}" + message = "#{username} #{state} issue #{issue_link} in #{project_link}: #{title}" + + if description + description = description.truncate(200, separator: ' ', omission: '...') + message << "
#{description}
" + end + + message + end + + def create_merge_request_message(data) + username = data[:user][:username] + + obj_attr = data[:object_attributes] + obj_attr = HashWithIndifferentAccess.new(obj_attr) + merge_request_id = obj_attr[:iid] + source_branch = obj_attr[:source_branch] + target_branch = obj_attr[:target_branch] + state = obj_attr[:state] + description = obj_attr[:description] + title = obj_attr[:title] + + merge_request_url = "#{project_url}/merge_requests/#{merge_request_id}" + merge_request_link = "##{merge_request_id}" + message = "#{username} #{state} merge request #{merge_request_link} in " \ + "#{project_link}: #{title}" + + if description + description = description.truncate(200, separator: ' ', omission: '...') + message << "
#{description}
" + end + + message + end + + def project_name + project.name_with_namespace.gsub(/\s/, '') + end + + def project_url + project.web_url + end + + def project_link + "#{project_name}" + end + + def is_update?(data) + data[:object_attributes][:action] == 'update' + end end diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb new file mode 100644 index 0000000000..804c3d5ddd --- /dev/null +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -0,0 +1,102 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) +# + +require 'spec_helper' + +describe HipchatService do + describe "Associations" do + it { is_expected.to belong_to :project } + it { is_expected.to have_one :service_hook } + end + + describe "Execute" do + let(:hipchat) { HipchatService.new } + let(:user) { create(:user, username: 'username') } + let(:project) { create(:project, name: 'project') } + let(:api_url) { 'https://hipchat.example.com/v2/room/123456/notification?auth_token=verySecret' } + let(:project_name) { project.name_with_namespace.gsub(/\s/, '') } + + before(:each) do + hipchat.stub( + project_id: project.id, + project: project, + room: 123456, + server: 'https://hipchat.example.com', + token: 'verySecret' + ) + WebMock.stub_request(:post, api_url) + end + + context 'push events' do + let(:push_sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) } + + it "should call Hipchat API for push events" do + hipchat.execute(push_sample_data) + + expect(WebMock).to have_requested(:post, api_url).once + end + end + + context 'issue events' do + let(:issue) { create(:issue, title: 'Awesome issue', description: 'please fix') } + let(:issue_service) { Issues::CreateService.new(project, user) } + let(:issues_sample_data) { issue_service.hook_data(issue, 'open') } + + it "should call Hipchat API for issue events" do + hipchat.execute(issues_sample_data) + + expect(WebMock).to have_requested(:post, api_url).once + end + + it "should create an issue message" do + message = hipchat.send(:create_issue_message, issues_sample_data) + + obj_attr = issues_sample_data[:object_attributes] + expect(message).to eq("#{user.username} opened issue " \ + "##{obj_attr["iid"]} in " \ + "#{project_name}: " \ + "Awesome issue" \ + "
please fix
") + end + end + + context 'merge request events' do + let(:merge_request) { create(:merge_request, description: 'please fix', title: 'Awesome merge request', target_project: project, source_project: project) } + let(:merge_service) { MergeRequests::CreateService.new(project, user) } + let(:merge_sample_data) { merge_service.hook_data(merge_request, 'open') } + + it "should call Hipchat API for merge requests events" do + hipchat.execute(merge_sample_data) + + expect(WebMock).to have_requested(:post, api_url).once + end + + it "should create a merge request message" do + message = hipchat.send(:create_merge_request_message, + merge_sample_data) + + obj_attr = merge_sample_data[:object_attributes] + expect(message).to eq("#{user.username} opened merge request " \ + "##{obj_attr["iid"]} in " \ + "#{project_name}: " \ + "Awesome merge request" \ + "
please fix
") + end + end + end +end From 38862308f003d39b660920c36e142b2ece0a4f70 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 5 Mar 2015 09:43:41 -0800 Subject: [PATCH 056/143] Cache project row on dashboard, group and user page --- app/views/shared/_project.html.haml | 41 +++++++++++++++-------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/app/views/shared/_project.html.haml b/app/views/shared/_project.html.haml index d9ae045986..8746970c23 100644 --- a/app/views/shared/_project.html.haml +++ b/app/views/shared/_project.html.haml @@ -1,20 +1,21 @@ -= link_to project_path(project), class: dom_class(project) do - - if avatar - .dash-project-avatar - = project_icon(project, alt: '', class: 'avatar project-avatar s40') - .dash-project-access-icon - = visibility_level_icon(project.visibility_level) - %span.str-truncated - %span.namespace-name - - if project.namespace - = project.namespace.human_name - \/ - %span.project-name.filter-title - = project.name - - if stars - %span.pull-right.light - %i.fa.fa-star - = project.star_count - - else - %span.arrow - %i.fa.fa-angle-right += cache [project, controller.controller_name, controller.action_name] do + = link_to project_path(project), class: dom_class(project) do + - if avatar + .dash-project-avatar + = project_icon(project, alt: '', class: 'avatar project-avatar s40') + .dash-project-access-icon + = visibility_level_icon(project.visibility_level) + %span.str-truncated + %span.namespace-name + - if project.namespace + = project.namespace.human_name + \/ + %span.project-name.filter-title + = project.name + - if stars + %span.pull-right.light + %i.fa.fa-star + = project.star_count + - else + %span.arrow + %i.fa.fa-angle-right From c17e11ca27882c0a35e23eba72689f2fdb89680a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 5 Mar 2015 11:35:36 -0800 Subject: [PATCH 057/143] Bump gitlab_git to fix 500 with annotated tags w/o message --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index c2f419832a..462c932584 100644 --- a/Gemfile +++ b/Gemfile @@ -39,7 +39,7 @@ gem "browser" # Extracting information from a git repository # Provide access to Gitlab::Git library -gem "gitlab_git", '7.0.0.rc15' +gem "gitlab_git", '7.0.1' # Ruby/Rack Git Smart-HTTP Server Handler gem 'gitlab-grack', '~> 2.0.0.rc2', require: 'grack' diff --git a/Gemfile.lock b/Gemfile.lock index 19c71bd08c..9be5983430 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -213,7 +213,7 @@ GEM mime-types (~> 1.19) gitlab_emoji (0.0.1.1) emoji (~> 1.0.1) - gitlab_git (7.0.0.rc15) + gitlab_git (7.0.1) activesupport (~> 4.0) charlock_holmes (~> 0.6) gitlab-linguist (~> 3.0) @@ -708,7 +708,7 @@ DEPENDENCIES gitlab-grack (~> 2.0.0.rc2) gitlab-linguist (~> 3.0.1) gitlab_emoji (~> 0.0.1.1) - gitlab_git (= 7.0.0.rc15) + gitlab_git (= 7.0.1) gitlab_meta (= 7.0) gitlab_omniauth-ldap (= 1.2.0) gollum-lib (~> 4.0.0) From 8b53d9efe648f10e0572c2d8017489d0d3bb4755 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Mar 2015 01:41:29 -0800 Subject: [PATCH 058/143] Fix bug with active tab remembering (saving cookie with different path) --- app/assets/javascripts/project_show.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/project_show.js.coffee b/app/assets/javascripts/project_show.js.coffee index d0eaaad92b..6828ae471e 100644 --- a/app/assets/javascripts/project_show.js.coffee +++ b/app/assets/javascripts/project_show.js.coffee @@ -6,7 +6,7 @@ class @ProjectShow new Flash('Star toggle failed. Try again later.', 'alert') $("a[data-toggle='tab']").on "shown.bs.tab", (e) -> - $.cookie "default_view", $(e.target).attr("href"), { expires: 30 } + $.cookie "default_view", $(e.target).attr("href"), { expires: 30, path: '/' } defaultView = $.cookie("default_view") if defaultView From b14d21e1749b682bbdfebad80cf404c2b640b551 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Mar 2015 02:18:53 -0800 Subject: [PATCH 059/143] Use bootstrap buttons with custom colors instead of own css --- app/assets/stylesheets/generic/buttons.scss | 121 ++------------------ app/assets/stylesheets/gl_bootstrap.scss | 7 ++ 2 files changed, 14 insertions(+), 114 deletions(-) diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss index 3b36027506..d106e3b201 100644 --- a/app/assets/stylesheets/generic/buttons.scss +++ b/app/assets/stylesheets/generic/buttons.scss @@ -1,115 +1,5 @@ .btn { - display: inline-block; - margin-bottom: 0; - font-weight: normal; - text-align: center; - vertical-align: middle; - cursor: pointer; - background-image: none; - border: $btn-border; - white-space: nowrap; - padding: 6px 12px; - font-size: 13px; - line-height: 18px; - border-radius: 4px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - -o-user-select: none; - user-select: none; - color: #444444; - background-color: #fff; - text-shadow: none; - - &.hover, - &:hover { - color: #444444; - text-decoration: none; - background-color: #ebebeb; - border-color: #adadad; - } - - &.focus, - &:focus { - color: #444444; - text-decoration: none; - outline: thin dotted #333; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; - } - - &.active, - &:active { - outline: 0; - background-image: none; - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); - } - - &.disabled, - &[disabled] { - cursor: not-allowed; - pointer-events: none; - opacity: 0.65; - filter: alpha(opacity=65); - -webkit-box-shadow: none; - box-shadow: none; - } - - &.btn-primary { - color: #ffffff; - background-color: $bg_primary; - border-color: $border_primary; - - &.hover, - &:hover, - &.disabled, - &[disabled] { - color: #ffffff; - } - } - - &.btn-success { - color: #ffffff; - background-color: $bg_success; - border-color: $border_success; - - - &.hover, - &:hover, - &.disabled, - &[disabled] { - color: #ffffff; - } - } - - &.btn-danger { - color: #ffffff; - background-color: $bg_danger; - border-color: $border_danger; - - - &.hover, - &:hover, - &.disabled, - &[disabled] { - color: #ffffff; - } - } - - &.btn-warning { - color: #ffffff; - background-color: $bg_warning; - border-color: $border_warning; - - - &.hover, - &:hover, - &.disabled, - &[disabled] { - color: #ffffff; - } - } + @extend .btn-default; &.btn-new { @extend .btn-success; @@ -174,9 +64,12 @@ } } - &.btn-lg { - font-size: 15px; - line-height: 1.4; + &.btn-save { + @extend .btn-primary; + } + + &.btn-new, &.btn-create { + @extend .btn-success; } } diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/gl_bootstrap.scss index 6efa56544a..34ddf6f871 100644 --- a/app/assets/stylesheets/gl_bootstrap.scss +++ b/app/assets/stylesheets/gl_bootstrap.scss @@ -8,6 +8,12 @@ $nav-pills-active-link-hover-bg: $bg_primary; $pagination-active-bg: $bg_primary; $list-group-active-bg: $bg_primary; +$brand-primary: $bg_primary; +$brand-success: $bg_success; +$brand-info: #029ACF; +$brand-warning: $bg_warning; +$brand-danger: $bg_danger; + // Core variables and mixins @import "bootstrap/variables"; @import "bootstrap/mixins"; @@ -23,6 +29,7 @@ $list-group-active-bg: $bg_primary; @import "bootstrap/grid"; @import "bootstrap/tables"; @import "bootstrap/forms"; +@import "bootstrap/buttons"; // Components @import "bootstrap/component-animations"; From 757dca2b78c8b218295c855d6b7529bad05ae24b Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 6 Mar 2015 13:26:33 +0100 Subject: [PATCH 060/143] Escape wildcards when searching LDAP by username. --- CHANGELOG | 1 + lib/gitlab/ldap/authentication.rb | 2 +- lib/gitlab/ldap/person.rb | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 37aee53bc0..59846b778e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -20,6 +20,7 @@ v 7.9.0 (unreleased) - Add brakeman (security scanner for Ruby on Rails) - Slack username and channel options - Add grouped milestones from all projects to dashboard. + - Escape wildcards when searching LDAP by username. v 7.8.1 - Fix run of custom post receive hooks diff --git a/lib/gitlab/ldap/authentication.rb b/lib/gitlab/ldap/authentication.rb index 8af2c74e95..649cf3194b 100644 --- a/lib/gitlab/ldap/authentication.rb +++ b/lib/gitlab/ldap/authentication.rb @@ -50,7 +50,7 @@ module Gitlab end def user_filter(login) - filter = Net::LDAP::Filter.eq(config.uid, login) + filter = Net::LDAP::Filter.equals(config.uid, login) # Apply LDAP user filter if present if config.user_filter.present? diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb index 3e0b3e6cbf..3c42617937 100644 --- a/lib/gitlab/ldap/person.rb +++ b/lib/gitlab/ldap/person.rb @@ -9,10 +9,12 @@ module Gitlab attr_accessor :entry, :provider def self.find_by_uid(uid, adapter) + uid = Net::LDAP::Filter.escape(uid) adapter.user(adapter.config.uid, uid) end def self.find_by_dn(dn, adapter) + dn = Net::LDAP::Filter.escape(dn) adapter.user('dn', dn) end From dc558eb24e7432570e1fdbd73c9d67551602c8dc Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 6 Mar 2015 13:49:27 +0100 Subject: [PATCH 061/143] Fix width of text in milestone lists. --- app/assets/stylesheets/sections/milestone.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/sections/milestone.scss b/app/assets/stylesheets/sections/milestone.scss index d20391e38f..29ad4e24f0 100644 --- a/app/assets/stylesheets/sections/milestone.scss +++ b/app/assets/stylesheets/sections/milestone.scss @@ -1,3 +1,3 @@ .issues-sortable-list .str-truncated { - max-width: 70%; + max-width: 90%; } From be94e135524943236f85a63de08fa8ccc445a0af Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 6 Mar 2015 14:03:41 +0100 Subject: [PATCH 062/143] Add assignee icon to milestone merge requests. --- app/assets/javascripts/milestone.js.coffee | 7 +++++++ app/controllers/projects/merge_requests_controller.rb | 6 ++++++ app/views/projects/milestones/_merge_request.html.haml | 3 +++ 3 files changed, 16 insertions(+) diff --git a/app/assets/javascripts/milestone.js.coffee b/app/assets/javascripts/milestone.js.coffee index c42f31933d..d644d50b66 100644 --- a/app/assets/javascripts/milestone.js.coffee +++ b/app/assets/javascripts/milestone.js.coffee @@ -49,6 +49,13 @@ class @Milestone data: data success: (data) -> if data.saved == true + if data.assignee_avatar_url + img_tag = $('') + img_tag.attr('src', data.assignee_avatar_url) + img_tag.addClass('avatar s16') + $(li).find('.assignee-icon').html(img_tag) + else + $(li).find('.assignee-icon').html('') $(li).effect 'highlight' else new Flash("Issue update failed", 'alert') diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 26d4c51773..848cf36749 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -100,6 +100,12 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.') end + format.json do + render json: { + saved: @merge_request.valid?, + assignee_avatar_url: @merge_request.assignee.try(:avatar_url) + } + end end else render "edit" diff --git a/app/views/projects/milestones/_merge_request.html.haml b/app/views/projects/milestones/_merge_request.html.haml index 46f2df1b18..42fbd0cd2c 100644 --- a/app/views/projects/milestones/_merge_request.html.haml +++ b/app/views/projects/milestones/_merge_request.html.haml @@ -3,3 +3,6 @@ = link_to [@project.namespace.becomes(Namespace), @project, merge_request] do %span.cgray ##{merge_request.iid} = link_to_gfm merge_request.title, [@project.namespace.becomes(Namespace), @project, merge_request], title: merge_request.title + .pull-right.assignee-icon + - if merge_request.assignee + = image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16" From b673d87227867f6d142ee6e615c750a600661c6b Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 6 Mar 2015 15:01:13 +0100 Subject: [PATCH 063/143] Send notifications and leave system comments when bulk updating issues. --- CHANGELOG | 1 + app/controllers/projects/issues_controller.rb | 11 +++++- app/services/issues/bulk_update_service.rb | 35 ++++++------------- app/views/projects/issues/index.html.haml | 4 +-- .../issues/bulk_update_service_spec.rb | 28 ++++++--------- 5 files changed, 33 insertions(+), 46 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b927b60140..698ca0881f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,7 @@ v 7.9.0 (unreleased) - Add Bitbucket omniauth provider. - Add Bitbucket importer. - Support referencing issues to a project whose name starts with a digit + - Send notifications and leave system comments when bulk updating issues. v 7.8.2 - Fix service migration issue when upgrading from versions prior to 7.3 diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 6a2af08a19..1f1a9b4d43 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -93,7 +93,7 @@ class Projects::IssuesController < Projects::ApplicationController end def bulk_update - result = Issues::BulkUpdateService.new(project, current_user, params).execute + result = Issues::BulkUpdateService.new(project, current_user, bulk_update_params).execute redirect_to :back, notice: "#{result[:count]} issues updated" end @@ -141,4 +141,13 @@ class Projects::IssuesController < Projects::ApplicationController :milestone_id, :state_event, :task_num, label_ids: [] ) end + + def bulk_update_params + params.require(:update).permit( + :issues_ids, + :assignee_id, + :milestone_id, + :state_event + ) + end end diff --git a/app/services/issues/bulk_update_service.rb b/app/services/issues/bulk_update_service.rb index f72a346af6..c7cd20b6b6 100644 --- a/app/services/issues/bulk_update_service.rb +++ b/app/services/issues/bulk_update_service.rb @@ -1,38 +1,23 @@ module Issues class BulkUpdateService < BaseService def execute - update_data = params[:update] + issues_ids = params.delete(:issues_ids).split(",") + issue_params = params - issues_ids = update_data[:issues_ids].split(",") - milestone_id = update_data[:milestone_id] - assignee_id = update_data[:assignee_id] - status = update_data[:status] - - new_state = nil - - if status.present? - if status == 'closed' - new_state = :close - else - new_state = :reopen - end - end - - opts = {} - opts[:milestone_id] = milestone_id if milestone_id.present? - opts[:assignee_id] = assignee_id if assignee_id.present? + issue_params.delete(:state_event) unless issue_params[:state_event].present? + issue_params.delete(:milestone_id) unless issue_params[:milestone_id].present? + issue_params.delete(:assignee_id) unless issue_params[:assignee_id].present? issues = Issue.where(id: issues_ids) - issues = issues.select { |issue| can?(current_user, :modify_issue, issue) } - issues.each do |issue| - issue.update_attributes(opts) - issue.send new_state if new_state + next unless can?(current_user, :modify_issue, issue) + + Issues::UpdateService.new(issue.project, current_user, issue_params).execute(issue) end { - count: issues.count, - success: !issues.count.zero? + count: issues.count, + success: !issues.count.zero? } end end diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml index 7defc8787a..cbbcb1d06c 100644 --- a/app/views/projects/issues/index.html.haml +++ b/app/views/projects/issues/index.html.haml @@ -25,11 +25,11 @@ .clearfix .issues_bulk_update.hide = form_tag bulk_update_namespace_project_issues_path(@project.namespace, @project), method: :post do - = select_tag('update[status]', options_for_select([['Open', 'open'], ['Closed', 'closed']]), prompt: "Status") + = select_tag('update[state_event]', options_for_select([['Open', 'reopen'], ['Closed', 'close']]), prompt: "Status") = project_users_select_tag('update[assignee_id]', placeholder: 'Assignee') = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone") = hidden_field_tag 'update[issues_ids]', [] - = hidden_field_tag :status, params[:status] + = hidden_field_tag :state_event, params[:state_event] = button_tag "Update issues", class: "btn update_selected_issues btn-save" .issues-holder diff --git a/spec/services/issues/bulk_update_service_spec.rb b/spec/services/issues/bulk_update_service_spec.rb index 504213e667..a97c55011c 100644 --- a/spec/services/issues/bulk_update_service_spec.rb +++ b/spec/services/issues/bulk_update_service_spec.rb @@ -21,10 +21,8 @@ describe Issues::BulkUpdateService do create(:issue, project: @project) end @params = { - update: { - status: 'closed', - issues_ids: @issues.map(&:id) - } + state_event: 'close', + issues_ids: @issues.map(&:id) } end @@ -46,10 +44,8 @@ describe Issues::BulkUpdateService do create(:closed_issue, project: @project) end @params = { - update: { - status: 'reopen', - issues_ids: @issues.map(&:id) - } + state_event: 'reopen', + issues_ids: @issues.map(&:id) } end @@ -69,10 +65,8 @@ describe Issues::BulkUpdateService do before do @new_assignee = create :user @params = { - update: { - issues_ids: [issue.id], - assignee_id: @new_assignee.id - } + issues_ids: [issue.id], + assignee_id: @new_assignee.id } end @@ -88,7 +82,7 @@ describe Issues::BulkUpdateService do @project.issues.first.update_attribute(:assignee, @new_assignee) expect(@project.issues.first.assignee).not_to be_nil - @params[:update][:assignee_id] = -1 + @params[:assignee_id] = -1 Issues::BulkUpdateService.new(@project, @user, @params).execute expect(@project.issues.first.assignee).to be_nil @@ -98,7 +92,7 @@ describe Issues::BulkUpdateService do @project.issues.first.update_attribute(:assignee, @new_assignee) expect(@project.issues.first.assignee).not_to be_nil - @params[:update][:assignee_id] = '' + @params[:assignee_id] = '' Issues::BulkUpdateService.new(@project, @user, @params).execute expect(@project.issues.first.assignee).not_to be_nil @@ -110,10 +104,8 @@ describe Issues::BulkUpdateService do before do @milestone = create :milestone @params = { - update: { - issues_ids: [issue.id], - milestone_id: @milestone.id - } + issues_ids: [issue.id], + milestone_id: @milestone.id } end From 7e204cf389346d23e71bc4c2fa9e14cf82a7ed2e Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 5 Mar 2015 10:38:23 -0800 Subject: [PATCH 064/143] Added comment notification events to HipChat and Slack services. Supports four different event types all bundled under the "note" event type: - comments on a commit - comments on an issue - comments on a merge request - comments on a code snippet --- CHANGELOG | 3 +- .../projects/services_controller.rb | 3 +- app/helpers/gitlab_routing_helper.rb | 4 + app/models/concerns/mentionable.rb | 1 - app/models/note.rb | 8 ++ app/models/project_services/asana_service.rb | 2 +- .../project_services/assembla_service.rb | 1 + app/models/project_services/bamboo_service.rb | 1 + .../project_services/buildbox_service.rb | 1 + .../project_services/campfire_service.rb | 1 + .../gitlab_issue_tracker_service.rb | 1 + .../project_services/hipchat_service.rb | 74 +++++++++- .../project_services/issue_tracker_service.rb | 1 + app/models/project_services/jira_service.rb | 1 + .../pivotaltracker_service.rb | 1 + .../project_services/pushover_service.rb | 1 + .../project_services/redmine_service.rb | 1 + app/models/project_services/slack_service.rb | 6 +- .../slack_service/note_message.rb | 82 +++++++++++ .../project_services/teamcity_service.rb | 1 + app/models/service.rb | 2 + app/models/snippet.rb | 4 + app/services/notes/create_service.rb | 12 ++ app/views/projects/services/_form.html.haml | 8 ++ ...50225065047_add_note_events_to_services.rb | 5 + db/schema.rb | 3 +- lib/gitlab/note_data_builder.rb | 77 +++++++++++ lib/gitlab/url_builder.rb | 29 ++++ spec/factories/merge_requests.rb | 2 +- spec/factories/notes.rb | 6 + spec/lib/gitlab/note_data_builder_spec.rb | 73 ++++++++++ spec/lib/gitlab/url_builder_spec.rb | 58 ++++++++ .../project_services/hipchat_service_spec.rb | 86 ++++++++++++ .../slack_service/note_message_spec.rb | 129 ++++++++++++++++++ .../project_services/slack_service_spec.rb | 67 ++++++++- 35 files changed, 736 insertions(+), 19 deletions(-) create mode 100644 app/models/project_services/slack_service/note_message.rb create mode 100644 db/migrate/20150225065047_add_note_events_to_services.rb create mode 100644 lib/gitlab/note_data_builder.rb create mode 100644 spec/lib/gitlab/note_data_builder_spec.rb create mode 100644 spec/models/project_services/slack_service/note_message_spec.rb diff --git a/CHANGELOG b/CHANGELOG index b927b60140..611c6c77d5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,8 @@ Please view this file on the master branch, on stable branches it's out of date. v 7.9.0 (unreleased) - - Added issue and merge request events to HipChat and Slack service (Stan Hu) + - Added comment notification events to HipChat and Slack services (Stan Hu) + - Added issue and merge request events to HipChat and Slack services (Stan Hu) - Fix merge request URL passed to Webhooks. (Stan Hu) - Fix bug that caused a server error when editing a comment to "+1" or "-1" (Stan Hu) - Move labels/milestones tabs to sidebar diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index 087579de10..382d63d053 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -52,7 +52,8 @@ class Projects::ServicesController < Projects::ApplicationController :build_key, :server, :teamcity_url, :build_type, :description, :issues_url, :new_issue_url, :restrict_to_branch, :channel, :colorize_messages, :channels, - :push_events, :issues_events, :merge_requests_events, :tag_push_events + :push_events, :issues_events, :merge_requests_events, :tag_push_events, + :note_events ) end end diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index ac37f909ce..8518a47a3a 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -44,4 +44,8 @@ module GitlabRoutingHelper def merge_request_url(entity, *args) namespace_project_merge_request_url(entity.project.namespace, entity.project, entity, *args) end + + def snippet_url(entity, *args) + namespace_project_snippet_url(entity.project.namespace, entity.project, entity, *args) + end end diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb index 50be458bf2..74900d4675 100644 --- a/app/models/concerns/mentionable.rb +++ b/app/models/concerns/mentionable.rb @@ -99,5 +99,4 @@ module Mentionable preexisting = references(p, original) create_cross_references!(p, a, preexisting) end - end diff --git a/app/models/note.rb b/app/models/note.rb index e6c258ffbe..b19d7b0f25 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -308,6 +308,10 @@ class Note < ActiveRecord::Base end end + def hook_attrs + attributes + end + def set_diff # First lets find notes with same diff # before iterating over all mr diffs @@ -466,6 +470,10 @@ class Note < ActiveRecord::Base for_merge_request? && for_diff_line? end + def for_project_snippet? + noteable_type == "Snippet" + end + # override to return commits, which are not active record def noteable if for_commit? diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index 8dce33e670..6a62220738 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -15,8 +15,8 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # - require 'asana' class AsanaService < Service diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb index 6dc2500e77..fb7e0c0fb0 100644 --- a/app/models/project_services/assembla_service.rb +++ b/app/models/project_services/assembla_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class AssemblaService < Service diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb index 50b7cb795d..0100f1e4a1 100644 --- a/app/models/project_services/bamboo_service.rb +++ b/app/models/project_services/bamboo_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class BambooService < CiService diff --git a/app/models/project_services/buildbox_service.rb b/app/models/project_services/buildbox_service.rb index 1270484ff6..270863c157 100644 --- a/app/models/project_services/buildbox_service.rb +++ b/app/models/project_services/buildbox_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require "addressable/uri" diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb index 21e1ca603b..1c63444fbf 100644 --- a/app/models/project_services/campfire_service.rb +++ b/app/models/project_services/campfire_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class CampfireService < Service diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb index 90be1e42b2..84346350a6 100644 --- a/app/models/project_services/gitlab_issue_tracker_service.rb +++ b/app/models/project_services/gitlab_issue_tracker_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class GitlabIssueTrackerService < IssueTrackerService diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 9d094eaf14..d24351a7b1 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -45,7 +45,7 @@ class HipchatService < Service end def supported_events - %w(push issue merge_request) + %w(push issue merge_request note) end def execute(data) @@ -73,6 +73,8 @@ class HipchatService < Service create_issue_message(data) unless is_update?(data) when "merge_request" create_merge_request_message(data) unless is_update?(data) + when "note" + create_note_message(data) end end @@ -108,6 +110,14 @@ class HipchatService < Service message end + def format_body(body) + if body + body = body.truncate(200, separator: ' ', omission: '...') + end + + "
#{body}
" + end + def create_issue_message(data) username = data[:user][:username] @@ -123,8 +133,8 @@ class HipchatService < Service message = "#{username} #{state} issue #{issue_link} in #{project_link}: #{title}" if description - description = description.truncate(200, separator: ' ', omission: '...') - message << "
#{description}
" + description = format_body(description) + message << description end message @@ -148,8 +158,62 @@ class HipchatService < Service "#{project_link}: #{title}" if description - description = description.truncate(200, separator: ' ', omission: '...') - message << "
#{description}
" + description = format_body(description) + message << description + end + + message + end + + def format_title(title) + "" + title.lines.first.chomp + "" + end + + def create_note_message(data) + data = HashWithIndifferentAccess.new(data) + username = data[:user][:username] + + repo_attr = HashWithIndifferentAccess.new(data[:repository]) + + obj_attr = HashWithIndifferentAccess.new(data[:object_attributes]) + note = obj_attr[:note] + note_url = obj_attr[:url] + noteable_type = obj_attr[:noteable_type] + + case noteable_type + when "Commit" + commit_attr = HashWithIndifferentAccess.new(data[:commit]) + subject_desc = commit_attr[:id] + subject_desc = Commit.truncate_sha(subject_desc) + subject_type = "commit" + title = format_title(commit_attr[:message]) + when "Issue" + subj_attr = HashWithIndifferentAccess.new(data[:issue]) + subject_id = subj_attr[:iid] + subject_desc = "##{subject_id}" + subject_type = "issue" + title = format_title(subj_attr[:title]) + when "MergeRequest" + subj_attr = HashWithIndifferentAccess.new(data[:merge_request]) + subject_id = subj_attr[:iid] + subject_desc = "##{subject_id}" + subject_type = "merge request" + title = format_title(subj_attr[:title]) + when "Snippet" + subj_attr = HashWithIndifferentAccess.new(data[:snippet]) + subject_id = subj_attr[:id] + subject_desc = "##{subject_id}" + subject_type = "snippet" + title = format_title(subj_attr[:title]) + end + + subject_html = "#{subject_type} #{subject_desc}" + message = "#{username} commented on #{subject_html} in #{project_link}: " + message << title + + if note + note = format_body(note) + message << note end message diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb index 7fe1326890..16876335b6 100644 --- a/app/models/project_services/issue_tracker_service.rb +++ b/app/models/project_services/issue_tracker_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class IssueTrackerService < Service diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 4a76f23c69..fcd9dc2f33 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class JiraService < IssueTrackerService diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb index 13cbb9bdbc..ade9ee9787 100644 --- a/app/models/project_services/pivotaltracker_service.rb +++ b/app/models/project_services/pivotaltracker_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class PivotaltrackerService < Service diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb index a67abb3483..0ce324434d 100644 --- a/app/models/project_services/pushover_service.rb +++ b/app/models/project_services/pushover_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class PushoverService < Service diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb index 7d7d7d7660..dd9ba97ee1 100644 --- a/app/models/project_services/redmine_service.rb +++ b/app/models/project_services/redmine_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class RedmineService < IssueTrackerService diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index c529a78401..a58840116f 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class SlackService < Service @@ -43,7 +44,7 @@ class SlackService < Service end def supported_events - %w(push issue merge_request) + %w(push issue merge_request note) end def execute(data) @@ -69,6 +70,8 @@ class SlackService < Service IssueMessage.new(data) unless is_update?(data) when "merge_request" MergeMessage.new(data) unless is_update?(data) + when "note" + NoteMessage.new(data) end opt = {} @@ -99,3 +102,4 @@ end require "slack_service/issue_message" require "slack_service/push_message" require "slack_service/merge_message" +require "slack_service/note_message" diff --git a/app/models/project_services/slack_service/note_message.rb b/app/models/project_services/slack_service/note_message.rb new file mode 100644 index 0000000000..f93dc358f6 --- /dev/null +++ b/app/models/project_services/slack_service/note_message.rb @@ -0,0 +1,82 @@ +class SlackService + class NoteMessage < BaseMessage + attr_reader :message + attr_reader :username + attr_reader :project_name + attr_reader :project_link + attr_reader :note + attr_reader :note_url + attr_reader :title + + def initialize(params) + params = HashWithIndifferentAccess.new(params) + @username = params[:user][:username] + @project_name = params[:project_name] + @project_url = params[:project_url] + + obj_attr = params[:object_attributes] + obj_attr = HashWithIndifferentAccess.new(obj_attr) + @note = obj_attr[:note] + @note_url = obj_attr[:url] + noteable_type = obj_attr[:noteable_type] + + case noteable_type + when "Commit" + create_commit_note(HashWithIndifferentAccess.new(params[:commit])) + when "Issue" + create_issue_note(HashWithIndifferentAccess.new(params[:issue])) + when "MergeRequest" + create_merge_note(HashWithIndifferentAccess.new(params[:merge_request])) + when "Snippet" + create_snippet_note(HashWithIndifferentAccess.new(params[:snippet])) + end + end + + def attachments + description_message + end + + private + + def format_title(title) + title.lines.first.chomp + end + + def create_commit_note(commit) + commit_sha = commit[:id] + commit_sha = Commit.truncate_sha(commit_sha) + commit_link = "[commit #{commit_sha}](#{@note_url})" + title = format_title(commit[:message]) + @message = "#{@username} commented on #{commit_link} in #{project_link}: *#{title}*" + end + + def create_issue_note(issue) + issue_iid = issue[:iid] + note_link = "[issue ##{issue_iid}](#{@note_url})" + title = format_title(issue[:title]) + @message = "#{@username} commented on #{note_link} in #{project_link}: *#{title}*" + end + + def create_merge_note(merge_request) + merge_request_id = merge_request[:iid] + merge_request_link = "[merge request ##{merge_request_id}](#{@note_url})" + title = format_title(merge_request[:title]) + @message = "#{@username} commented on #{merge_request_link} in #{project_link}: *#{title}*" + end + + def create_snippet_note(snippet) + snippet_id = snippet[:id] + snippet_link = "[snippet ##{snippet_id}](#{@note_url})" + title = format_title(snippet[:title]) + @message = "#{@username} commented on #{snippet_link} in #{project_link}: *#{title}*" + end + + def description_message + [{ text: format(@note), color: attachment_color }] + end + + def project_link + "[#{@project_name}](#{@project_url})" + end + end +end diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb index cd9388de87..038c200adc 100644 --- a/app/models/project_services/teamcity_service.rb +++ b/app/models/project_services/teamcity_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class TeamcityService < CiService diff --git a/app/models/service.rb b/app/models/service.rb index 8f6a9d57d3..33734e97c5 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -28,6 +28,7 @@ class Service < ActiveRecord::Base default_value_for :issues_events, true default_value_for :merge_requests_events, true default_value_for :tag_push_events, true + default_value_for :note_events, true after_initialize :initialize_properties @@ -42,6 +43,7 @@ class Service < ActiveRecord::Base scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) } scope :issue_hooks, -> { where(issues_events: true, active: true) } scope :merge_request_hooks, -> { where(merge_requests_events: true, active: true) } + scope :note_hooks, -> { where(note_events: true, active: true) } def activated? active diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 82c1ab9444..3fb2ec1d66 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -59,6 +59,10 @@ class Snippet < ActiveRecord::Base content end + def hook_attrs + attributes + end + def size 0 end diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb index f64006a4ed..e969061f22 100644 --- a/app/services/notes/create_service.rb +++ b/app/services/notes/create_service.rb @@ -17,10 +17,22 @@ module Notes note.references.each do |mentioned| Note.create_cross_reference_note(mentioned, note.noteable, note.author, note.project) end + + execute_hooks(note) end end note end + + def hook_data(note) + Gitlab::NoteDataBuilder.build(note, current_user) + end + + def execute_hooks(note) + note_data = hook_data(note) + # TODO: Support Webhooks + note.project.execute_services(note_data, :note_hooks) + end end end diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index 55ac85c32b..defcdbe268 100644 --- a/app/views/projects/services/_form.html.haml +++ b/app/views/projects/services/_form.html.haml @@ -47,6 +47,14 @@ %strong Tag push events %p.light This url will be triggered when a new tag is pushed to the repository + - if @service.supported_events.include?("note") + %div + = f.check_box :note_events, class: 'pull-left' + .prepend-left-20 + = f.label :note_events, class: 'list-label' do + %strong Comments + %p.light + This url will be triggered when someone adds a comment - if @service.supported_events.include?("issue") %div = f.check_box :issues_events, class: 'pull-left' diff --git a/db/migrate/20150225065047_add_note_events_to_services.rb b/db/migrate/20150225065047_add_note_events_to_services.rb new file mode 100644 index 0000000000..d54ba9e482 --- /dev/null +++ b/db/migrate/20150225065047_add_note_events_to_services.rb @@ -0,0 +1,5 @@ +class AddNoteEventsToServices < ActiveRecord::Migration + def change + add_column :services, :note_events, :boolean, default: true, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 1a9b512e15..a686bb4b3c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150223022001) do +ActiveRecord::Schema.define(version: 20150225065047) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -371,6 +371,7 @@ ActiveRecord::Schema.define(version: 20150223022001) do t.boolean "issues_events", default: true t.boolean "merge_requests_events", default: true t.boolean "tag_push_events", default: true + t.boolean "note_events", default: true, null: false end add_index "services", ["created_at", "id"], name: "index_services_on_created_at_and_id", using: :btree diff --git a/lib/gitlab/note_data_builder.rb b/lib/gitlab/note_data_builder.rb new file mode 100644 index 0000000000..644dec45dc --- /dev/null +++ b/lib/gitlab/note_data_builder.rb @@ -0,0 +1,77 @@ +module Gitlab + class NoteDataBuilder + class << self + # Produce a hash of post-receive data + # + # For all notes: + # + # data = { + # object_kind: "note", + # user: { + # name: String, + # username: String, + # avatar_url: String + # } + # project_id: Integer, + # repository: { + # name: String, + # url: String, + # description: String, + # homepage: String, + # } + # object_attributes: { + # + # } + # : { + # } + # note-specific data is a hash with one of the following keys and contains + # the hook data for that type. + # - commit + # - issue + # - merge_request + # - snippet + # + def build(note, user) + project = note.project + data = build_base_data(project, user, note) + + if note.for_commit? + data[:commit] = build_data_for_commit(project, user, note) + elsif note.for_issue? + data[:issue] = note.noteable.hook_attrs + elsif note.for_merge_request? + data[:merge_request] = note.noteable.hook_attrs + elsif note.for_project_snippet? + data[:snippet] = note.noteable.hook_attrs + end + + data + end + + def build_base_data(project, user, note) + base_data = { + object_kind: "note", + user: user.hook_attrs, + project_id: project.id, + repository: { + name: project.name, + url: project.url_to_repo, + description: project.description, + homepage: project.web_url, + }, + object_attributes: note.hook_attrs + } + + base_data[:object_attributes][:url] = + Gitlab::UrlBuilder.new(:note).build(note.id) + base_data + end + + def build_data_for_commit(project, user, note) + # commit_id is the SHA hash + commit = project.repository.commit(note.commit_id) + commit.hook_attrs(project) + end + end + end +end diff --git a/lib/gitlab/url_builder.rb b/lib/gitlab/url_builder.rb index ab7c8ad89f..6830d15875 100644 --- a/lib/gitlab/url_builder.rb +++ b/lib/gitlab/url_builder.rb @@ -13,6 +13,9 @@ module Gitlab build_issue_url(id) when :merge_request build_merge_request_url(id) + when :note + build_note_url(id) + end end @@ -27,5 +30,31 @@ module Gitlab merge_request = MergeRequest.find(id) merge_request_url(merge_request, host: Gitlab.config.gitlab['url']) end + + def build_note_url(id) + note = Note.find(id) + if note.for_commit? + namespace_project_commit_url(namespace_id: note.project.namespace, + id: note.commit_id, + project_id: note.project, + host: Gitlab.config.gitlab['url'], + anchor: "note_#{note.id}") + elsif note.for_issue? + issue = Issue.find(note.noteable_id) + issue_url(issue, + host: Gitlab.config.gitlab['url'], + anchor: "note_#{note.id}") + elsif note.for_merge_request? + merge_request = MergeRequest.find(note.noteable_id) + merge_request_url(merge_request, + host: Gitlab.config.gitlab['url'], + anchor: "note_#{note.id}") + elsif note.for_project_snippet? + snippet = Snippet.find(note.noteable_id) + snippet_url(snippet, + host: Gitlab.config.gitlab['url'], + anchor: "note_#{note.id}") + end + end end end diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index 6ce1d7446f..77cd37c22d 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -40,7 +40,7 @@ FactoryGirl.define do source_branch "master" target_branch "feature" - merge_status :can_be_merged + merge_status "can_be_merged" trait :with_diffs do end diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb index 83d0cc62db..f1c33461b5 100644 --- a/spec/factories/notes.rb +++ b/spec/factories/notes.rb @@ -30,6 +30,7 @@ FactoryGirl.define do factory :note_on_issue, traits: [:on_issue], aliases: [:votable_note] factory :note_on_merge_request, traits: [:on_merge_request] factory :note_on_merge_request_diff, traits: [:on_merge_request, :on_diff] + factory :note_on_project_snippet, traits: [:on_project_snippet] trait :on_commit do project factory: :project @@ -52,6 +53,11 @@ FactoryGirl.define do noteable_type "Issue" end + trait :on_project_snippet do + noteable_id 1 + noteable_type "Snippet" + end + trait :with_attachment do attachment { fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "`/png") } end diff --git a/spec/lib/gitlab/note_data_builder_spec.rb b/spec/lib/gitlab/note_data_builder_spec.rb new file mode 100644 index 0000000000..448cd0c688 --- /dev/null +++ b/spec/lib/gitlab/note_data_builder_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe 'Gitlab::NoteDataBuilder' do + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:data) { Gitlab::NoteDataBuilder.build(note, user) } + let(:note_url) { Gitlab::UrlBuilder.new(:note).build(note.id) } + let(:fixed_time) { Time.at(1425600000) } # Avoid time precision errors + + before(:each) do + expect(data).to have_key(:object_attributes) + expect(data[:object_attributes]).to have_key(:url) + expect(data[:object_attributes][:url]).to eq(note_url) + expect(data[:object_kind]).to eq('note') + expect(data[:user]).to eq(user.hook_attrs) + end + + describe 'When asking for a note on commit' do + let(:note) { create(:note_on_commit) } + + it 'returns the note and commit-specific data' do + expect(data).to have_key(:commit) + end + end + + describe 'When asking for a note on commit diff' do + let(:note) { create(:note_on_commit_diff) } + + it 'returns the note and commit-specific data' do + expect(data).to have_key(:commit) + end + end + + describe 'When asking for a note on issue' do + let(:issue) { create(:issue, created_at: fixed_time, updated_at: fixed_time) } + let(:note) { create(:note_on_issue, noteable_id: issue.id) } + + it 'returns the note and issue-specific data' do + expect(data).to have_key(:issue) + expect(data[:issue]).to eq(issue.hook_attrs) + end + end + + describe 'When asking for a note on merge request' do + let(:merge_request) { create(:merge_request, created_at: fixed_time, updated_at: fixed_time) } + let(:note) { create(:note_on_merge_request, noteable_id: merge_request.id) } + + it 'returns the note and merge request data' do + expect(data).to have_key(:merge_request) + expect(data[:merge_request]).to eq(merge_request.hook_attrs) + end + end + + describe 'When asking for a note on merge request diff' do + let(:merge_request) { create(:merge_request, created_at: fixed_time, updated_at: fixed_time) } + let(:note) { create(:note_on_merge_request_diff, noteable_id: merge_request.id) } + + it 'returns the note and merge request diff data' do + expect(data).to have_key(:merge_request) + expect(data[:merge_request]).to eq(merge_request.hook_attrs) + end + end + + describe 'When asking for a note on project snippet' do + let!(:snippet) { create(:project_snippet, created_at: fixed_time, updated_at: fixed_time) } + let!(:note) { create(:note_on_project_snippet, noteable_id: snippet.id) } + + it 'returns the note and project snippet data' do + expect(data).to have_key(:snippet) + expect(data[:snippet]).to eq(snippet.hook_attrs) + end + end +end diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb index 94b2fd5508..5153ed15af 100644 --- a/spec/lib/gitlab/url_builder_spec.rb +++ b/spec/lib/gitlab/url_builder_spec.rb @@ -16,4 +16,62 @@ describe Gitlab::UrlBuilder do expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}" end end + + describe 'When asking for a note on commit' do + let(:note) { create(:note_on_commit) } + let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) } + + it 'returns the note url' do + expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}" + end + end + + describe 'When asking for a note on commit diff' do + let(:note) { create(:note_on_commit_diff) } + let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) } + + it 'returns the note url' do + expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}" + end + end + + describe 'When asking for a note on issue' do + let(:issue) { create(:issue) } + let(:note) { create(:note_on_issue, noteable_id: issue.id) } + let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) } + + it 'returns the note url' do + expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}#note_#{note.id}" + end + end + + describe 'When asking for a note on merge request' do + let(:merge_request) { create(:merge_request) } + let(:note) { create(:note_on_merge_request, noteable_id: merge_request.id) } + let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) } + + it 'returns the note url' do + expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}" + end + end + + describe 'When asking for a note on merge request diff' do + let(:merge_request) { create(:merge_request) } + let(:note) { create(:note_on_merge_request_diff, noteable_id: merge_request.id) } + let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) } + + it 'returns the note url' do + expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}" + end + end + + describe 'When asking for a note on project snippet' do + let(:snippet) { create(:project_snippet) } + let(:note) { create(:note_on_project_snippet, noteable_id: snippet.id) } + let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) } + + it 'returns the note url' do + expect(url).to eq "#{Settings.gitlab['url']}/#{snippet.project.path_with_namespace}/snippets/#{note.noteable_id}#note_#{note.id}" + end + end end diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index 804c3d5ddd..95ce4f8e4a 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -98,5 +98,91 @@ describe HipchatService do "
please fix
") end end + + context "Note events" do + let(:user) { create(:user) } + let(:project) { create(:project, creator_id: user.id) } + let(:issue) { create(:issue, project: project) } + let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } + let(:snippet) { create(:project_snippet, project: project) } + let(:commit_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') } + let(:merge_request_note) { create(:note_on_merge_request, noteable_id: merge_request.id, note: "merge request note") } + let(:issue_note) { create(:note_on_issue, noteable_id: issue.id, note: "issue note")} + let(:snippet_note) { create(:note_on_project_snippet, noteable_id: snippet.id, note: "snippet note") } + + it "should call Hipchat API for commit comment events" do + data = Gitlab::NoteDataBuilder.build(commit_note, user) + hipchat.execute(data) + + expect(WebMock).to have_requested(:post, api_url).once + + message = hipchat.send(:create_message, data) + + obj_attr = data[:object_attributes] + commit_id = Commit.truncate_sha(data[:commit][:id]) + title = hipchat.send(:format_title, data[:commit][:message]) + + expect(message).to eq("#{user.username} commented on " \ + "commit #{commit_id} in " \ + "#{project_name}: " \ + "#{title}" \ + "
a comment on a commit
") + end + + it "should call Hipchat API for merge request comment events" do + data = Gitlab::NoteDataBuilder.build(merge_request_note, user) + hipchat.execute(data) + + expect(WebMock).to have_requested(:post, api_url).once + + message = hipchat.send(:create_message, data) + + obj_attr = data[:object_attributes] + merge_id = data[:merge_request]['iid'] + title = data[:merge_request]['title'] + + expect(message).to eq("#{user.username} commented on " \ + "merge request ##{merge_id} in " \ + "#{project_name}: " \ + "#{title}" \ + "
merge request note
") + end + + it "should call Hipchat API for issue comment events" do + data = Gitlab::NoteDataBuilder.build(issue_note, user) + hipchat.execute(data) + + message = hipchat.send(:create_message, data) + + obj_attr = data[:object_attributes] + issue_id = data[:issue]['iid'] + title = data[:issue]['title'] + + expect(message).to eq("#{user.username} commented on " \ + "issue ##{issue_id} in " \ + "#{project_name}: " \ + "#{title}" \ + "
issue note
") + end + + it "should call Hipchat API for snippet comment events" do + data = Gitlab::NoteDataBuilder.build(snippet_note, user) + hipchat.execute(data) + + expect(WebMock).to have_requested(:post, api_url).once + + message = hipchat.send(:create_message, data) + + obj_attr = data[:object_attributes] + snippet_id = data[:snippet]['id'] + title = data[:snippet]['title'] + + expect(message).to eq("#{user.username} commented on " \ + "snippet ##{snippet_id} in " \ + "#{project_name}: " \ + "#{title}" \ + "
snippet note
") + end + end end end diff --git a/spec/models/project_services/slack_service/note_message_spec.rb b/spec/models/project_services/slack_service/note_message_spec.rb new file mode 100644 index 0000000000..f2516c1000 --- /dev/null +++ b/spec/models/project_services/slack_service/note_message_spec.rb @@ -0,0 +1,129 @@ +require 'spec_helper' + +describe SlackService::NoteMessage do + let(:color) { '#345' } + + before do + @args = { + user: { + name: 'Test User', + username: 'username', + avatar_url: 'http://fakeavatar' + }, + project_name: 'project_name', + project_url: 'somewhere.com', + repository: { + name: 'project_name', + url: 'somewhere.com', + }, + object_attributes: { + id: 10, + note: 'comment on a commit', + url: 'url', + noteable_type: 'Commit' + } + } + end + + context 'commit notes' do + before do + @args[:object_attributes][:note] = 'comment on a commit' + @args[:object_attributes][:noteable_type] = 'Commit' + @args[:commit] = { + id: '5f163b2b95e6f53cbd428f5f0b103702a52b9a23', + message: "Added a commit message\ndetails\n123\n" + } + end + + it 'returns a message regarding notes on commits' do + message = SlackService::NoteMessage.new(@args) + expect(message.pretext).to eq("username commented on " \ + " in : " \ + "*Added a commit message*") + expected_attachments = [ + { + text: "comment on a commit", + color: color, + } + ] + expect(message.attachments).to eq(expected_attachments) + end + end + + context 'merge request notes' do + before do + @args[:object_attributes][:note] = 'comment on a merge request' + @args[:object_attributes][:noteable_type] = 'MergeRequest' + @args[:merge_request] = { + id: 1, + iid: 30, + title: "merge request title\ndetails\n" + } + end + it 'returns a message regarding notes on a merge request' do + message = SlackService::NoteMessage.new(@args) + expect(message.pretext).to eq("username commented on " \ + " in : " \ + "*merge request title*") + expected_attachments = [ + { + text: "comment on a merge request", + color: color, + } + ] + expect(message.attachments).to eq(expected_attachments) + end + end + + context 'issue notes' do + before do + @args[:object_attributes][:note] = 'comment on an issue' + @args[:object_attributes][:noteable_type] = 'Issue' + @args[:issue] = { + id: 1, + iid: 20, + title: "issue title\ndetails\n" + } + end + + it 'returns a message regarding notes on an issue' do + message = SlackService::NoteMessage.new(@args) + expect(message.pretext).to eq( + "username commented on " \ + " in : " \ + "*issue title*") + expected_attachments = [ + { + text: "comment on an issue", + color: color, + } + ] + expect(message.attachments).to eq(expected_attachments) + end + end + + context 'project snippet notes' do + before do + @args[:object_attributes][:note] = 'comment on a snippet' + @args[:object_attributes][:noteable_type] = 'Snippet' + @args[:snippet] = { + id: 5, + title: "snippet title\ndetails\n" + } + end + + it 'returns a message regarding notes on a project snippet' do + message = SlackService::NoteMessage.new(@args) + expect(message.pretext).to eq("username commented on " \ + " in : " \ + "*snippet title*") + expected_attachments = [ + { + text: "comment on a snippet", + color: color, + } + ] + expect(message.attachments).to eq(expected_attachments) + end + end +end diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb index 4e8a96ec73..c36506644b 100644 --- a/spec/models/project_services/slack_service_spec.rb +++ b/spec/models/project_services/slack_service_spec.rb @@ -76,16 +76,16 @@ describe SlackService do 'open') end - it "should call Slack API for pull requests" do + it "should call Slack API for push events" do slack.execute(push_sample_data) - WebMock.should have_requested(:post, webhook_url).once + expect(WebMock).to have_requested(:post, webhook_url).once end it "should call Slack API for issue events" do slack.execute(@issues_sample_data) - WebMock.should have_requested(:post, webhook_url).once + expect(WebMock).to have_requested(:post, webhook_url).once end it "should call Slack API for merge requests events" do @@ -97,10 +97,10 @@ describe SlackService do it 'should use the username as an option for slack when configured' do slack.stub(username: username) expect(Slack::Notifier).to receive(:new). - with(webhook_url, username: username). - and_return( - double(:slack_service).as_null_object - ) + with(webhook_url, username: username). + and_return( + double(:slack_service).as_null_object + ) slack.execute(push_sample_data) end @@ -114,4 +114,57 @@ describe SlackService do slack.execute(push_sample_data) end end + + describe "Note events" do + let(:slack) { SlackService.new } + let(:user) { create(:user) } + let(:project) { create(:project, creator_id: user.id) } + let(:issue) { create(:issue, project: project) } + let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } + let(:snippet) { create(:project_snippet, project: project) } + let(:commit_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') } + let(:merge_request_note) { create(:note_on_merge_request, noteable_id: merge_request.id, note: "merge request note") } + let(:issue_note) { create(:note_on_issue, noteable_id: issue.id, note: "issue note")} + let(:snippet_note) { create(:note_on_project_snippet, noteable_id: snippet.id, note: "snippet note") } + let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' } + + before do + slack.stub( + project: project, + project_id: project.id, + service_hook: true, + webhook: webhook_url + ) + + WebMock.stub_request(:post, webhook_url) + end + + it "should call Slack API for commit comment events" do + data = Gitlab::NoteDataBuilder.build(commit_note, user) + slack.execute(data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + + it "should call Slack API for merge request comment events" do + data = Gitlab::NoteDataBuilder.build(merge_request_note, user) + slack.execute(data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + + it "should call Slack API for issue comment events" do + data = Gitlab::NoteDataBuilder.build(issue_note, user) + slack.execute(data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + + it "should call Slack API for snippet comment events" do + data = Gitlab::NoteDataBuilder.build(snippet_note, user) + slack.execute(data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + end end From ad14ed5e49a956511ae8f4d3bf377457fdb1075d Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 6 Mar 2015 08:31:49 -0800 Subject: [PATCH 065/143] Add tag_push event notification to HipChat and Slack services. Normalize output to use: - User name instead of username - Include first line of title in message description - Link to "Issue #X" instead of "#X" --- CHANGELOG | 6 +-- .../project_services/hipchat_service.rb | 38 +++++++++------- app/models/project_services/slack_service.rb | 4 +- .../slack_service/issue_message.rb | 8 ++-- .../slack_service/merge_message.rb | 14 ++++-- .../slack_service/note_message.rb | 12 ++--- .../slack_service/push_message.rb | 19 +++++--- .../project_services/hipchat_service_spec.rb | 45 +++++++++++++++---- .../slack_service/issue_message_spec.rb | 11 ++--- .../slack_service/merge_message_spec.rb | 13 +++--- .../slack_service/note_message_spec.rb | 8 ++-- .../slack_service/push_message_spec.rb | 20 +++++++++ 12 files changed, 134 insertions(+), 64 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 611c6c77d5..c0d38a9abf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,8 +1,9 @@ Please view this file on the master branch, on stable branches it's out of date. v 7.9.0 (unreleased) - - Added comment notification events to HipChat and Slack services (Stan Hu) - - Added issue and merge request events to HipChat and Slack services (Stan Hu) + - Add tag push notifications and normalize HipChat and Slack messages to be consistent (Stan Hu) + - Add comment notification events to HipChat and Slack services (Stan Hu) + - Add issue and merge request events to HipChat and Slack services (Stan Hu) - Fix merge request URL passed to Webhooks. (Stan Hu) - Fix bug that caused a server error when editing a comment to "+1" or "-1" (Stan Hu) - Move labels/milestones tabs to sidebar @@ -35,7 +36,6 @@ v 7.8.2 - Fix response of push to repository to return "Not found" if user doesn't have access - Fix check if user is allowed to view the file attachment - Fix import check for case sensetive namespaces - - Added issue and merge request events to Slack service (Stan Hu) - Increase timeout for Git-over-HTTP requests to 1 hour since large pulls/pushes can take a long time. v 7.8.1 diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index d24351a7b1..90ba7e080f 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -45,7 +45,7 @@ class HipchatService < Service end def supported_events - %w(push issue merge_request note) + %w(push issue merge_request note tag_push) end def execute(data) @@ -67,7 +67,7 @@ class HipchatService < Service message = \ case object_kind - when "push" + when "push", "tag_push" create_push_message(data) when "issue" create_issue_message(data) unless is_update?(data) @@ -79,21 +79,27 @@ class HipchatService < Service end def create_push_message(push) - ref = push[:ref].gsub("refs/heads/", "") + if push[:ref].starts_with?('refs/tags/') + ref_type = 'tag' + ref = push[:ref].gsub('refs/tags/', '') + else + ref_type = 'branch' + ref = push[:ref].gsub('refs/heads/', '') + end + before = push[:before] after = push[:after] message = "" message << "#{push[:user_name]} " if before.include?('000000') - message << "pushed new branch #{ref}"\ - " to "\ - "#{project_url}\n" + " to #{project_link}\n" elsif after.include?('000000') - message << "removed branch #{ref} from #{project.name_with_namespace.gsub!(/\s/,'')} \n" + message << "removed #{ref_type} #{ref} from #{project_name} \n" else - message << "pushed to branch #{ref} " message << "of #{project.name_with_namespace.gsub!(/\s/,'')} " message << "(Compare changes)" @@ -119,7 +125,7 @@ class HipchatService < Service end def create_issue_message(data) - username = data[:user][:username] + user_name = data[:user][:name] obj_attr = data[:object_attributes] obj_attr = HashWithIndifferentAccess.new(obj_attr) @@ -129,8 +135,8 @@ class HipchatService < Service issue_url = obj_attr[:url] description = obj_attr[:description] - issue_link = "##{issue_iid}" - message = "#{username} #{state} issue #{issue_link} in #{project_link}: #{title}" + issue_link = "issue ##{issue_iid}" + message = "#{user_name} #{state} #{issue_link} in #{project_link}: #{title}" if description description = format_body(description) @@ -141,7 +147,7 @@ class HipchatService < Service end def create_merge_request_message(data) - username = data[:user][:username] + user_name = data[:user][:name] obj_attr = data[:object_attributes] obj_attr = HashWithIndifferentAccess.new(obj_attr) @@ -153,8 +159,8 @@ class HipchatService < Service title = obj_attr[:title] merge_request_url = "#{project_url}/merge_requests/#{merge_request_id}" - merge_request_link = "##{merge_request_id}" - message = "#{username} #{state} merge request #{merge_request_link} in " \ + merge_request_link = "merge request ##{merge_request_id}" + message = "#{user_name} #{state} #{merge_request_link} in " \ "#{project_link}: #{title}" if description @@ -171,7 +177,7 @@ class HipchatService < Service def create_note_message(data) data = HashWithIndifferentAccess.new(data) - username = data[:user][:username] + user_name = data[:user][:name] repo_attr = HashWithIndifferentAccess.new(data[:repository]) @@ -208,7 +214,7 @@ class HipchatService < Service end subject_html = "#{subject_type} #{subject_desc}" - message = "#{username} commented on #{subject_html} in #{project_link}: " + message = "#{user_name} commented on #{subject_html} in #{project_link}: " message << title if note diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index a58840116f..36d9874edd 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -44,7 +44,7 @@ class SlackService < Service end def supported_events - %w(push issue merge_request note) + %w(push issue merge_request note tag_push) end def execute(data) @@ -64,7 +64,7 @@ class SlackService < Service message = \ case object_kind - when "push" + when "push", "tag_push" PushMessage.new(data) when "issue" IssueMessage.new(data) unless is_update?(data) diff --git a/app/models/project_services/slack_service/issue_message.rb b/app/models/project_services/slack_service/issue_message.rb index e2fed0bb1b..5af24a8060 100644 --- a/app/models/project_services/slack_service/issue_message.rb +++ b/app/models/project_services/slack_service/issue_message.rb @@ -1,6 +1,6 @@ class SlackService class IssueMessage < BaseMessage - attr_reader :username + attr_reader :user_name attr_reader :title attr_reader :project_name attr_reader :project_url @@ -11,7 +11,7 @@ class SlackService attr_reader :description def initialize(params) - @username = params[:user][:username] + @user_name = params[:user][:name] @project_name = params[:project_name] @project_url = params[:project_url] @@ -34,7 +34,7 @@ class SlackService private def message - "#{username} #{state} issue #{issue_link} in #{project_link}: #{title}" + "#{user_name} #{state} #{issue_link} in #{project_link}: *#{title}*" end def opened_issue? @@ -50,7 +50,7 @@ class SlackService end def issue_link - "[##{issue_iid}](#{issue_url})" + "[issue ##{issue_iid}](#{issue_url})" end end end diff --git a/app/models/project_services/slack_service/merge_message.rb b/app/models/project_services/slack_service/merge_message.rb index 4dcce1d15a..e792c258f7 100644 --- a/app/models/project_services/slack_service/merge_message.rb +++ b/app/models/project_services/slack_service/merge_message.rb @@ -1,15 +1,16 @@ class SlackService class MergeMessage < BaseMessage - attr_reader :username + attr_reader :user_name attr_reader :project_name attr_reader :project_url attr_reader :merge_request_id attr_reader :source_branch attr_reader :target_branch attr_reader :state + attr_reader :title def initialize(params) - @username = params[:user][:username] + @user_name = params[:user][:name] @project_name = params[:project_name] @project_url = params[:project_url] @@ -19,6 +20,7 @@ class SlackService @source_branch = obj_attr[:source_branch] @target_branch = obj_attr[:target_branch] @state = obj_attr[:state] + @title = format_title(obj_attr[:title]) end def pretext @@ -31,6 +33,10 @@ class SlackService private + def format_title(title) + '*' + title.lines.first.chomp + '*' + end + def message merge_request_message end @@ -40,11 +46,11 @@ class SlackService end def merge_request_message - "#{username} #{state} merge request #{merge_request_link} in #{project_link}" + "#{user_name} #{state} #{merge_request_link} in #{project_link}: #{title}" end def merge_request_link - "[##{merge_request_id}](#{merge_request_url})" + "[merge request ##{merge_request_id}](#{merge_request_url})" end def merge_request_url diff --git a/app/models/project_services/slack_service/note_message.rb b/app/models/project_services/slack_service/note_message.rb index f93dc358f6..074478b292 100644 --- a/app/models/project_services/slack_service/note_message.rb +++ b/app/models/project_services/slack_service/note_message.rb @@ -1,7 +1,7 @@ class SlackService class NoteMessage < BaseMessage attr_reader :message - attr_reader :username + attr_reader :user_name attr_reader :project_name attr_reader :project_link attr_reader :note @@ -10,7 +10,7 @@ class SlackService def initialize(params) params = HashWithIndifferentAccess.new(params) - @username = params[:user][:username] + @user_name = params[:user][:name] @project_name = params[:project_name] @project_url = params[:project_url] @@ -47,28 +47,28 @@ class SlackService commit_sha = Commit.truncate_sha(commit_sha) commit_link = "[commit #{commit_sha}](#{@note_url})" title = format_title(commit[:message]) - @message = "#{@username} commented on #{commit_link} in #{project_link}: *#{title}*" + @message = "#{@user_name} commented on #{commit_link} in #{project_link}: *#{title}*" end def create_issue_note(issue) issue_iid = issue[:iid] note_link = "[issue ##{issue_iid}](#{@note_url})" title = format_title(issue[:title]) - @message = "#{@username} commented on #{note_link} in #{project_link}: *#{title}*" + @message = "#{@user_name} commented on #{note_link} in #{project_link}: *#{title}*" end def create_merge_note(merge_request) merge_request_id = merge_request[:iid] merge_request_link = "[merge request ##{merge_request_id}](#{@note_url})" title = format_title(merge_request[:title]) - @message = "#{@username} commented on #{merge_request_link} in #{project_link}: *#{title}*" + @message = "#{@user_name} commented on #{merge_request_link} in #{project_link}: *#{title}*" end def create_snippet_note(snippet) snippet_id = snippet[:id] snippet_link = "[snippet ##{snippet_id}](#{@note_url})" title = format_title(snippet[:title]) - @message = "#{@username} commented on #{snippet_link} in #{project_link}: *#{title}*" + @message = "#{@user_name} commented on #{snippet_link} in #{project_link}: *#{title}*" end def description_message diff --git a/app/models/project_services/slack_service/push_message.rb b/app/models/project_services/slack_service/push_message.rb index 2e566bc317..3dc2df0476 100644 --- a/app/models/project_services/slack_service/push_message.rb +++ b/app/models/project_services/slack_service/push_message.rb @@ -6,7 +6,8 @@ class SlackService attr_reader :project_name attr_reader :project_url attr_reader :ref - attr_reader :username + attr_reader :ref_type + attr_reader :user_name def initialize(params) @after = params[:after] @@ -14,8 +15,14 @@ class SlackService @commits = params.fetch(:commits, []) @project_name = params[:project_name] @project_url = params[:project_url] - @ref = params[:ref].gsub('refs/heads/', '') - @username = params[:user_name] + if params[:ref].starts_with?('refs/tags/') + @ref_type = 'tag' + @ref = params[:ref].gsub('refs/tags/', '') + else + @ref_type = 'branch' + @ref = params[:ref].gsub('refs/heads/', '') + end + @user_name = params[:user_name] end def pretext @@ -45,15 +52,15 @@ class SlackService end def new_branch_message - "#{username} pushed new branch #{branch_link} to #{project_link}" + "#{user_name} pushed new #{ref_type} #{branch_link} to #{project_link}" end def removed_branch_message - "#{username} removed branch #{ref} from #{project_link}" + "#{user_name} removed #{ref_type} #{ref} from #{project_link}" end def push_message - "#{username} pushed to branch #{branch_link} of #{project_link} (#{compare_link})" + "#{user_name} pushed to #{ref_type} #{branch_link} of #{project_link} (#{compare_link})" end def commit_messages diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index 95ce4f8e4a..b9f2bee148 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -50,6 +50,35 @@ describe HipchatService do expect(WebMock).to have_requested(:post, api_url).once end + + it "should create a push message" do + message = hipchat.send(:create_push_message, push_sample_data) + + obj_attr = push_sample_data[:object_attributes] + branch = push_sample_data[:ref].gsub('refs/heads/', '') + expect(message).to include("#{user.name} pushed to branch " \ + "#{branch} of " \ + "#{project_name}") + end + end + + context 'tag_push events' do + let(:push_sample_data) { Gitlab::PushDataBuilder.build(project, user, '000000', '111111', 'refs/tags/test', []) } + + it "should call Hipchat API for tag push events" do + hipchat.execute(push_sample_data) + + expect(WebMock).to have_requested(:post, api_url).once + end + + it "should create a tag push message" do + message = hipchat.send(:create_push_message, push_sample_data) + + obj_attr = push_sample_data[:object_attributes] + expect(message).to eq("#{user.name} pushed new tag " \ + "test to " \ + "#{project_name}\n") + end end context 'issue events' do @@ -67,8 +96,8 @@ describe HipchatService do message = hipchat.send(:create_issue_message, issues_sample_data) obj_attr = issues_sample_data[:object_attributes] - expect(message).to eq("#{user.username} opened issue " \ - "##{obj_attr["iid"]} in " \ + expect(message).to eq("#{user.name} opened " \ + "issue ##{obj_attr["iid"]} in " \ "#{project_name}: " \ "Awesome issue" \ "
please fix
") @@ -91,8 +120,8 @@ describe HipchatService do merge_sample_data) obj_attr = merge_sample_data[:object_attributes] - expect(message).to eq("#{user.username} opened merge request " \ - "##{obj_attr["iid"]} in " \ + expect(message).to eq("#{user.name} opened " \ + "merge request ##{obj_attr["iid"]} in " \ "#{project_name}: " \ "Awesome merge request" \ "
please fix
") @@ -122,7 +151,7 @@ describe HipchatService do commit_id = Commit.truncate_sha(data[:commit][:id]) title = hipchat.send(:format_title, data[:commit][:message]) - expect(message).to eq("#{user.username} commented on " \ + expect(message).to eq("#{user.name} commented on " \ "commit #{commit_id} in " \ "#{project_name}: " \ "#{title}" \ @@ -141,7 +170,7 @@ describe HipchatService do merge_id = data[:merge_request]['iid'] title = data[:merge_request]['title'] - expect(message).to eq("#{user.username} commented on " \ + expect(message).to eq("#{user.name} commented on " \ "merge request ##{merge_id} in " \ "#{project_name}: " \ "#{title}" \ @@ -158,7 +187,7 @@ describe HipchatService do issue_id = data[:issue]['iid'] title = data[:issue]['title'] - expect(message).to eq("#{user.username} commented on " \ + expect(message).to eq("#{user.name} commented on " \ "issue ##{issue_id} in " \ "#{project_name}: " \ "#{title}" \ @@ -177,7 +206,7 @@ describe HipchatService do snippet_id = data[:snippet]['id'] title = data[:snippet]['title'] - expect(message).to eq("#{user.username} commented on " \ + expect(message).to eq("#{user.name} commented on " \ "snippet ##{snippet_id} in " \ "#{project_name}: " \ "#{title}" \ diff --git a/spec/models/project_services/slack_service/issue_message_spec.rb b/spec/models/project_services/slack_service/issue_message_spec.rb index a23a7cc068..8bca1fef44 100644 --- a/spec/models/project_services/slack_service/issue_message_spec.rb +++ b/spec/models/project_services/slack_service/issue_message_spec.rb @@ -6,7 +6,8 @@ describe SlackService::IssueMessage do let(:args) { { user: { - username: 'username' + name: 'Test User', + username: 'Test User' }, project_name: 'project_name', project_url: 'somewhere.com', @@ -29,8 +30,8 @@ describe SlackService::IssueMessage do context 'open' do it 'returns a message regarding opening of issues' do expect(subject.pretext).to eq( - 'username opened issue in : '\ - 'Issue title') + 'Test User opened in : '\ + '*Issue title*') expect(subject.attachments).to eq([ { text: "issue description", @@ -47,8 +48,8 @@ describe SlackService::IssueMessage do end it 'returns a message regarding closing of issues' do expect(subject.pretext). to eq( - 'username closed issue in : '\ - 'Issue title') + 'Test User closed in : '\ + '*Issue title*') expect(subject.attachments).to be_empty end end diff --git a/spec/models/project_services/slack_service/merge_message_spec.rb b/spec/models/project_services/slack_service/merge_message_spec.rb index 25d03cd873..aeb408aa76 100644 --- a/spec/models/project_services/slack_service/merge_message_spec.rb +++ b/spec/models/project_services/slack_service/merge_message_spec.rb @@ -6,13 +6,14 @@ describe SlackService::MergeMessage do let(:args) { { user: { - username: 'username' + name: 'Test User', + username: 'Test User' }, project_name: 'project_name', project_url: 'somewhere.com', object_attributes: { - title: 'Issue title', + title: "Issue title\nSecond line", id: 10, iid: 100, assignee_id: 1, @@ -30,8 +31,8 @@ describe SlackService::MergeMessage do context 'open' do it 'returns a message regarding opening of merge requests' do expect(subject.pretext).to eq( - 'username opened merge request '\ - 'in ') + 'Test User opened '\ + 'in : *Issue title*') expect(subject.attachments).to be_empty end end @@ -42,8 +43,8 @@ describe SlackService::MergeMessage do end it 'returns a message regarding closing of merge requests' do expect(subject.pretext).to eq( - 'username closed merge request '\ - 'in ') + 'Test User closed '\ + 'in : *Issue title*') expect(subject.attachments).to be_empty end end diff --git a/spec/models/project_services/slack_service/note_message_spec.rb b/spec/models/project_services/slack_service/note_message_spec.rb index f2516c1000..21fb575480 100644 --- a/spec/models/project_services/slack_service/note_message_spec.rb +++ b/spec/models/project_services/slack_service/note_message_spec.rb @@ -37,7 +37,7 @@ describe SlackService::NoteMessage do it 'returns a message regarding notes on commits' do message = SlackService::NoteMessage.new(@args) - expect(message.pretext).to eq("username commented on " \ + expect(message.pretext).to eq("Test User commented on " \ " in : " \ "*Added a commit message*") expected_attachments = [ @@ -62,7 +62,7 @@ describe SlackService::NoteMessage do end it 'returns a message regarding notes on a merge request' do message = SlackService::NoteMessage.new(@args) - expect(message.pretext).to eq("username commented on " \ + expect(message.pretext).to eq("Test User commented on " \ " in : " \ "*merge request title*") expected_attachments = [ @@ -89,7 +89,7 @@ describe SlackService::NoteMessage do it 'returns a message regarding notes on an issue' do message = SlackService::NoteMessage.new(@args) expect(message.pretext).to eq( - "username commented on " \ + "Test User commented on " \ " in : " \ "*issue title*") expected_attachments = [ @@ -114,7 +114,7 @@ describe SlackService::NoteMessage do it 'returns a message regarding notes on a project snippet' do message = SlackService::NoteMessage.new(@args) - expect(message.pretext).to eq("username commented on " \ + expect(message.pretext).to eq("Test User commented on " \ " in : " \ "*snippet title*") expected_attachments = [ diff --git a/spec/models/project_services/slack_service/push_message_spec.rb b/spec/models/project_services/slack_service/push_message_spec.rb index ef0e7a6ee3..3ef065459d 100644 --- a/spec/models/project_services/slack_service/push_message_spec.rb +++ b/spec/models/project_services/slack_service/push_message_spec.rb @@ -39,6 +39,26 @@ describe SlackService::PushMessage do end end + context 'tag push' do + let(:args) { + { + after: 'after', + before: '000000', + project_name: 'project_name', + ref: 'refs/tags/new_tag', + user_name: 'user_name', + project_url: 'url' + } + } + + it 'returns a message regarding pushes' do + expect(subject.pretext).to eq('user_name pushed new tag ' \ + ' to ' \ + '') + expect(subject.attachments).to be_empty + end + end + context 'new branch' do before do args[:before] = '000000' From 663b3c968f73f8ffebf32059fed86192ecbee5d8 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 6 Mar 2015 17:14:19 +0100 Subject: [PATCH 066/143] Condense commits already in target branch when updating merge request source branch. --- CHANGELOG | 1 + app/models/note.rb | 31 ++++++++++++++++--- .../merge_requests/refresh_service.rb | 8 ++++- .../merge_requests/refresh_service_spec.rb | 2 +- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b927b60140..2cea709f16 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,7 @@ v 7.9.0 (unreleased) - Add Bitbucket omniauth provider. - Add Bitbucket importer. - Support referencing issues to a project whose name starts with a digit + - Condense commits already in target branch when updating merge request source branch. v 7.8.2 - Fix service migration issue when upgrading from versions prior to 7.3 diff --git a/app/models/note.rb b/app/models/note.rb index e6c258ffbe..e79b7a8834 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -151,18 +151,41 @@ class Note < ActiveRecord::Base ) end - def create_new_commits_note(noteable, project, author, commits) - commits_text = ActionController::Base.helpers.pluralize(commits.size, 'new commit') + def create_new_commits_note(merge_request, project, author, new_commits, existing_commits = []) + total_count = new_commits.length + existing_commits.length + commits_text = ActionController::Base.helpers.pluralize(total_count, 'commit') body = "Added #{commits_text}:\n\n" - commits.each do |commit| + if existing_commits.length > 0 + commit_ids = + if existing_commits.length == 1 + existing_commits.first.short_id + else + "#{existing_commits.first.short_id}...#{existing_commits.last.short_id}" + end + + commits_text = ActionController::Base.helpers.pluralize(existing_commits.length, 'commit') + + branch = + if merge_request.for_fork? + "#{merge_request.target_project_namespace}:#{merge_request.target_branch}" + else + merge_request.target_branch + end + + message = "* #{commit_ids} - _#{commits_text} from branch `#{branch}`_" + body << message + body << "\n" + end + + new_commits.each do |commit| message = "* #{commit.short_id} - #{commit.title}" body << message body << "\n" end create( - noteable: noteable, + noteable: merge_request, project: project, author: author, note: body, diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb index 96761bec99..ea84647276 100644 --- a/app/services/merge_requests/refresh_service.rb +++ b/app/services/merge_requests/refresh_service.rb @@ -82,8 +82,14 @@ module MergeRequests merge_requests = filter_merge_requests(merge_requests) merge_requests.each do |merge_request| + mr_commit_ids = Set.new(merge_request.commits.map(&:id)) + + new_commits, existing_commits = @commits.partition do |commit| + mr_commit_ids.include?(commit.id) + end + Note.create_new_commits_note(merge_request, merge_request.project, - @current_user, @commits) + @current_user, new_commits, existing_commits) end end diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 2830da8781..879df0c9c6 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -61,7 +61,7 @@ describe MergeRequests::RefreshService do it { expect(@merge_request.notes).to be_empty } it { expect(@merge_request).to be_open } - it { expect(@fork_merge_request.notes.last.note).to include('new commit') } + it { expect(@fork_merge_request.notes.last.note).to include('Added 4 commits') } it { expect(@fork_merge_request).to be_open } end From 9f089ac48c22b2f7cfbc7dd0ca29da924c566363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Fri, 6 Mar 2015 19:49:38 +0100 Subject: [PATCH 067/143] use constant-time string compare for internal api authentication Ruby str_equal uses memcmp internally to compare String. Memcmp is vunerable to timing attacks because it returns early on mismatch (on most x32 platforms memcmp uses a bytewise comparision). Devise.secure_compare implements a constant time comparision instead. --- lib/api/helpers.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 228a719fbd..ee678d84c8 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -83,7 +83,10 @@ module API end def authenticate_by_gitlab_shell_token! - unauthorized! unless secret_token == params['secret_token'].try(:chomp) + input = params['secret_token'].try(:chomp) + unless Devise.secure_compare(secret_token, input) + unauthorized! + end end def authenticated_as_admin! From 84ebc22ad2d9296d23b442948dd3435b33d36cbe Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 6 Mar 2015 23:12:26 +0100 Subject: [PATCH 068/143] Use 2 periods instead of 3 to signify inclusive range. --- app/models/note.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/note.rb b/app/models/note.rb index e79b7a8834..43981a0044 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -161,7 +161,7 @@ class Note < ActiveRecord::Base if existing_commits.length == 1 existing_commits.first.short_id else - "#{existing_commits.first.short_id}...#{existing_commits.last.short_id}" + "#{existing_commits.first.short_id}..#{existing_commits.last.short_id}" end commits_text = ActionController::Base.helpers.pluralize(existing_commits.length, 'commit') From 4dddaef8661c8bfb5127d5db12b91d18cfcf0b8f Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 6 Mar 2015 23:08:28 +0100 Subject: [PATCH 069/143] Automatically link commit ranges to compare page. --- CHANGELOG | 1 + lib/gitlab/markdown.rb | 28 +++++++++++- lib/gitlab/reference_extractor.rb | 16 +++++-- spec/helpers/gitlab_markdown_helper_spec.rb | 48 +++++++++++++++++++++ spec/lib/gitlab/reference_extractor_spec.rb | 19 ++++++++ 5 files changed, 108 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 611c6c77d5..06eb3c1c2c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,6 +27,7 @@ v 7.9.0 (unreleased) - Add Bitbucket omniauth provider. - Add Bitbucket importer. - Support referencing issues to a project whose name starts with a digit + - Automatically link commit ranges to compare page: sha1...sha4 or sha1..sha4 (includes sha1 in comparison) v 7.8.2 - Fix service migration issue when upgrading from versions prior to 7.3 diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index d85c2ee4f2..2dfa18da48 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -14,6 +14,7 @@ module Gitlab # * !123 for merge requests # * $123 for snippets # * 123456 for commits + # * 123456...7890123 for commit ranges (comparisons) # # It also parses Emoji codes to insert images. See # http://www.emoji-cheat-sheet.com/ for a list of the supported icons. @@ -133,13 +134,14 @@ module Gitlab |#{PROJ_STR}?\#(?([a-zA-Z\-]+-)?\d+) # Issue ID |#{PROJ_STR}?!(?\d+) # MR ID |\$(?\d+) # Snippet ID + |(#{PROJ_STR}@)?(?[\h]{6,40}\.{2,3}[\h]{6,40}) # Commit range |(#{PROJ_STR}@)?(?[\h]{6,40}) # Commit ID |(?gfm-extraction-[\h]{6,40}) # Skip gfm extractions. Otherwise will be parsed as commit ) (?\W)? # Suffix }x.freeze - TYPES = [:user, :issue, :label, :merge_request, :snippet, :commit].freeze + TYPES = [:user, :issue, :label, :merge_request, :snippet, :commit, :commit_range].freeze def parse_references(text, project = @project) # parse reference links @@ -290,6 +292,30 @@ module Gitlab end end + def reference_commit_range(identifier, project = @project, prefix_text = nil) + from_id, to_id = identifier.split(/\.{2,3}/, 2) + + inclusive = identifier !~ /\.{3}/ + from_id << "^" if inclusive + + if project.valid_repo? && + from = project.repository.commit(from_id) && + to = project.repository.commit(to_id) + + options = html_options.merge( + title: "Commits #{from_id} through #{to_id}", + class: "gfm gfm-commit_range #{html_options[:class]}" + ) + prefix_text = "#{prefix_text}@" if prefix_text + + link_to( + "#{prefix_text}#{identifier}", + namespace_project_compare_url(project.namespace, project, from: from_id, to: to_id), + options + ) + end + end + def reference_external_issue(identifier, project = @project, prefix_text = nil) url = url_for_issue(identifier, project) diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index 7e5c991a22..5b9772de16 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -1,13 +1,13 @@ module Gitlab # Extract possible GFM references from an arbitrary String for further processing. class ReferenceExtractor - attr_accessor :users, :labels, :issues, :merge_requests, :snippets, :commits + attr_accessor :users, :labels, :issues, :merge_requests, :snippets, :commits, :commit_ranges include Markdown def initialize - @users, @labels, @issues, @merge_requests, @snippets, @commits = - [], [], [], [], [], [] + @users, @labels, @issues, @merge_requests, @snippets, @commits, @commit_ranges = + [], [], [], [], [], [], [] end def analyze(string, project) @@ -60,6 +60,16 @@ module Gitlab end.reject(&:nil?) end + def commit_ranges_for(project = nil) + commit_ranges.map do |entry| + repo = entry[:project].repository if entry[:project] + if repo && should_lookup?(project, entry[:project]) + from_id, to_id = entry[:id].split(/\.{2,3}/, 2) + [repo.commit(from_id), repo.commit(to_id)] + end + end.reject(&:nil?) + end + private def reference_link(type, identifier, project, _) diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 76fcf888a6..74a42932fe 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -9,6 +9,7 @@ describe GitlabMarkdownHelper do let(:user) { create(:user, username: 'gfm') } let(:commit) { project.repository.commit } + let(:earlier_commit){ project.repository.commit("HEAD~2") } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let(:snippet) { create(:project_snippet, project: project) } @@ -53,6 +54,53 @@ describe GitlabMarkdownHelper do to have_selector('a.gfm.foo') end + describe "referencing a commit range" do + let(:expected) { namespace_project_compare_path(project.namespace, project, from: earlier_commit.id, to: commit.id) } + + it "should link using a full id" do + actual = "What happened in #{earlier_commit.id}...#{commit.id}" + expect(gfm(actual)).to match(expected) + end + + it "should link using a short id" do + actual = "What happened in #{earlier_commit.short_id}...#{commit.short_id}" + expected = namespace_project_compare_path(project.namespace, project, from: earlier_commit.short_id, to: commit.short_id) + expect(gfm(actual)).to match(expected) + end + + it "should link inclusively" do + actual = "What happened in #{earlier_commit.id}..#{commit.id}" + expected = namespace_project_compare_path(project.namespace, project, from: "#{earlier_commit.id}^", to: commit.id) + expect(gfm(actual)).to match(expected) + end + + it "should link with adjacent text" do + actual = "(see #{earlier_commit.id}...#{commit.id})" + expect(gfm(actual)).to match(expected) + end + + it "should keep whitespace intact" do + actual = "Changes #{earlier_commit.id}...#{commit.id} dramatically" + expected = /Changes #{earlier_commit.id}...#{commit.id}<\/a> dramatically/ + expect(gfm(actual)).to match(expected) + end + + it "should not link with an invalid id" do + actual = expected = "What happened in #{earlier_commit.id.reverse}...#{commit.id.reverse}" + expect(gfm(actual)).to eq(expected) + end + + it "should include a title attribute" do + actual = "What happened in #{earlier_commit.id}...#{commit.id}" + expect(gfm(actual)).to match(/title="Commits #{earlier_commit.id} through #{commit.id}"/) + end + + it "should include standard gfm classes" do + actual = "What happened in #{earlier_commit.id}...#{commit.id}" + expect(gfm(actual)).to match(/class="\s?gfm gfm-commit_range\s?"/) + end + end + describe "referencing a commit" do let(:expected) { namespace_project_commit_path(project.namespace, project, commit) } diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 0847c31258..034f8ee7c4 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -31,6 +31,11 @@ describe Gitlab::ReferenceExtractor do expect(subject.commits).to eq([{ project: nil, id: '98cf0ae3' }]) end + it 'extracts commit ranges' do + subject.analyze('here you go, a commit range: 98cf0ae3...98cf0ae4', nil) + expect(subject.commit_ranges).to eq([{ project: nil, id: '98cf0ae3...98cf0ae4' }]) + end + it 'extracts multiple references and preserves their order' do subject.analyze('@me and @you both care about this', nil) expect(subject.users).to eq([ @@ -100,5 +105,19 @@ describe Gitlab::ReferenceExtractor do expect(extracted[0].sha).to eq(commit.sha) expect(extracted[0].message).to eq(commit.message) end + + it 'accesses valid commit ranges' do + commit = project.repository.commit('master') + earlier_commit = project.repository.commit('master~2') + + subject.analyze("this references commits #{earlier_commit.sha[0..6]}...#{commit.sha[0..6]}", + project) + extracted = subject.commit_ranges_for(project) + expect(extracted.size).to eq(1) + expect(extracted[0][0].sha).to eq(earlier_commit.sha) + expect(extracted[0][0].message).to eq(earlier_commit.message) + expect(extracted[0][1].sha).to eq(commit.sha) + expect(extracted[0][1].message).to eq(commit.message) + end end end From 3bfd53149c2791b1598f3fc14e37cd33b7aef2d5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Mar 2015 18:36:22 -0800 Subject: [PATCH 070/143] Replace bs-callout with alert --- app/assets/stylesheets/gl_bootstrap.scss | 46 ------------------- app/views/admin/groups/_form.html.haml | 2 +- app/views/admin/services/_form.html.haml | 2 +- app/views/profiles/show.html.haml | 2 +- app/views/projects/blob/_blob.html.haml | 2 +- app/views/projects/diffs/_warning.html.haml | 2 +- app/views/projects/imports/new.html.haml | 2 +- app/views/projects/labels/_form.html.haml | 2 +- .../merge_requests/_new_submit.html.haml | 4 +- .../merge_requests/show/_diffs.html.haml | 2 +- app/views/projects/new.html.haml | 2 +- .../protected_branches/index.html.haml | 2 +- app/views/projects/services/_form.html.haml | 2 +- app/views/shared/_group_form.html.haml | 2 +- 14 files changed, 14 insertions(+), 60 deletions(-) diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/gl_bootstrap.scss index 34ddf6f871..2f07f7202b 100644 --- a/app/assets/stylesheets/gl_bootstrap.scss +++ b/app/assets/stylesheets/gl_bootstrap.scss @@ -161,52 +161,6 @@ $brand-danger: $bg_danger; font-size: 12px; } - -/* - * Callouts from Bootstrap3 docs - * - * Not quite alerts, but custom and helpful notes for folks reading the docs. - * Requires a base and modifier class. - */ - -/* Common styles for all types */ -.bs-callout { - margin: 20px 0; - padding: 20px; - border-left: 3px solid #eee; - color: #666; - background: #f9f9f9; -} -.bs-callout h4 { - margin-top: 0; - margin-bottom: 5px; -} -.bs-callout p:last-child { - margin-bottom: 0; -} - -/* Variations */ -.bs-callout-danger { - background-color: #fdf7f7; - border-color: #eed3d7; - color: #b94a48; -} -.bs-callout-warning { - background-color: #faf8f0; - border-color: #faebcc; - color: #8a6d3b; -} -.bs-callout-info { - background-color: #f4f8fa; - border-color: #bce8f1; - color: #34789a; -} -.bs-callout-success { - background-color: #dff0d8; - border-color: #5cA64d; - color: #3c763d; -} - /** * fix to keep tooltips position in top navigation bar * diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml index 86a7320060..9e7751830a 100644 --- a/app/views/admin/groups/_form.html.haml +++ b/app/views/admin/groups/_form.html.haml @@ -14,7 +14,7 @@ .form-group .col-sm-2 .col-sm-10 - .bs-callout.bs-callout-info + .alert.alert-info = render 'shared/group_tips' .form-actions = f.submit 'Create group', class: "btn btn-create" diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml index 62f4001ca6..4ddddbd46e 100644 --- a/app/views/admin/services/_form.html.haml +++ b/app/views/admin/services/_form.html.haml @@ -10,7 +10,7 @@ - @service.errors.full_messages.each do |msg| %p= msg - if @service.help.present? - .bs-callout + .alert.alert-info = preserve do = markdown @service.help diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index b2808c46c0..459361a0d5 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -89,7 +89,7 @@ = link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar" - if @user.public_profile? - .bs-callout.bs-callout-info + .alert.alert-info %h4 Public profile %p Your profile is publicly visible because you joined public project(s) diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml index 64cc3fad6c..05b1f5e841 100644 --- a/app/views/projects/blob/_blob.html.haml +++ b/app/views/projects/blob/_blob.html.haml @@ -15,7 +15,7 @@ - else = link_to title, '#' -%ul.blob-commit-info.bs-callout.bs-callout-info.hidden-xs +%ul.blob-commit-info.alert.alert-info.hidden-xs - blob_commit = @repository.last_commit_for_path(@commit.id, blob.path) = render blob_commit, project: @project diff --git a/app/views/projects/diffs/_warning.html.haml b/app/views/projects/diffs/_warning.html.haml index c9a6b3ebd9..af1f342afb 100644 --- a/app/views/projects/diffs/_warning.html.haml +++ b/app/views/projects/diffs/_warning.html.haml @@ -1,4 +1,4 @@ -.bs-callout.bs-callout-warning +.alert.alert-warning %h4 Too many changes. .pull-right diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml index 097374e112..f1248ac2af 100644 --- a/app/views/projects/imports/new.html.haml +++ b/app/views/projects/imports/new.html.haml @@ -12,7 +12,7 @@ %span Import existing git repo .col-sm-10 = f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git' - .bs-callout.bs-callout-info + .alert.alert-info This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git. %br The import will time out after 4 minutes. For big repositories, use a clone/push combination. diff --git a/app/views/projects/labels/_form.html.haml b/app/views/projects/labels/_form.html.haml index 95912536e4..2305fce112 100644 --- a/app/views/projects/labels/_form.html.haml +++ b/app/views/projects/labels/_form.html.haml @@ -2,7 +2,7 @@ -if @label.errors.any? .row .col-sm-10.col-sm-offset-2 - .bs-callout.bs-callout-danger + .alert.alert-danger - @label.errors.full_messages.each do |msg| %span= msg %br diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml index 73eccfa556..bf80afe878 100644 --- a/app/views/projects/merge_requests/_new_submit.html.haml +++ b/app/views/projects/merge_requests/_new_submit.html.haml @@ -99,11 +99,11 @@ - if @diffs.present? = render "projects/diffs/diffs", diffs: @diffs, project: @project - elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE - .bs-callout.bs-callout-danger + .alert.alert-danger %h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits. %p To preserve performance the line changes are not shown. - else - .bs-callout.bs-callout-danger + .alert.alert-danger %h4 This comparison includes a huge diff. %p To preserve performance the line changes are not shown. diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml index cfef1d5e4c..786b5f3906 100644 --- a/app/views/projects/merge_requests/show/_diffs.html.haml +++ b/app/views/projects/merge_requests/show/_diffs.html.haml @@ -3,7 +3,7 @@ - elsif @merge_request_diff.empty? .nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch} - else - .bs-callout.bs-callout-warning + .alert.alert-warning %h4 Changes view for this comparison is extremely large. %p diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 025c4fd550..5daf8470d8 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -34,7 +34,7 @@ %span Import existing git repo .col-sm-10 = f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git' - .bs-callout.bs-callout-info + .alert.alert-info This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git. %br The import will time out after 4 minutes. For big repositories, use a clone/push combination. diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml index dc20e96732..cfe2808417 100644 --- a/app/views/projects/protected_branches/index.html.haml +++ b/app/views/projects/protected_branches/index.html.haml @@ -2,7 +2,7 @@ %p.light Keep stable branches secure and force developers to use Merge Requests %hr -.bs-callout.bs-callout-info +.alert.alert-info %p Protected branches are designed to %ul %li prevent pushes from everybody except #{link_to "masters", help_page_path("permissions", "permissions"), class: "vlink"} diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index defcdbe268..8afae91d75 100644 --- a/app/views/projects/services/_form.html.haml +++ b/app/views/projects/services/_form.html.haml @@ -18,7 +18,7 @@ %li= msg - if @service.help.present? - .bs-callout + .alert.alert-info = preserve do = markdown @service.help diff --git a/app/views/shared/_group_form.html.haml b/app/views/shared/_group_form.html.haml index 5875f71bac..b34dd53e3b 100644 --- a/app/views/shared/_group_form.html.haml +++ b/app/views/shared/_group_form.html.haml @@ -15,7 +15,7 @@ = f.text_field :path, placeholder: 'open-source', class: 'form-control', autofocus: local_assigns[:autofocus] || false - if @group.persisted? - .bs-callout.bs-callout-danger + .alert.alert-danger %ul %li Changing group path can have unintended side effects. %li Renaming group path will rename directory for all related projects From cd73b26e0732ab3ce979e971e6ceeb0c2417b5c3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Mar 2015 19:02:12 -0800 Subject: [PATCH 071/143] Refactor gitlab css state colors --- app/assets/stylesheets/generic/buttons.scss | 8 ++-- app/assets/stylesheets/generic/common.scss | 2 +- app/assets/stylesheets/generic/issue_box.scss | 6 +-- app/assets/stylesheets/generic/jquery.scss | 4 +- app/assets/stylesheets/generic/selects.scss | 2 +- app/assets/stylesheets/gl_bootstrap.scss | 44 ++++++++++++------- app/assets/stylesheets/main/variables.scss | 27 +++--------- .../stylesheets/sections/dashboard.scss | 8 ++-- .../stylesheets/sections/merge_requests.scss | 16 +++---- app/assets/stylesheets/sections/notes.scss | 2 +- .../stylesheets/sections/notifications.scss | 6 +-- app/assets/stylesheets/sections/projects.scss | 6 +-- app/assets/stylesheets/sections/tree.scss | 2 +- 13 files changed, 65 insertions(+), 68 deletions(-) diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss index d106e3b201..7cc9782f53 100644 --- a/app/assets/stylesheets/generic/buttons.scss +++ b/app/assets/stylesheets/generic/buttons.scss @@ -41,16 +41,16 @@ } &.btn-close { - color: $bg_danger; - border-color: $border_danger; + color: $gl-danger; + border-color: $gl-danger; &:hover { color: #B94A48; } } &.btn-reopen { - color: $bg_success; - border-color: $border_success; + color: $gl-success; + border-color: $gl-success; &:hover { color: #468847; } diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss index 3db821fdf7..ca01e20720 100644 --- a/app/assets/stylesheets/generic/common.scss +++ b/app/assets/stylesheets/generic/common.scss @@ -61,7 +61,7 @@ pre { .dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus { - background: $bg_primary; + background: $gl-primary; color: #FFF } diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss index 2563ab516e..9558f241b7 100644 --- a/app/assets/stylesheets/generic/issue_box.scss +++ b/app/assets/stylesheets/generic/issue_box.scss @@ -11,17 +11,17 @@ margin-right: 5px; &.issue-box-closed { - background-color: $bg_danger; + background-color: $gl-danger; color: #FFF; } &.issue-box-merged { - background-color: $bg_primary; + background-color: $gl-primary; color: #FFF; } &.issue-box-open { - background-color: $bg_success; + background-color: $gl-success; color: #FFF; } diff --git a/app/assets/stylesheets/generic/jquery.scss b/app/assets/stylesheets/generic/jquery.scss index bfbbc7d25e..871b808bad 100644 --- a/app/assets/stylesheets/generic/jquery.scss +++ b/app/assets/stylesheets/generic/jquery.scss @@ -41,8 +41,8 @@ } .ui-state-active { - border: 1px solid $bg_primary; - background: $bg_primary; + border: 1px solid $gl-primary; + background: $gl-primary; color: #FFF; } diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss index d85e80a512..2a2f9e8eb5 100644 --- a/app/assets/stylesheets/generic/selects.scss +++ b/app/assets/stylesheets/generic/selects.scss @@ -42,7 +42,7 @@ .select2-results { max-height: 350px; .select2-highlighted { - background: $bg_primary; + background: $gl-primary; } } } diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/gl_bootstrap.scss index 2f07f7202b..1c29fdac37 100644 --- a/app/assets/stylesheets/gl_bootstrap.scss +++ b/app/assets/stylesheets/gl_bootstrap.scss @@ -4,15 +4,27 @@ */ $font-size-base: 13px !default; -$nav-pills-active-link-hover-bg: $bg_primary; -$pagination-active-bg: $bg_primary; -$list-group-active-bg: $bg_primary; +$nav-pills-active-link-hover-bg: $gl-primary; +$pagination-active-bg: $gl-primary; +$list-group-active-bg: $gl-primary; -$brand-primary: $bg_primary; -$brand-success: $bg_success; -$brand-info: #029ACF; -$brand-warning: $bg_warning; -$brand-danger: $bg_danger; +$brand-primary: $gl-primary; +$brand-success: $gl-success; +$brand-info: #029ACF; +$brand-warning: $gl-warning; +$brand-danger: $gl-danger; + +$state-primary-bg: lighten($gl-primary, 30%); +$state-success-bg: lighten($gl-success, 10%); +$state-info-bg: lighten($gl-info, 30%); +$state-warning-bg: lighten($gl-warning, 30%); +$state-danger-bg: lighten($gl-danger, 30%); + +$state-primary-txt: $gl-primary; +$state-success-txt: $gl-success; +$state-info-txt: $gl-info; +$state-warning-txt: $gl-warning; +$state-danger-txt: $gl-danger; // Core variables and mixins @import "bootstrap/variables"; @@ -226,31 +238,31 @@ $brand-danger: $bg_danger; .panel-danger { @include panel-colored; .panel-heading { - color: $border_danger; - border-color: $border_danger; + color: $gl-danger; + border-color: $gl-danger; } } .panel-success { @include panel-colored; .panel-heading { - color: $border_success; - border-color: $border_success; + color: $gl-success; + border-color: $gl-success; } } .panel-primary { @include panel-colored; .panel-heading { - color: $border_primary; - border-color: $border_primary; + color: $gl-primary; + border-color: $gl-primary; } } .panel-warning { @include panel-colored; .panel-heading { - color: $border_warning; - border-color: $border_warning; + color: $gl-warning; + border-color: $gl-warning; } } diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss index acbf5be94a..57b881c073 100644 --- a/app/assets/stylesheets/main/variables.scss +++ b/app/assets/stylesheets/main/variables.scss @@ -14,28 +14,13 @@ $link_hover_color: darken($link-color, 10%); $btn-border: 1px solid #ccc; /* - * Success colors (green) + * State colors: */ -$border_success: #019875; -$bg_success: #019875; - -/* - * Danger colors (red) - */ -$border_danger: #d43f3a; -$bg_danger: #d9534f; - -/* - * Primary colors (blue) - */ -$border_primary: #446e9b; -$bg_primary: #446e9b; - -/* - * Warning colors (yellow) - */ -$bg_warning: #EB9532; -$border_warning: #EB9532; +$gl-success: #019875; +$gl-danger: #d9534f; +$gl-primary: #446e9b; +$gl-info: #029ACF; +$gl-warning: #EB9532; /** * Commit Diff Colors diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/sections/dashboard.scss index d8fd83d44b..c8e3c7d4a2 100644 --- a/app/assets/stylesheets/sections/dashboard.scss +++ b/app/assets/stylesheets/sections/dashboard.scss @@ -111,8 +111,8 @@ } .dash-new-project { - background: $bg_success; - border: 1px solid $border_success; + background: $gl-success; + border: 1px solid $gl-success; a { color: #FFF; @@ -120,8 +120,8 @@ } .dash-new-group { - background: $bg_success; - border: 1px solid $border_success; + background: $gl-success; + border: 1px solid $gl-success; a { color: #FFF; diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss index 0d2d8b0173..01f6a70522 100644 --- a/app/assets/stylesheets/sections/merge_requests.scss +++ b/app/assets/stylesheets/sections/merge_requests.scss @@ -136,8 +136,8 @@ background-color: #F5F5F5; &.ci-success { - color: $bg_success; - border-color: $border_success; + color: $gl-success; + border-color: $gl-success; background-color: #F1FAF1; } @@ -148,20 +148,20 @@ } &.ci-running { - color: $bg_warning; - border-color: $border_warning; + color: $gl-warning; + border-color: $gl-warning; background-color: #FAF5F1; } &.ci-failed { - color: $bg_danger; - border-color: $border_danger; + color: $gl-danger; + border-color: $gl-danger; background-color: #FAF1F1; } &.ci-error { - color: $bg_danger; - border-color: $border_danger; + color: $gl-danger; + border-color: $gl-danger; background-color: #FAF1F1; } } diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 40adc8b3ba..e476b9ac77 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -194,7 +194,7 @@ ul.notes { &:hover { font-size: 24px; - background: $bg_primary; + background: $gl-primary; color: #FFF; @include show-add-diff-note; } diff --git a/app/assets/stylesheets/sections/notifications.scss b/app/assets/stylesheets/sections/notifications.scss index f11c5dff4a..cc273f5522 100644 --- a/app/assets/stylesheets/sections/notifications.scss +++ b/app/assets/stylesheets/sections/notifications.scss @@ -10,13 +10,13 @@ } .ns-part { - color: $bg_primary; + color: $gl-primary; } .ns-watch { - color: $bg_success; + color: $gl-success; } .ns-mute { - color: $bg_danger; + color: $gl-danger; } diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index 8bad9b139f..586698fdd9 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -267,15 +267,15 @@ ul.nav.nav-projects-tabs { } .vs-public { - color: $bg_primary; + color: $gl-primary; } .vs-internal { - color: $bg_warning; + color: $gl-warning; } .vs-private { - color: $bg_success; + color: $gl-success; } .breadcrumb.repo-breadcrumb { diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss index 60a1c00b04..9f91c27f90 100644 --- a/app/assets/stylesheets/sections/tree.scss +++ b/app/assets/stylesheets/sections/tree.scss @@ -46,7 +46,7 @@ } i { - color: $bg_primary; + color: $gl-primary; } img { From 3cbc0b1c6d21ce6797900416ac9c1b22caf94845 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Mar 2015 20:02:34 -0800 Subject: [PATCH 072/143] Cleanup css variables --- app/assets/stylesheets/generic/common.scss | 2 +- .../stylesheets/generic/typography.scss | 72 +- app/assets/stylesheets/gl_bootstrap.scss | 24 +- app/assets/stylesheets/gl_variables.scss | 863 ++++++++++++++++++ app/assets/stylesheets/main/mixins.scss | 8 - app/assets/stylesheets/main/variables.scss | 38 +- app/assets/stylesheets/sections/notes.scss | 7 +- app/assets/stylesheets/sections/projects.scss | 2 +- app/assets/stylesheets/sections/tree.scss | 5 - 9 files changed, 882 insertions(+), 139 deletions(-) create mode 100644 app/assets/stylesheets/gl_variables.scss diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss index ca01e20720..431f1d68a2 100644 --- a/app/assets/stylesheets/generic/common.scss +++ b/app/assets/stylesheets/generic/common.scss @@ -71,7 +71,7 @@ pre { /** FLASH message **/ .author_link { - color: $link_color; + color: $gl-link-color; } .help li { color:$style_color; } diff --git a/app/assets/stylesheets/generic/typography.scss b/app/assets/stylesheets/generic/typography.scss index c547ebb3aa..4d940ee6b2 100644 --- a/app/assets/stylesheets/generic/typography.scss +++ b/app/assets/stylesheets/generic/typography.scss @@ -2,28 +2,12 @@ * Headers * */ -h1.page-title { - @include page-title; - font-size: 28px; -} - -h2.page-title { - @include page-title; - font-size: 24px; -} - -h3.page-title { - @include page-title; - font-size: 22px; -} - -h4.page-title { +.page-title { margin-top: 0px; -} - -h6 { - color: #888; - text-transform: uppercase; + color: #333; + line-height: 1.5; + font-weight: normal; + margin-bottom: 5px; } /** CODE **/ @@ -36,52 +20,6 @@ pre { } } -/** - * Links - * - */ -a { - outline: none; - color: $link_color; - &:hover { - text-decoration: underline; - color: $link_hover_color; - } - - &:focus { - text-decoration: underline; - } - - &.darken { - color: $style_color; - } - - &.lined { - text-decoration: underline; - &:hover { text-decoration: underline; } - } - - &.gray { - color: gray; - } - - &.supp_diff_link { - text-align: center; - padding: 20px 0; - background: #f1f1f1; - width: 100%; - float: left; - } - - &.neib { - margin-right: 15px; - } -} - -a:focus { - outline: none; -} - .monospace { font-family: $monospace_font; } diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/gl_bootstrap.scss index 1c29fdac37..18a6be409d 100644 --- a/app/assets/stylesheets/gl_bootstrap.scss +++ b/app/assets/stylesheets/gl_bootstrap.scss @@ -2,29 +2,7 @@ * Twitter bootstrap with GitLab customizations/additions * */ - -$font-size-base: 13px !default; -$nav-pills-active-link-hover-bg: $gl-primary; -$pagination-active-bg: $gl-primary; -$list-group-active-bg: $gl-primary; - -$brand-primary: $gl-primary; -$brand-success: $gl-success; -$brand-info: #029ACF; -$brand-warning: $gl-warning; -$brand-danger: $gl-danger; - -$state-primary-bg: lighten($gl-primary, 30%); -$state-success-bg: lighten($gl-success, 10%); -$state-info-bg: lighten($gl-info, 30%); -$state-warning-bg: lighten($gl-warning, 30%); -$state-danger-bg: lighten($gl-danger, 30%); - -$state-primary-txt: $gl-primary; -$state-success-txt: $gl-success; -$state-info-txt: $gl-info; -$state-warning-txt: $gl-warning; -$state-danger-txt: $gl-danger; +@import "gl_variables"; // Core variables and mixins @import "bootstrap/variables"; diff --git a/app/assets/stylesheets/gl_variables.scss b/app/assets/stylesheets/gl_variables.scss new file mode 100644 index 0000000000..d40ab1b916 --- /dev/null +++ b/app/assets/stylesheets/gl_variables.scss @@ -0,0 +1,863 @@ +// Override Bootstrap variables here (defaults from bootstrap-sass v3.3.3): + +// +// Variables +// -------------------------------------------------- + + +//== Colors +// +//## Gray and brand colors for use across Bootstrap. + +// $gray-base: #000 +// $gray-darker: lighten($gray-base, 13.5%) // #222 +// $gray-dark: lighten($gray-base, 20%) // #333 +// $gray: lighten($gray-base, 33.5%) // #555 +// $gray-light: lighten($gray-base, 46.7%) // #777 +// $gray-lighter: lighten($gray-base, 93.5%) // #eee + +$brand-primary: $gl-primary; +$brand-success: $gl-success; +$brand-info: $gl-info; +$brand-warning: $gl-warning; +$brand-danger: $gl-danger; + + +//== Scaffolding +// +//## Settings for some of the most global styles. + +//** Background color for ``. +// $body-bg: #fff +//** Global text color on ``. +// $text-color: $gray-dark + +//** Global textual link color. +$link-color: $gl-link-color; +//** Link hover color set via `darken()` function. +// $link-hover-color: darken($link-color, 15%) +//** Link hover decoration. +// $link-hover-decoration: underline + + +//== Typography +// +//## Font, line-height, and color for body text, headings, and more. + +// $font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif +// $font-family-serif: Georgia, "Times New Roman", Times, serif +//** Default monospace fonts for ``, ``, and `
`.
+// $font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace
+// $font-family-base:        $font-family-sans-serif
+
+$font-size-base:          $gl-font-size;
+// $font-size-large:         ceil(($font-size-base * 1.25)) // ~18px
+// $font-size-small:         ceil(($font-size-base * 0.85)) // ~12px
+
+// $font-size-h1:            floor(($font-size-base * 2.6)) // ~36px
+// $font-size-h2:            floor(($font-size-base * 2.15)) // ~30px
+// $font-size-h3:            ceil(($font-size-base * 1.7)) // ~24px
+// $font-size-h4:            ceil(($font-size-base * 1.25)) // ~18px
+// $font-size-h5:            $font-size-base
+// $font-size-h6:            ceil(($font-size-base * 0.85)) // ~12px
+
+//** Unit-less `line-height` for use in components like buttons.
+// $line-height-base:        1.428571429 // 20/14
+//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
+// $line-height-computed:    floor(($font-size-base * $line-height-base)) // ~20px
+
+//** By default, this inherits from the ``.
+// $headings-font-family:    inherit
+// $headings-font-weight:    500
+// $headings-line-height:    1.1
+// $headings-color:          inherit
+
+
+//== Iconography
+//
+//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
+
+//** Load fonts from this directory.
+
+// [converter] If $bootstrap-sass-asset-helper if used, provide path relative to the assets load path.
+// [converter] This is because some asset helpers, such as Sprockets, do not work with file-relative paths.
+// $icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/")
+
+//** File name for all font files.
+// $icon-font-name:          "glyphicons-halflings-regular"
+//** Element ID within SVG icon file.
+// $icon-font-svg-id:        "glyphicons_halflingsregular"
+
+
+//== Components
+//
+//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
+
+// $padding-base-vertical:     6px
+// $padding-base-horizontal:   12px
+
+// $padding-large-vertical:    10px
+// $padding-large-horizontal:  16px
+
+// $padding-small-vertical:    5px
+// $padding-small-horizontal:  10px
+
+// $padding-xs-vertical:       1px
+// $padding-xs-horizontal:     5px
+
+// $line-height-large:         1.3333333 // extra decimals for Win 8.1 Chrome
+// $line-height-small:         1.5
+
+// $border-radius-base:        4px
+// $border-radius-large:       6px
+// $border-radius-small:       3px
+
+//** Global color for active items (e.g., navs or dropdowns).
+// $component-active-color:    #fff
+//** Global background color for active items (e.g., navs or dropdowns).
+// $component-active-bg:       $brand-primary
+
+//** Width of the `border` for generating carets that indicator dropdowns.
+// $caret-width-base:          4px
+//** Carets increase slightly in size for larger components.
+// $caret-width-large:         5px
+
+
+//== Tables
+//
+//## Customizes the `.table` component with basic values, each used across all table variations.
+
+//** Padding for ``s and ``s.
+// $table-cell-padding:            8px
+//** Padding for cells in `.table-condensed`.
+// $table-condensed-cell-padding:  5px
+
+//** Default background color used for all tables.
+// $table-bg:                      transparent
+//** Background color used for `.table-striped`.
+// $table-bg-accent:               #f9f9f9
+//** Background color used for `.table-hover`.
+// $table-bg-hover:                #f5f5f5
+// $table-bg-active:               $table-bg-hover
+
+//** Border color for table and cell borders.
+// $table-border-color:            #ddd
+
+
+//== Buttons
+//
+//## For each of Bootstrap's buttons, define text, background and border color.
+
+// $btn-font-weight:                normal
+
+// $btn-default-color:              #333
+// $btn-default-bg:                 #fff
+// $btn-default-border:             #ccc
+
+// $btn-primary-color:              #fff
+// $btn-primary-bg:                 $brand-primary
+// $btn-primary-border:             darken($btn-primary-bg, 5%)
+
+// $btn-success-color:              #fff
+// $btn-success-bg:                 $brand-success
+// $btn-success-border:             darken($btn-success-bg, 5%)
+
+// $btn-info-color:                 #fff
+// $btn-info-bg:                    $brand-info
+// $btn-info-border:                darken($btn-info-bg, 5%)
+
+// $btn-warning-color:              #fff
+// $btn-warning-bg:                 $brand-warning
+// $btn-warning-border:             darken($btn-warning-bg, 5%)
+
+// $btn-danger-color:               #fff
+// $btn-danger-bg:                  $brand-danger
+// $btn-danger-border:              darken($btn-danger-bg, 5%)
+
+// $btn-link-disabled-color:        $gray-light
+
+
+//== Forms
+//
+//##
+
+//** `` background color
+// $input-bg:                       #fff
+//** `` background color
+// $input-bg-disabled:              $gray-lighter
+
+//** Text color for ``s
+// $input-color:                    $gray
+//** `` border color
+// $input-border:                   #ccc
+
+// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
+//** Default `.form-control` border radius
+// This has no effect on ``s in CSS.
+// $input-border-radius:            $border-radius-base
+//** Large `.form-control` border radius
+// $input-border-radius-large:      $border-radius-large
+//** Small `.form-control` border radius
+// $input-border-radius-small:      $border-radius-small
+
+//** Border color for inputs on focus
+// $input-border-focus:             #66afe9
+
+//** Placeholder text color
+// $input-color-placeholder:        #999
+
+//** Default `.form-control` height
+// $input-height-base:              ($line-height-computed + ($padding-base-vertical * 2) + 2)
+//** Large `.form-control` height
+// $input-height-large:             (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2)
+//** Small `.form-control` height
+// $input-height-small:             (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2)
+
+// $legend-color:                   $gray-dark
+// $legend-border-color:            #e5e5e5
+
+//** Background color for textual input addons
+// $input-group-addon-bg:           $gray-lighter
+//** Border color for textual input addons
+// $input-group-addon-border-color: $input-border
+
+//** Disabled cursor for form controls and buttons.
+// $cursor-disabled:                not-allowed
+
+
+//== Dropdowns
+//
+//## Dropdown menu container and contents.
+
+//** Background for the dropdown menu.
+// $dropdown-bg:                    #fff
+//** Dropdown menu `border-color`.
+// $dropdown-border:                rgba(0,0,0,.15)
+//** Dropdown menu `border-color` **for IE8**.
+// $dropdown-fallback-border:       #ccc
+//** Divider color for between dropdown items.
+// $dropdown-divider-bg:            #e5e5e5
+
+//** Dropdown link text color.
+// $dropdown-link-color:            $gray-dark
+//** Hover color for dropdown links.
+// $dropdown-link-hover-color:      darken($gray-dark, 5%)
+//** Hover background for dropdown links.
+// $dropdown-link-hover-bg:         #f5f5f5
+
+//** Active dropdown menu item text color.
+// $dropdown-link-active-color:     $component-active-color
+//** Active dropdown menu item background color.
+// $dropdown-link-active-bg:        $component-active-bg
+
+//** Disabled dropdown menu item background color.
+// $dropdown-link-disabled-color:   $gray-light
+
+//** Text color for headers within dropdown menus.
+// $dropdown-header-color:          $gray-light
+
+//** Deprecated `$dropdown-caret-color` as of v3.1.0
+// $dropdown-caret-color:           #000
+
+
+//-- Z-index master list
+//
+// Warning: Avoid customizing these values. They're used for a bird's eye view
+// of components dependent on the z-axis and are designed to all work together.
+//
+// Note: These variables are not generated into the Customizer.
+
+// $zindex-navbar:            1000
+// $zindex-dropdown:          1000
+// $zindex-popover:           1060
+// $zindex-tooltip:           1070
+// $zindex-navbar-fixed:      1030
+// $zindex-modal:             1040
+
+
+//== Media queries breakpoints
+//
+//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
+
+// Extra small screen / phone
+//** Deprecated `$screen-xs` as of v3.0.1
+// $screen-xs:                  480px
+//** Deprecated `$screen-xs-min` as of v3.2.0
+// $screen-xs-min:              $screen-xs
+//** Deprecated `$screen-phone` as of v3.0.1
+// $screen-phone:               $screen-xs-min
+
+// Small screen / tablet
+//** Deprecated `$screen-sm` as of v3.0.1
+// $screen-sm:                  768px
+// $screen-sm-min:              $screen-sm
+//** Deprecated `$screen-tablet` as of v3.0.1
+// $screen-tablet:              $screen-sm-min
+
+// Medium screen / desktop
+//** Deprecated `$screen-md` as of v3.0.1
+// $screen-md:                  992px
+// $screen-md-min:              $screen-md
+//** Deprecated `$screen-desktop` as of v3.0.1
+// $screen-desktop:             $screen-md-min
+
+// Large screen / wide desktop
+//** Deprecated `$screen-lg` as of v3.0.1
+// $screen-lg:                  1200px
+// $screen-lg-min:              $screen-lg
+//** Deprecated `$screen-lg-desktop` as of v3.0.1
+// $screen-lg-desktop:          $screen-lg-min
+
+// So media queries don't overlap when required, provide a maximum
+// $screen-xs-max:              ($screen-sm-min - 1)
+// $screen-sm-max:              ($screen-md-min - 1)
+// $screen-md-max:              ($screen-lg-min - 1)
+
+
+//== Grid system
+//
+//## Define your custom responsive grid.
+
+//** Number of columns in the grid.
+// $grid-columns:              12
+//** Padding between columns. Gets divided in half for the left and right.
+// $grid-gutter-width:         30px
+// Navbar collapse
+//** Point at which the navbar becomes uncollapsed.
+// $grid-float-breakpoint:     $screen-sm-min
+//** Point at which the navbar begins collapsing.
+// $grid-float-breakpoint-max: ($grid-float-breakpoint - 1)
+
+
+//== Container sizes
+//
+//## Define the maximum width of `.container` for different screen sizes.
+
+// Small screen / tablet
+// $container-tablet:             (720px + $grid-gutter-width)
+//** For `$screen-sm-min` and up.
+// $container-sm:                 $container-tablet
+
+// Medium screen / desktop
+// $container-desktop:            (940px + $grid-gutter-width)
+//** For `$screen-md-min` and up.
+// $container-md:                 $container-desktop
+
+// Large screen / wide desktop
+// $container-large-desktop:      (1140px + $grid-gutter-width)
+//** For `$screen-lg-min` and up.
+// $container-lg:                 $container-large-desktop
+
+
+//== Navbar
+//
+//##
+
+// Basics of a navbar
+// $navbar-height:                    50px
+// $navbar-margin-bottom:             $line-height-computed
+// $navbar-border-radius:             $border-radius-base
+// $navbar-padding-horizontal:        floor(($grid-gutter-width / 2))
+// $navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2)
+// $navbar-collapse-max-height:       340px
+
+// $navbar-default-color:             #777
+// $navbar-default-bg:                #f8f8f8
+// $navbar-default-border:            darken($navbar-default-bg, 6.5%)
+
+// Navbar links
+// $navbar-default-link-color:                #777
+// $navbar-default-link-hover-color:          #333
+// $navbar-default-link-hover-bg:             transparent
+// $navbar-default-link-active-color:         #555
+// $navbar-default-link-active-bg:            darken($navbar-default-bg, 6.5%)
+// $navbar-default-link-disabled-color:       #ccc
+// $navbar-default-link-disabled-bg:          transparent
+
+// Navbar brand label
+// $navbar-default-brand-color:               $navbar-default-link-color
+// $navbar-default-brand-hover-color:         darken($navbar-default-brand-color, 10%)
+// $navbar-default-brand-hover-bg:            transparent
+
+// Navbar toggle
+// $navbar-default-toggle-hover-bg:           #ddd
+// $navbar-default-toggle-icon-bar-bg:        #888
+// $navbar-default-toggle-border-color:       #ddd
+
+
+// Inverted navbar
+// Reset inverted navbar basics
+// $navbar-inverse-color:                      lighten($gray-light, 15%)
+// $navbar-inverse-bg:                         #222
+// $navbar-inverse-border:                     darken($navbar-inverse-bg, 10%)
+
+// Inverted navbar links
+// $navbar-inverse-link-color:                 lighten($gray-light, 15%)
+// $navbar-inverse-link-hover-color:           #fff
+// $navbar-inverse-link-hover-bg:              transparent
+// $navbar-inverse-link-active-color:          $navbar-inverse-link-hover-color
+// $navbar-inverse-link-active-bg:             darken($navbar-inverse-bg, 10%)
+// $navbar-inverse-link-disabled-color:        #444
+// $navbar-inverse-link-disabled-bg:           transparent
+
+// Inverted navbar brand label
+// $navbar-inverse-brand-color:                $navbar-inverse-link-color
+// $navbar-inverse-brand-hover-color:          #fff
+// $navbar-inverse-brand-hover-bg:             transparent
+
+// Inverted navbar toggle
+// $navbar-inverse-toggle-hover-bg:            #333
+// $navbar-inverse-toggle-icon-bar-bg:         #fff
+// $navbar-inverse-toggle-border-color:        #333
+
+
+//== Navs
+//
+//##
+
+//=== Shared nav styles
+// $nav-link-padding:                          10px 15px
+// $nav-link-hover-bg:                         $gray-lighter
+
+// $nav-disabled-link-color:                   $gray-light
+// $nav-disabled-link-hover-color:             $gray-light
+
+//== Tabs
+// $nav-tabs-border-color:                     #ddd
+
+// $nav-tabs-link-hover-border-color:          $gray-lighter
+
+// $nav-tabs-active-link-hover-bg:             $body-bg
+// $nav-tabs-active-link-hover-color:          $gray
+// $nav-tabs-active-link-hover-border-color:   #ddd
+
+// $nav-tabs-justified-link-border-color:            #ddd
+// $nav-tabs-justified-active-link-border-color:     $body-bg
+
+//== Pills
+// $nav-pills-border-radius:                   $border-radius-base
+// $nav-pills-active-link-hover-bg:            $component-active-bg
+// $nav-pills-active-link-hover-color:         $component-active-color
+
+
+//== Pagination
+//
+//##
+
+// $pagination-color:                     $link-color
+// $pagination-bg:                        #fff
+// $pagination-border:                    #ddd
+
+// $pagination-hover-color:               $link-hover-color
+// $pagination-hover-bg:                  $gray-lighter
+// $pagination-hover-border:              #ddd
+
+// $pagination-active-color:              #fff
+// $pagination-active-bg:                 $brand-primary
+// $pagination-active-border:             $brand-primary
+
+// $pagination-disabled-color:            $gray-light
+// $pagination-disabled-bg:               #fff
+// $pagination-disabled-border:           #ddd
+
+
+//== Pager
+//
+//##
+
+// $pager-bg:                             $pagination-bg
+// $pager-border:                         $pagination-border
+// $pager-border-radius:                  15px
+
+// $pager-hover-bg:                       $pagination-hover-bg
+
+// $pager-active-bg:                      $pagination-active-bg
+// $pager-active-color:                   $pagination-active-color
+
+// $pager-disabled-color:                 $pagination-disabled-color
+
+
+//== Jumbotron
+//
+//##
+
+// $jumbotron-padding:              30px
+// $jumbotron-color:                inherit
+// $jumbotron-bg:                   $gray-lighter
+// $jumbotron-heading-color:        inherit
+// $jumbotron-font-size:            ceil(($font-size-base * 1.5))
+
+
+//== Form states and alerts
+//
+//## Define colors for form feedback states and, by default, alerts.
+
+// $state-success-text:             #3c763d
+// $state-success-bg:               #dff0d8
+// $state-success-border:           darken(adjust-hue($state-success-bg, -10), 5%)
+
+// $state-info-text:                #31708f
+// $state-info-bg:                  #d9edf7
+// $state-info-border:              darken(adjust-hue($state-info-bg, -10), 7%)
+
+// $state-warning-text:             #8a6d3b
+// $state-warning-bg:               #fcf8e3
+// $state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 5%)
+
+// $state-danger-text:              #a94442
+// $state-danger-bg:                #f2dede
+// $state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 5%)
+
+
+//== Tooltips
+//
+//##
+
+//** Tooltip max width
+// $tooltip-max-width:           200px
+//** Tooltip text color
+// $tooltip-color:               #fff
+//** Tooltip background color
+// $tooltip-bg:                  #000
+// $tooltip-opacity:             .9
+
+//** Tooltip arrow width
+// $tooltip-arrow-width:         5px
+//** Tooltip arrow color
+// $tooltip-arrow-color:         $tooltip-bg
+
+
+//== Popovers
+//
+//##
+
+//** Popover body background color
+// $popover-bg:                          #fff
+//** Popover maximum width
+// $popover-max-width:                   276px
+//** Popover border color
+// $popover-border-color:                rgba(0,0,0,.2)
+//** Popover fallback border color
+// $popover-fallback-border-color:       #ccc
+
+//** Popover title background color
+// $popover-title-bg:                    darken($popover-bg, 3%)
+
+//** Popover arrow width
+// $popover-arrow-width:                 10px
+//** Popover arrow color
+// $popover-arrow-color:                 $popover-bg
+
+//** Popover outer arrow width
+// $popover-arrow-outer-width:           ($popover-arrow-width + 1)
+//** Popover outer arrow color
+// $popover-arrow-outer-color:           fade_in($popover-border-color, 0.05)
+//** Popover outer arrow fallback color
+// $popover-arrow-outer-fallback-color:  darken($popover-fallback-border-color, 20%)
+
+
+//== Labels
+//
+//##
+
+//** Default label background color
+// $label-default-bg:            $gray-light
+//** Primary label background color
+// $label-primary-bg:            $brand-primary
+//** Success label background color
+// $label-success-bg:            $brand-success
+//** Info label background color
+// $label-info-bg:               $brand-info
+//** Warning label background color
+// $label-warning-bg:            $brand-warning
+//** Danger label background color
+// $label-danger-bg:             $brand-danger
+
+//** Default label text color
+// $label-color:                 #fff
+//** Default text color of a linked label
+// $label-link-hover-color:      #fff
+
+
+//== Modals
+//
+//##
+
+//** Padding applied to the modal body
+// $modal-inner-padding:         15px
+
+//** Padding applied to the modal title
+// $modal-title-padding:         15px
+//** Modal title line-height
+// $modal-title-line-height:     $line-height-base
+
+//** Background color of modal content area
+// $modal-content-bg:                             #fff
+//** Modal content border color
+// $modal-content-border-color:                   rgba(0,0,0,.2)
+//** Modal content border color **for IE8**
+// $modal-content-fallback-border-color:          #999
+
+//** Modal backdrop background color
+// $modal-backdrop-bg:           #000
+//** Modal backdrop opacity
+// $modal-backdrop-opacity:      .5
+//** Modal header border color
+// $modal-header-border-color:   #e5e5e5
+//** Modal footer border color
+// $modal-footer-border-color:   $modal-header-border-color
+
+// $modal-lg:                    900px
+// $modal-md:                    600px
+// $modal-sm:                    300px
+
+
+//== Alerts
+//
+//## Define alert colors, border radius, and padding.
+
+// $alert-padding:               15px
+// $alert-border-radius:         $border-radius-base
+// $alert-link-font-weight:      bold
+
+// $alert-success-bg:            $state-success-bg
+// $alert-success-text:          $state-success-text
+// $alert-success-border:        $state-success-border
+
+// $alert-info-bg:               $state-info-bg
+// $alert-info-text:             $state-info-text
+// $alert-info-border:           $state-info-border
+
+// $alert-warning-bg:            $state-warning-bg
+// $alert-warning-text:          $state-warning-text
+// $alert-warning-border:        $state-warning-border
+
+// $alert-danger-bg:             $state-danger-bg
+// $alert-danger-text:           $state-danger-text
+// $alert-danger-border:         $state-danger-border
+
+
+//== Progress bars
+//
+//##
+
+//** Background color of the whole progress component
+// $progress-bg:                 #f5f5f5
+//** Progress bar text color
+// $progress-bar-color:          #fff
+//** Variable for setting rounded corners on progress bar.
+// $progress-border-radius:      $border-radius-base
+
+//** Default progress bar color
+// $progress-bar-bg:             $brand-primary
+//** Success progress bar color
+// $progress-bar-success-bg:     $brand-success
+//** Warning progress bar color
+// $progress-bar-warning-bg:     $brand-warning
+//** Danger progress bar color
+// $progress-bar-danger-bg:      $brand-danger
+//** Info progress bar color
+// $progress-bar-info-bg:        $brand-info
+
+
+//== List group
+//
+//##
+
+//** Background color on `.list-group-item`
+// $list-group-bg:                 #fff
+//** `.list-group-item` border color
+// $list-group-border:             #ddd
+//** List group border radius
+// $list-group-border-radius:      $border-radius-base
+
+//** Background color of single list items on hover
+// $list-group-hover-bg:           #f5f5f5
+//** Text color of active list items
+// $list-group-active-color:       $component-active-color
+//** Background color of active list items
+// $list-group-active-bg:          $component-active-bg
+//** Border color of active list elements
+// $list-group-active-border:      $list-group-active-bg
+//** Text color for content within active list items
+// $list-group-active-text-color:  lighten($list-group-active-bg, 40%)
+
+//** Text color of disabled list items
+// $list-group-disabled-color:      $gray-light
+//** Background color of disabled list items
+// $list-group-disabled-bg:         $gray-lighter
+//** Text color for content within disabled list items
+// $list-group-disabled-text-color: $list-group-disabled-color
+
+// $list-group-link-color:         #555
+// $list-group-link-hover-color:   $list-group-link-color
+// $list-group-link-heading-color: #333
+
+
+//== Panels
+//
+//##
+
+// $panel-bg:                    #fff
+// $panel-body-padding:          15px
+// $panel-heading-padding:       10px 15px
+// $panel-footer-padding:        $panel-heading-padding
+// $panel-border-radius:         $border-radius-base
+
+//** Border color for elements within panels
+// $panel-inner-border:          #ddd
+// $panel-footer-bg:             #f5f5f5
+
+// $panel-default-text:          $gray-dark
+// $panel-default-border:        #ddd
+// $panel-default-heading-bg:    #f5f5f5
+
+// $panel-primary-text:          #fff
+// $panel-primary-border:        $brand-primary
+// $panel-primary-heading-bg:    $brand-primary
+
+// $panel-success-text:          $state-success-text
+// $panel-success-border:        $state-success-border
+// $panel-success-heading-bg:    $state-success-bg
+
+// $panel-info-text:             $state-info-text
+// $panel-info-border:           $state-info-border
+// $panel-info-heading-bg:       $state-info-bg
+
+// $panel-warning-text:          $state-warning-text
+// $panel-warning-border:        $state-warning-border
+// $panel-warning-heading-bg:    $state-warning-bg
+
+// $panel-danger-text:           $state-danger-text
+// $panel-danger-border:         $state-danger-border
+// $panel-danger-heading-bg:     $state-danger-bg
+
+
+//== Thumbnails
+//
+//##
+
+//** Padding around the thumbnail image
+// $thumbnail-padding:           4px
+//** Thumbnail background color
+// $thumbnail-bg:                $body-bg
+//** Thumbnail border color
+// $thumbnail-border:            #ddd
+//** Thumbnail border radius
+// $thumbnail-border-radius:     $border-radius-base
+
+//** Custom text color for thumbnail captions
+// $thumbnail-caption-color:     $text-color
+//** Padding around the thumbnail caption
+// $thumbnail-caption-padding:   9px
+
+
+//== Wells
+//
+//##
+
+// $well-bg:                     #f5f5f5
+// $well-border:                 darken($well-bg, 7%)
+
+
+//== Badges
+//
+//##
+
+// $badge-color:                 #fff
+//** Linked badge text color on hover
+// $badge-link-hover-color:      #fff
+// $badge-bg:                    $gray-light
+
+//** Badge text color in active nav link
+// $badge-active-color:          $link-color
+//** Badge background color in active nav link
+// $badge-active-bg:             #fff
+
+// $badge-font-weight:           bold
+// $badge-line-height:           1
+// $badge-border-radius:         10px
+
+
+//== Breadcrumbs
+//
+//##
+
+// $breadcrumb-padding-vertical:   8px
+// $breadcrumb-padding-horizontal: 15px
+//** Breadcrumb background color
+// $breadcrumb-bg:                 #f5f5f5
+//** Breadcrumb text color
+// $breadcrumb-color:              #ccc
+//** Text color of current page in the breadcrumb
+// $breadcrumb-active-color:       $gray-light
+//** Textual separator for between breadcrumb elements
+// $breadcrumb-separator:          "/"
+
+
+//== Carousel
+//
+//##
+
+// $carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6)
+
+// $carousel-control-color:                      #fff
+// $carousel-control-width:                      15%
+// $carousel-control-opacity:                    .5
+// $carousel-control-font-size:                  20px
+
+// $carousel-indicator-active-bg:                #fff
+// $carousel-indicator-border-color:             #fff
+
+// $carousel-caption-color:                      #fff
+
+
+//== Close
+//
+//##
+
+// $close-font-weight:           bold
+// $close-color:                 #000
+// $close-text-shadow:           0 1px 0 #fff
+
+
+//== Code
+//
+//##
+
+// $code-color:                  #c7254e
+// $code-bg:                     #f9f2f4
+
+// $kbd-color:                   #fff
+// $kbd-bg:                      #333
+
+// $pre-bg:                      #f5f5f5
+// $pre-color:                   $gray-dark
+// $pre-border-color:            #ccc
+// $pre-scrollable-max-height:   340px
+
+
+//== Type
+//
+//##
+
+//** Horizontal offset for forms and lists.
+// $component-offset-horizontal: 180px
+//** Text muted color
+// $text-muted:                  $gray-light
+//** Abbreviations and acronyms border color
+// $abbr-border-color:           $gray-light
+//** Headings small color
+// $headings-small-color:        $gray-light
+//** Blockquote small color
+// $blockquote-small-color:      $gray-light
+//** Blockquote font size
+// $blockquote-font-size:        ($font-size-base * 1.25)
+//** Blockquote border color
+// $blockquote-border-color:     $gray-lighter
+//** Page header border color
+// $page-header-border-color:    $gray-lighter
+//** Width of horizontal description list titles
+// $dl-horizontal-offset:        $component-offset-horizontal
+//** Horizontal line color.
+// $hr-border:                   $gray-lighter
diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/main/mixins.scss
index e54482d14c..80cb0c1565 100644
--- a/app/assets/stylesheets/main/mixins.scss
+++ b/app/assets/stylesheets/main/mixins.scss
@@ -121,14 +121,6 @@
   }
 }
 
-@mixin page-title {
-  color: #333;
-  line-height: 1.5;
-  font-weight: normal;
-  margin-top: 0px;
-  margin-bottom: 10px;
-}
-
 @mixin str-truncated($max_width: 82%) {
   display: inline-block;
   overflow: hidden;
diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss
index 57b881c073..6be81b2335 100644
--- a/app/assets/stylesheets/main/variables.scss
+++ b/app/assets/stylesheets/main/variables.scss
@@ -1,17 +1,14 @@
-/*
- * General Colors
- */
 $style_color: #474D57;
 $hover: #FFF3EB;
 $box_bg: #F9F9F9;
-
-/*
- * Link colors
- */
-$link_color: #446e9b;
-$link_hover_color: darken($link-color, 10%);
-
-$btn-border: 1px solid #ccc;
+$gl-link-color: #446e9b;
+$nprogress-color: #c0392b;
+$gl-font-size: 13px;
+$list-font-size: 15px;
+$sidebar_width: 230px;
+$avatar_radius: 50%;
+$code_font_size: 13px;
+$code_line_height: 1.5;
 
 /*
  * State colors:
@@ -27,22 +24,3 @@ $gl-warning: #EB9532;
  */
 $added: #63c363;
 $deleted: #f77;
-
-/**
- * NProgress customize
- */
-$nprogress-color: #c0392b;
-
-/**
- * Font sizes
- */
-$list-font-size: 15px;
-
-/**
- * Sidebar navigation width
- */
-$sidebar_width: 230px;
-
-$avatar_radius: 50%;
-$code_font_size: 13px;
-$code_line_height: 1.5;
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss
index e476b9ac77..73f23626d5 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/sections/notes.scss
@@ -40,7 +40,7 @@ ul.notes {
       font-weight: bold;
       font-size: 14px;
       &:hover {
-        color: $link_color;
+        color: $gl-link-color;
       }
     }
     .author-username {
@@ -70,7 +70,7 @@ ul.notes {
         a[href*="/uploads/"] {
           &:before {
             margin-right: 4px;
-            
+
             font: normal normal normal 14px/1 FontAwesome;
             font-size: inherit;
             text-rendering: auto;
@@ -153,7 +153,6 @@ ul.notes {
       @extend .cgray;
 
       &:hover {
-        color: $link_hover_color;
         &.danger { @extend .cred; }
       }
     }
@@ -181,7 +180,7 @@ ul.notes {
     background: #FFF;
     padding: 4px;
     font-size: 16px;
-    color: $link_color;
+    color: $gl-link-color;
     margin-left: -60px;
     position: absolute;
     z-index: 10;
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss
index 586698fdd9..3a912d234f 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/sections/projects.scss
@@ -108,7 +108,7 @@
 
   .btn {
     background: none;
-    color: $link_color;
+    color: $gl-link-color;
 
     &.active {
       background-color: #f5f5f5;
diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss
index 9f91c27f90..3305abc7d2 100644
--- a/app/assets/stylesheets/sections/tree.scss
+++ b/app/assets/stylesheets/sections/tree.scss
@@ -39,11 +39,6 @@
     .tree-item-file-name {
       max-width: 320px;
       vertical-align: middle;
-      a {
-        &:hover {
-          color: $link_hover_color;
-        }
-      }
 
       i {
         color: $gl-primary;

From ceb8f9dfeb77c99dfac121fb349ee3c8a9969ae9 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Fri, 6 Mar 2015 21:15:15 -0800
Subject: [PATCH 073/143] Remove custom css for panels and navs

---
 app/assets/stylesheets/gl_bootstrap.scss      | 54 -------------------
 app/assets/stylesheets/gl_variables.scss      |  4 +-
 app/assets/stylesheets/main/mixins.scss       | 11 ----
 .../stylesheets/sections/dashboard.scss       |  7 +--
 4 files changed, 4 insertions(+), 72 deletions(-)

diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/gl_bootstrap.scss
index 18a6be409d..e8e58511f3 100644
--- a/app/assets/stylesheets/gl_bootstrap.scss
+++ b/app/assets/stylesheets/gl_bootstrap.scss
@@ -131,10 +131,6 @@
       }
     }
   }
-
-  &.nav-small-tabs > li > a {
-    padding: 6px 9px;
-  }
 }
 
 .nav-tabs > li > a,
@@ -142,15 +138,6 @@
   color: #666;
 }
 
-.nav-compact > li > a {
-  padding: 6px 12px;
-}
-
-.nav-small > li > a {
-  padding: 3px 5px;
-  font-size: 12px;
-}
-
 /**
  * fix to keep tooltips position in top navigation bar
  *
@@ -165,10 +152,7 @@
  *
  */
 .panel {
-  @include border-radius(0px);
-
   .panel-heading {
-    @include border-radius(0px);
     font-size: 14px;
     line-height: 18px;
 
@@ -206,41 +190,3 @@
     }
   }
 }
-
-.panel-default {
-  .panel-heading {
-    background-color: #EEE;
-  }
-}
-
-.panel-danger {
-  @include panel-colored;
-  .panel-heading {
-    color: $gl-danger;
-    border-color: $gl-danger;
-  }
-}
-
-.panel-success {
-  @include panel-colored;
-  .panel-heading {
-    color: $gl-success;
-    border-color: $gl-success;
-  }
-}
-
-.panel-primary {
-  @include panel-colored;
-  .panel-heading {
-    color: $gl-primary;
-    border-color: $gl-primary;
-  }
-}
-
-.panel-warning {
-  @include panel-colored;
-  .panel-heading {
-    color: $gl-warning;
-    border-color: $gl-warning;
-  }
-}
diff --git a/app/assets/stylesheets/gl_variables.scss b/app/assets/stylesheets/gl_variables.scss
index d40ab1b916..4f54551a22 100644
--- a/app/assets/stylesheets/gl_variables.scss
+++ b/app/assets/stylesheets/gl_variables.scss
@@ -617,7 +617,7 @@ $font-size-base:          $gl-font-size;
 //## Define alert colors, border radius, and padding.
 
 // $alert-padding:               15px
-// $alert-border-radius:         $border-radius-base
+$alert-border-radius:            0;
 // $alert-link-font-weight:      bold
 
 // $alert-success-bg:            $state-success-bg
@@ -702,7 +702,7 @@ $font-size-base:          $gl-font-size;
 // $panel-body-padding:          15px
 // $panel-heading-padding:       10px 15px
 // $panel-footer-padding:        $panel-heading-padding
-// $panel-border-radius:         $border-radius-base
+$panel-border-radius:            0;
 
 //** Border color for elements within panels
 // $panel-inner-border:          #ddd
diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/main/mixins.scss
index 80cb0c1565..ccba65e3fd 100644
--- a/app/assets/stylesheets/main/mixins.scss
+++ b/app/assets/stylesheets/main/mixins.scss
@@ -129,14 +129,3 @@
   white-space: nowrap;
   max-width: $max_width;
 }
-
-@mixin panel-colored {
-  border: 1px solid #EEE;
-  background: $box_bg;
-  @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
-
-  .panel-heading {
-    font-weight: bold;
-    background-color: $box_bg;
-  }
-}
diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/sections/dashboard.scss
index c8e3c7d4a2..96f84b7122 100644
--- a/app/assets/stylesheets/sections/dashboard.scss
+++ b/app/assets/stylesheets/sections/dashboard.scss
@@ -31,11 +31,8 @@
   li {
     &.active {
       a {
-        background-color: #EEE;
-        border-bottom: 1px solid #EEE !important;
-        &:hover {
-          background: #eee;
-        }
+        background-color: whitesmoke !important;
+        border-bottom: 1px solid whitesmoke !important;
       }
     }
 

From 887cf5c7101c058d30b10d767c186d548e6c5e92 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Fri, 6 Mar 2015 21:40:23 -0800
Subject: [PATCH 074/143] Better name for pages css dir

---
 .../stylesheets/{sections => generic}/nav_sidebar.scss    | 0
 app/assets/stylesheets/main/fonts.scss                    | 3 ---
 app/assets/stylesheets/main/variables.scss                | 8 +++++++-
 app/assets/stylesheets/{sections => pages}/admin.scss     | 0
 app/assets/stylesheets/{sections => pages}/commit.scss    | 0
 app/assets/stylesheets/{sections => pages}/commits.scss   | 0
 app/assets/stylesheets/{sections => pages}/dashboard.scss | 0
 app/assets/stylesheets/{sections => pages}/diff.scss      | 0
 app/assets/stylesheets/{sections => pages}/editor.scss    | 0
 app/assets/stylesheets/{sections => pages}/errors.scss    | 0
 app/assets/stylesheets/{sections => pages}/events.scss    | 0
 app/assets/stylesheets/{sections => pages}/explore.scss   | 0
 app/assets/stylesheets/{sections => pages}/graph.scss     | 0
 app/assets/stylesheets/{sections => pages}/groups.scss    | 0
 app/assets/stylesheets/{sections => pages}/header.scss    | 0
 app/assets/stylesheets/{sections => pages}/help.scss      | 0
 app/assets/stylesheets/{sections => pages}/import.scss    | 0
 app/assets/stylesheets/{sections => pages}/issuable.scss  | 0
 app/assets/stylesheets/{sections => pages}/issues.scss    | 0
 app/assets/stylesheets/{sections => pages}/labels.scss    | 0
 app/assets/stylesheets/{sections => pages}/login.scss     | 0
 .../stylesheets/{sections => pages}/markdown_area.scss    | 0
 .../stylesheets/{sections => pages}/merge_requests.scss   | 0
 app/assets/stylesheets/{sections => pages}/milestone.scss | 0
 app/assets/stylesheets/{sections => pages}/note_form.scss | 0
 app/assets/stylesheets/{sections => pages}/notes.scss     | 0
 .../stylesheets/{sections => pages}/notifications.scss    | 0
 app/assets/stylesheets/{sections => pages}/profile.scss   | 0
 app/assets/stylesheets/{sections => pages}/projects.scss  | 0
 app/assets/stylesheets/{sections => pages}/search.scss    | 0
 app/assets/stylesheets/{sections => pages}/snippets.scss  | 0
 .../stylesheets/{sections => pages}/stat_graph.scss       | 0
 app/assets/stylesheets/{sections => pages}/themes.scss    | 0
 app/assets/stylesheets/{sections => pages}/tree.scss      | 0
 app/assets/stylesheets/{sections => pages}/votes.scss     | 0
 app/assets/stylesheets/{sections => pages}/wiki.scss      | 0
 36 files changed, 7 insertions(+), 4 deletions(-)
 rename app/assets/stylesheets/{sections => generic}/nav_sidebar.scss (100%)
 delete mode 100644 app/assets/stylesheets/main/fonts.scss
 rename app/assets/stylesheets/{sections => pages}/admin.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/commit.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/commits.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/dashboard.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/diff.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/editor.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/errors.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/events.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/explore.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/graph.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/groups.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/header.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/help.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/import.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/issuable.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/issues.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/labels.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/login.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/markdown_area.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/merge_requests.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/milestone.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/note_form.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/notes.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/notifications.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/profile.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/projects.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/search.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/snippets.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/stat_graph.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/themes.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/tree.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/votes.scss (100%)
 rename app/assets/stylesheets/{sections => pages}/wiki.scss (100%)

diff --git a/app/assets/stylesheets/sections/nav_sidebar.scss b/app/assets/stylesheets/generic/nav_sidebar.scss
similarity index 100%
rename from app/assets/stylesheets/sections/nav_sidebar.scss
rename to app/assets/stylesheets/generic/nav_sidebar.scss
diff --git a/app/assets/stylesheets/main/fonts.scss b/app/assets/stylesheets/main/fonts.scss
deleted file mode 100644
index f945aaca84..0000000000
--- a/app/assets/stylesheets/main/fonts.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-/** Typo **/
-$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
-$regular_font: "Helvetica Neue", Helvetica, Arial, sans-serif;
diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss
index 6be81b2335..d751678f1b 100644
--- a/app/assets/stylesheets/main/variables.scss
+++ b/app/assets/stylesheets/main/variables.scss
@@ -19,8 +19,14 @@ $gl-primary: #446e9b;
 $gl-info: #029ACF;
 $gl-warning: #EB9532;
 
-/**
+/*
  * Commit Diff Colors
  */
 $added: #63c363;
 $deleted: #f77;
+
+/*
+ * Fonts
+ */
+$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
+$regular_font: "Helvetica Neue", Helvetica, Arial, sans-serif;
diff --git a/app/assets/stylesheets/sections/admin.scss b/app/assets/stylesheets/pages/admin.scss
similarity index 100%
rename from app/assets/stylesheets/sections/admin.scss
rename to app/assets/stylesheets/pages/admin.scss
diff --git a/app/assets/stylesheets/sections/commit.scss b/app/assets/stylesheets/pages/commit.scss
similarity index 100%
rename from app/assets/stylesheets/sections/commit.scss
rename to app/assets/stylesheets/pages/commit.scss
diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/pages/commits.scss
similarity index 100%
rename from app/assets/stylesheets/sections/commits.scss
rename to app/assets/stylesheets/pages/commits.scss
diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/pages/dashboard.scss
similarity index 100%
rename from app/assets/stylesheets/sections/dashboard.scss
rename to app/assets/stylesheets/pages/dashboard.scss
diff --git a/app/assets/stylesheets/sections/diff.scss b/app/assets/stylesheets/pages/diff.scss
similarity index 100%
rename from app/assets/stylesheets/sections/diff.scss
rename to app/assets/stylesheets/pages/diff.scss
diff --git a/app/assets/stylesheets/sections/editor.scss b/app/assets/stylesheets/pages/editor.scss
similarity index 100%
rename from app/assets/stylesheets/sections/editor.scss
rename to app/assets/stylesheets/pages/editor.scss
diff --git a/app/assets/stylesheets/sections/errors.scss b/app/assets/stylesheets/pages/errors.scss
similarity index 100%
rename from app/assets/stylesheets/sections/errors.scss
rename to app/assets/stylesheets/pages/errors.scss
diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/pages/events.scss
similarity index 100%
rename from app/assets/stylesheets/sections/events.scss
rename to app/assets/stylesheets/pages/events.scss
diff --git a/app/assets/stylesheets/sections/explore.scss b/app/assets/stylesheets/pages/explore.scss
similarity index 100%
rename from app/assets/stylesheets/sections/explore.scss
rename to app/assets/stylesheets/pages/explore.scss
diff --git a/app/assets/stylesheets/sections/graph.scss b/app/assets/stylesheets/pages/graph.scss
similarity index 100%
rename from app/assets/stylesheets/sections/graph.scss
rename to app/assets/stylesheets/pages/graph.scss
diff --git a/app/assets/stylesheets/sections/groups.scss b/app/assets/stylesheets/pages/groups.scss
similarity index 100%
rename from app/assets/stylesheets/sections/groups.scss
rename to app/assets/stylesheets/pages/groups.scss
diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/pages/header.scss
similarity index 100%
rename from app/assets/stylesheets/sections/header.scss
rename to app/assets/stylesheets/pages/header.scss
diff --git a/app/assets/stylesheets/sections/help.scss b/app/assets/stylesheets/pages/help.scss
similarity index 100%
rename from app/assets/stylesheets/sections/help.scss
rename to app/assets/stylesheets/pages/help.scss
diff --git a/app/assets/stylesheets/sections/import.scss b/app/assets/stylesheets/pages/import.scss
similarity index 100%
rename from app/assets/stylesheets/sections/import.scss
rename to app/assets/stylesheets/pages/import.scss
diff --git a/app/assets/stylesheets/sections/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
similarity index 100%
rename from app/assets/stylesheets/sections/issuable.scss
rename to app/assets/stylesheets/pages/issuable.scss
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/pages/issues.scss
similarity index 100%
rename from app/assets/stylesheets/sections/issues.scss
rename to app/assets/stylesheets/pages/issues.scss
diff --git a/app/assets/stylesheets/sections/labels.scss b/app/assets/stylesheets/pages/labels.scss
similarity index 100%
rename from app/assets/stylesheets/sections/labels.scss
rename to app/assets/stylesheets/pages/labels.scss
diff --git a/app/assets/stylesheets/sections/login.scss b/app/assets/stylesheets/pages/login.scss
similarity index 100%
rename from app/assets/stylesheets/sections/login.scss
rename to app/assets/stylesheets/pages/login.scss
diff --git a/app/assets/stylesheets/sections/markdown_area.scss b/app/assets/stylesheets/pages/markdown_area.scss
similarity index 100%
rename from app/assets/stylesheets/sections/markdown_area.scss
rename to app/assets/stylesheets/pages/markdown_area.scss
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
similarity index 100%
rename from app/assets/stylesheets/sections/merge_requests.scss
rename to app/assets/stylesheets/pages/merge_requests.scss
diff --git a/app/assets/stylesheets/sections/milestone.scss b/app/assets/stylesheets/pages/milestone.scss
similarity index 100%
rename from app/assets/stylesheets/sections/milestone.scss
rename to app/assets/stylesheets/pages/milestone.scss
diff --git a/app/assets/stylesheets/sections/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
similarity index 100%
rename from app/assets/stylesheets/sections/note_form.scss
rename to app/assets/stylesheets/pages/note_form.scss
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/pages/notes.scss
similarity index 100%
rename from app/assets/stylesheets/sections/notes.scss
rename to app/assets/stylesheets/pages/notes.scss
diff --git a/app/assets/stylesheets/sections/notifications.scss b/app/assets/stylesheets/pages/notifications.scss
similarity index 100%
rename from app/assets/stylesheets/sections/notifications.scss
rename to app/assets/stylesheets/pages/notifications.scss
diff --git a/app/assets/stylesheets/sections/profile.scss b/app/assets/stylesheets/pages/profile.scss
similarity index 100%
rename from app/assets/stylesheets/sections/profile.scss
rename to app/assets/stylesheets/pages/profile.scss
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/pages/projects.scss
similarity index 100%
rename from app/assets/stylesheets/sections/projects.scss
rename to app/assets/stylesheets/pages/projects.scss
diff --git a/app/assets/stylesheets/sections/search.scss b/app/assets/stylesheets/pages/search.scss
similarity index 100%
rename from app/assets/stylesheets/sections/search.scss
rename to app/assets/stylesheets/pages/search.scss
diff --git a/app/assets/stylesheets/sections/snippets.scss b/app/assets/stylesheets/pages/snippets.scss
similarity index 100%
rename from app/assets/stylesheets/sections/snippets.scss
rename to app/assets/stylesheets/pages/snippets.scss
diff --git a/app/assets/stylesheets/sections/stat_graph.scss b/app/assets/stylesheets/pages/stat_graph.scss
similarity index 100%
rename from app/assets/stylesheets/sections/stat_graph.scss
rename to app/assets/stylesheets/pages/stat_graph.scss
diff --git a/app/assets/stylesheets/sections/themes.scss b/app/assets/stylesheets/pages/themes.scss
similarity index 100%
rename from app/assets/stylesheets/sections/themes.scss
rename to app/assets/stylesheets/pages/themes.scss
diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/pages/tree.scss
similarity index 100%
rename from app/assets/stylesheets/sections/tree.scss
rename to app/assets/stylesheets/pages/tree.scss
diff --git a/app/assets/stylesheets/sections/votes.scss b/app/assets/stylesheets/pages/votes.scss
similarity index 100%
rename from app/assets/stylesheets/sections/votes.scss
rename to app/assets/stylesheets/pages/votes.scss
diff --git a/app/assets/stylesheets/sections/wiki.scss b/app/assets/stylesheets/pages/wiki.scss
similarity index 100%
rename from app/assets/stylesheets/sections/wiki.scss
rename to app/assets/stylesheets/pages/wiki.scss

From 433b4c76fc7d23d03811fa05e1589e3a8a788e82 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sat, 7 Mar 2015 00:28:53 -0800
Subject: [PATCH 075/143] Apply some styles from flatly theme

---
 app/assets/stylesheets/application.scss    |  2 +-
 app/assets/stylesheets/gl_variables.scss   | 49 +++++++++++-----------
 app/assets/stylesheets/main/variables.scss |  5 +++
 app/assets/stylesheets/pages/projects.scss | 14 -------
 app/views/projects/new.html.haml           |  4 +-
 app/views/projects/show.html.haml          |  2 +-
 app/views/shared/_no_ssh.html.haml         |  6 +--
 7 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index e5bb5e21bb..2f9f09b4c6 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -39,7 +39,7 @@
  * Page specific styles (issues, projects etc):
  */
 
-@import "sections/*";
+@import "pages/*";
 
 /**
  * Code highlight
diff --git a/app/assets/stylesheets/gl_variables.scss b/app/assets/stylesheets/gl_variables.scss
index 4f54551a22..090eff7f29 100644
--- a/app/assets/stylesheets/gl_variables.scss
+++ b/app/assets/stylesheets/gl_variables.scss
@@ -444,21 +444,21 @@ $font-size-base:          $gl-font-size;
 //
 //##
 
-// $pagination-color:                     $link-color
-// $pagination-bg:                        #fff
-// $pagination-border:                    #ddd
+$pagination-color:                     #fff;
+$pagination-bg:                        $brand-success;
+$pagination-border:                    transparent;
 
-// $pagination-hover-color:               $link-hover-color
-// $pagination-hover-bg:                  $gray-lighter
-// $pagination-hover-border:              #ddd
+$pagination-hover-color:               #fff;
+$pagination-hover-bg:                  darken($brand-success, 15%);
+$pagination-hover-border:              transparent;
 
-// $pagination-active-color:              #fff
-// $pagination-active-bg:                 $brand-primary
-// $pagination-active-border:             $brand-primary
+$pagination-active-color:              #fff;
+$pagination-active-bg:                 darken($brand-success, 15%);
+$pagination-active-border:             transparent;
 
-// $pagination-disabled-color:            $gray-light
-// $pagination-disabled-bg:               #fff
-// $pagination-disabled-border:           #ddd
+$pagination-disabled-color:            #b4bcc2;
+$pagination-disabled-bg:               lighten($brand-success, 15%);
+$pagination-disabled-border:           transparent;
 
 
 //== Pager
@@ -492,21 +492,22 @@ $font-size-base:          $gl-font-size;
 //
 //## Define colors for form feedback states and, by default, alerts.
 
-// $state-success-text:             #3c763d
-// $state-success-bg:               #dff0d8
-// $state-success-border:           darken(adjust-hue($state-success-bg, -10), 5%)
 
-// $state-info-text:                #31708f
-// $state-info-bg:                  #d9edf7
-// $state-info-border:              darken(adjust-hue($state-info-bg, -10), 7%)
+$state-success-text:             #fff;
+$state-success-bg:               $brand-success;
+$state-success-border:           $brand-success;
 
-// $state-warning-text:             #8a6d3b
-// $state-warning-bg:               #fcf8e3
-// $state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 5%)
+$state-info-text:                #fff;
+$state-info-bg:                  $brand-info;
+$state-info-border:              $brand-info;
 
-// $state-danger-text:              #a94442
-// $state-danger-bg:                #f2dede
-// $state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 5%)
+$state-warning-text:             #fff;
+$state-warning-bg:               $brand-warning;
+$state-warning-border:           $brand-warning;
+
+$state-danger-text:              #fff;
+$state-danger-bg:                $brand-danger;
+$state-danger-border:            $brand-danger;
 
 
 //== Tooltips
diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss
index d751678f1b..30e084ecd6 100644
--- a/app/assets/stylesheets/main/variables.scss
+++ b/app/assets/stylesheets/main/variables.scss
@@ -19,6 +19,11 @@ $gl-primary: #446e9b;
 $gl-info: #029ACF;
 $gl-warning: #EB9532;
 
+$gl-primary:         #2C3E50;
+$gl-success:         #18BC9C;
+$gl-info:            #3498DB;
+$gl-warning:         #F39C12;
+$gl-danger:          #E74C3C;
 /*
  * Commit Diff Colors
  */
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 3a912d234f..98ce4150ff 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -101,23 +101,9 @@
 
   .btn,
   .form-control {
-    border: 1px solid #E1E1E1;
-    box-shadow: none;
     padding: 6px 9px;
   }
 
-  .btn {
-    background: none;
-    color: $gl-link-color;
-
-    &.active {
-      background-color: #f5f5f5;
-      border: 1px solid rgba(0,0,0,0.195);
-      color: #333;
-      font-weight: bold;
-    }
-  }
-
   .form-control {
     cursor: auto;
     @extend .monospace;
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 5daf8470d8..00b912742b 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -34,7 +34,7 @@
               %span Import existing git repo
             .col-sm-10
               = f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git'
-              .alert.alert-info
+              .alert.alert-info.prepend-top-10
                 This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
                 %br
                 The import will time out after 4 minutes. For big repositories, use a clone/push combination.
@@ -65,7 +65,7 @@
               %i.fa.fa-bitbucket
               Import projects from Bitbucket
             = render 'bitbucket_import_modal'
-      
+
       - unless request.host == 'gitlab.com'
         .project-import.form-group
           .col-sm-2
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 787cfd9304..74b0739565 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -40,7 +40,7 @@
               %p Repository is read-only
 
           - if @project.forked_from_project
-            .alert.alert-success
+            .well
               %i.fa.fa-code-fork.project-fork-icon
               Forked from:
               %br
diff --git a/app/views/shared/_no_ssh.html.haml b/app/views/shared/_no_ssh.html.haml
index 1a2946bacc..089179e677 100644
--- a/app/views/shared/_no_ssh.html.haml
+++ b/app/views/shared/_no_ssh.html.haml
@@ -1,8 +1,8 @@
 - if cookies[:hide_no_ssh_message].blank? && !current_user.hide_no_ssh_key && current_user.require_ssh_key?
   .no-ssh-key-message.alert.alert-warning.hidden-xs
-    You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', new_profile_key_path} to your profile
+    You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', new_profile_key_path, class: 'alert-link'} to your profile
 
     .pull-right
-      = link_to "Don't show again", profile_path(user: {hide_no_ssh_key: true}), method: :put
+      = link_to "Don't show again", profile_path(user: {hide_no_ssh_key: true}), method: :put, class: 'alert-link'
       |
-      = link_to 'Remind later', '#', class: 'hide-no-ssh-message'
+      = link_to 'Remind later', '#', class: 'hide-no-ssh-message alert-link'

From 4f3d704845c1ead8d39f49b04812305a8f8ab93a Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sat, 7 Mar 2015 00:29:25 -0800
Subject: [PATCH 076/143] Move mixins and bootstrap css to base directory

---
 app/assets/stylesheets/application.scss              | 9 +++++++--
 app/assets/stylesheets/{ => base}/gl_bootstrap.scss  | 1 -
 app/assets/stylesheets/{ => base}/gl_variables.scss  | 0
 app/assets/stylesheets/{main => base}/layout.scss    | 0
 app/assets/stylesheets/{main => base}/mixins.scss    | 0
 app/assets/stylesheets/{main => base}/variables.scss | 0
 6 files changed, 7 insertions(+), 3 deletions(-)
 rename app/assets/stylesheets/{ => base}/gl_bootstrap.scss (99%)
 rename app/assets/stylesheets/{ => base}/gl_variables.scss (100%)
 rename app/assets/stylesheets/{main => base}/layout.scss (100%)
 rename app/assets/stylesheets/{main => base}/mixins.scss (100%)
 rename app/assets/stylesheets/{main => base}/variables.scss (100%)

diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 2f9f09b4c6..015ff2ce4e 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -11,12 +11,17 @@
  *= require cal-heatmap
 */
 
-@import "main/*";
+
+@import "base/variables";
+@import "base/mixins";
+@import "base/layout";
+
 
 /**
  * Customized Twitter bootstrap
  */
-@import 'gl_bootstrap';
+@import 'base/gl_variables';
+@import 'base/gl_bootstrap';
 
 /**
  * NProgress load bar css
diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/base/gl_bootstrap.scss
similarity index 99%
rename from app/assets/stylesheets/gl_bootstrap.scss
rename to app/assets/stylesheets/base/gl_bootstrap.scss
index e8e58511f3..b0e2a678fc 100644
--- a/app/assets/stylesheets/gl_bootstrap.scss
+++ b/app/assets/stylesheets/base/gl_bootstrap.scss
@@ -2,7 +2,6 @@
  * Twitter bootstrap with GitLab customizations/additions
  *
  */
-@import "gl_variables";
 
 // Core variables and mixins
 @import "bootstrap/variables";
diff --git a/app/assets/stylesheets/gl_variables.scss b/app/assets/stylesheets/base/gl_variables.scss
similarity index 100%
rename from app/assets/stylesheets/gl_variables.scss
rename to app/assets/stylesheets/base/gl_variables.scss
diff --git a/app/assets/stylesheets/main/layout.scss b/app/assets/stylesheets/base/layout.scss
similarity index 100%
rename from app/assets/stylesheets/main/layout.scss
rename to app/assets/stylesheets/base/layout.scss
diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/base/mixins.scss
similarity index 100%
rename from app/assets/stylesheets/main/mixins.scss
rename to app/assets/stylesheets/base/mixins.scss
diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/base/variables.scss
similarity index 100%
rename from app/assets/stylesheets/main/variables.scss
rename to app/assets/stylesheets/base/variables.scss

From e2b8025abe929007fb82e952b0be954a7598e528 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sat, 7 Mar 2015 01:06:16 -0800
Subject: [PATCH 077/143] Increase input padding and fit issue form in laptop
 screen

---
 app/assets/stylesheets/base/gl_bootstrap.scss | 8 ++++++++
 app/assets/stylesheets/base/gl_variables.scss | 4 ++--
 app/assets/stylesheets/generic/gfm.scss       | 2 +-
 app/assets/stylesheets/generic/selects.scss   | 4 ++--
 app/assets/stylesheets/pages/projects.scss    | 5 -----
 app/views/projects/_issuable_form.html.haml   | 2 ++
 app/views/projects/blob/_blob.html.haml       | 2 +-
 7 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/app/assets/stylesheets/base/gl_bootstrap.scss b/app/assets/stylesheets/base/gl_bootstrap.scss
index b0e2a678fc..d1dba6d66b 100644
--- a/app/assets/stylesheets/base/gl_bootstrap.scss
+++ b/app/assets/stylesheets/base/gl_bootstrap.scss
@@ -189,3 +189,11 @@
     }
   }
 }
+
+.alert {
+  a {
+    @extend .alert-link;
+    color: #fff;
+    text-decoration: underline;
+  }
+}
diff --git a/app/assets/stylesheets/base/gl_variables.scss b/app/assets/stylesheets/base/gl_variables.scss
index 090eff7f29..2aa57e46a0 100644
--- a/app/assets/stylesheets/base/gl_variables.scss
+++ b/app/assets/stylesheets/base/gl_variables.scss
@@ -93,8 +93,8 @@ $font-size-base:          $gl-font-size;
 //
 //## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
 
-// $padding-base-vertical:     6px
-// $padding-base-horizontal:   12px
+$padding-base-vertical:     8px;
+$padding-base-horizontal:   14px;
 
 // $padding-large-vertical:    10px
 // $padding-large-horizontal:  16px
diff --git a/app/assets/stylesheets/generic/gfm.scss b/app/assets/stylesheets/generic/gfm.scss
index 1427b6a5ae..617d91154d 100644
--- a/app/assets/stylesheets/generic/gfm.scss
+++ b/app/assets/stylesheets/generic/gfm.scss
@@ -3,7 +3,7 @@
  */
 .issue-form, .merge-request-form, .wiki-form {
   .description {
-    height: 20em;
+    height: 18em;
     border-top-left-radius: 0;
   }
 }
diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss
index 2a2f9e8eb5..41ed736bbe 100644
--- a/app/assets/stylesheets/generic/selects.scss
+++ b/app/assets/stylesheets/generic/selects.scss
@@ -3,7 +3,7 @@
   .select2-choice {
     background: #FFF;
     border-color: #BBB;
-    padding: 6px 12px;
+    padding: 8px 14px;
     font-size: 13px;
     line-height: 18px;
     height: auto;
@@ -20,7 +20,7 @@
 }
 
 .select2-container-multi .select2-choices .select2-search-field input {
-  padding: 6px 12px;
+  padding: 8px 14px;
   font-size: 13px;
   line-height: 18px;
   height: auto;
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 98ce4150ff..bfd05973d7 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -99,11 +99,6 @@
     margin-right: 45px;
   }
 
-  .btn,
-  .form-control {
-    padding: 6px 9px;
-  }
-
   .form-control {
     cursor: auto;
     @extend .monospace;
diff --git a/app/views/projects/_issuable_form.html.haml b/app/views/projects/_issuable_form.html.haml
index bfacab5e48..a7cd129b63 100644
--- a/app/views/projects/_issuable_form.html.haml
+++ b/app/views/projects/_issuable_form.html.haml
@@ -50,6 +50,7 @@
         = f.select(:milestone_id, milestone_options(issuable),
           { include_blank: 'Select milestone' }, { class: 'select2' })
       - else
+        .prepend-top-10
         %span.light No open milestones available.
        
       - if can? current_user, :admin_milestone, issuable.project
@@ -63,6 +64,7 @@
       = f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
         { selected: issuable.label_ids }, multiple: true, class: 'select2'
     - else
+      .prepend-top-10
       %span.light No labels yet.
      
     - if can? current_user, :admin_label, issuable.project
diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml
index 05b1f5e841..9ff61f3887 100644
--- a/app/views/projects/blob/_blob.html.haml
+++ b/app/views/projects/blob/_blob.html.haml
@@ -15,7 +15,7 @@
       - else
         = link_to title, '#'
 
-%ul.blob-commit-info.alert.alert-info.hidden-xs
+%ul.blob-commit-info.well.hidden-xs
   - blob_commit = @repository.last_commit_for_path(@commit.id, blob.path)
   = render blob_commit, project: @project
 

From bf02072a86d4b0d06c246ecbea4f980523983941 Mon Sep 17 00:00:00 2001
From: Douwe Maan 
Date: Fri, 6 Mar 2015 12:50:35 +0100
Subject: [PATCH 078/143] Properly handle autosave local storage exceptions.

---
 CHANGELOG                                 |  1 +
 app/assets/javascripts/autosave.js.coffee | 12 +++++++++---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 37aee53bc0..f6079092f5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -20,6 +20,7 @@ v 7.9.0 (unreleased)
   - Add brakeman (security scanner for Ruby on Rails)
   - Slack username and channel options
   - Add grouped milestones from all projects to dashboard.
+  - Properly handle autosave local storage exceptions.
 
 v 7.8.1
   - Fix run of custom post receive hooks
diff --git a/app/assets/javascripts/autosave.js.coffee b/app/assets/javascripts/autosave.js.coffee
index 3450f4b55f..5d3fe81da7 100644
--- a/app/assets/javascripts/autosave.js.coffee
+++ b/app/assets/javascripts/autosave.js.coffee
@@ -14,7 +14,11 @@ class @Autosave
   restore: ->
     return unless window.localStorage?
 
-    text = window.localStorage.getItem @key
+    try
+      text = window.localStorage.getItem @key
+    catch
+      return
+
     @field.val text if text?.length > 0
     @field.trigger "input"    
 
@@ -23,11 +27,13 @@ class @Autosave
 
     text = @field.val()
     if text?.length > 0
-      window.localStorage.setItem @key, text
+      try
+        window.localStorage.setItem @key, text
     else
       @reset()
 
   reset: ->
     return unless window.localStorage?
 
-    window.localStorage.removeItem @key
\ No newline at end of file
+    try 
+      window.localStorage.removeItem @key

From be3edeb6a1db341e5a10f9031c79f5fbc25e6f59 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sat, 7 Mar 2015 10:35:17 -0800
Subject: [PATCH 079/143] Small UI improvements after css refactoring

---
 app/assets/stylesheets/base/gl_bootstrap.scss | 2 +-
 app/assets/stylesheets/generic/buttons.scss   | 7 -------
 app/assets/stylesheets/generic/gfm.scss       | 2 +-
 app/assets/stylesheets/generic/selects.scss   | 3 ++-
 app/assets/stylesheets/pages/issues.scss      | 2 +-
 app/views/admin/projects/index.html.haml      | 4 ++--
 app/views/admin/users/index.html.haml         | 4 ++--
 app/views/groups/projects.html.haml           | 2 +-
 app/views/profiles/show.html.haml             | 8 +++++---
 9 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/app/assets/stylesheets/base/gl_bootstrap.scss b/app/assets/stylesheets/base/gl_bootstrap.scss
index d1dba6d66b..0775c17181 100644
--- a/app/assets/stylesheets/base/gl_bootstrap.scss
+++ b/app/assets/stylesheets/base/gl_bootstrap.scss
@@ -157,7 +157,7 @@
 
     .panel-head-actions {
       position: relative;
-      top: -7px;
+      top: -6px;
       float: right;
     }
   }
diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss
index 7cc9782f53..0224484d82 100644
--- a/app/assets/stylesheets/generic/buttons.scss
+++ b/app/assets/stylesheets/generic/buttons.scss
@@ -6,12 +6,10 @@
   }
 
   &.btn-create {
-    @extend .wide;
     @extend .btn-success;
   }
 
   &.btn-save {
-    @extend .wide;
     @extend .btn-primary;
   }
 
@@ -23,11 +21,6 @@
     float: right;
   }
 
-  &.wide {
-    padding-left: 20px;
-    padding-right: 20px;
-  }
-
   &.btn-small {
     padding: 2px 10px;
     font-size: 12px;
diff --git a/app/assets/stylesheets/generic/gfm.scss b/app/assets/stylesheets/generic/gfm.scss
index 617d91154d..8fac5e534f 100644
--- a/app/assets/stylesheets/generic/gfm.scss
+++ b/app/assets/stylesheets/generic/gfm.scss
@@ -3,7 +3,7 @@
  */
 .issue-form, .merge-request-form, .wiki-form {
   .description {
-    height: 18em;
+    height: 16em;
     border-top-left-radius: 0;
   }
 }
diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss
index 41ed736bbe..2773ee11fd 100644
--- a/app/assets/stylesheets/generic/selects.scss
+++ b/app/assets/stylesheets/generic/selects.scss
@@ -3,10 +3,11 @@
   .select2-choice {
     background: #FFF;
     border-color: #BBB;
-    padding: 8px 14px;
+    padding: 6px 14px;
     font-size: 13px;
     line-height: 18px;
     height: auto;
+    margin: 2px 0;
 
     .select2-arrow {
       background: #FFF;
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index b909725bff..46522e9ece 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -40,7 +40,7 @@
 }
 
 .check-all-holder {
-  height: 32px;
+  height: 36px;
   float: left;
   margin-right: 12px;
   padding: 6px 15px;
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index b984188eb9..3a1e61d5d8 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -44,7 +44,7 @@
         Projects (#{@projects.total_count})
         .panel-head-actions
           .dropdown.inline
-            %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
+            %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'}
               %span.light sort:
               - if @sort.present?
                 = sort_options_hash[@sort]
@@ -63,7 +63,7 @@
                   = sort_title_oldest_updated
                 = link_to admin_namespaces_projects_path(sort: sort_value_largest_repo) do
                   = sort_title_largest_repo
-          = link_to 'New Project', new_project_path, class: "btn btn-new"
+          = link_to 'New Project', new_project_path, class: "btn btn-sm btn-success"
       %ul.well-list
         - @projects.each do |project|
           %li
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 4a4f0549ad..35e9fd5154 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -35,7 +35,7 @@
         Users (#{@users.total_count})
         .panel-head-actions
           .dropdown.inline
-            %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+            %a.dropdown-toggle.btn.btn-sm{href: '#', "data-toggle" => "dropdown"}
               %span.light sort:
               - if @sort.present?
                 = sort_options_hash[@sort]
@@ -59,7 +59,7 @@
                 = link_to admin_users_path(sort: sort_value_oldest_updated) do
                   = sort_title_oldest_updated
 
-          = link_to 'New User', new_admin_user_path, class: "btn btn-new"
+          = link_to 'New User', new_admin_user_path, class: "btn btn-new btn-sm"
       %ul.well-list
         - @users.each do |user|
           %li
diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml
index 8c829654fb..c95347b3a5 100644
--- a/app/views/groups/projects.html.haml
+++ b/app/views/groups/projects.html.haml
@@ -4,7 +4,7 @@
     projects:
     - if can? current_user, :manage_group, @group
       .panel-head-actions
-        = link_to new_project_path(namespace_id: @group.id), class: "btn btn-new" do
+        = link_to new_project_path(namespace_id: @group.id), class: "btn btn-sm btn-success" do
           %i.fa.fa-plus
           New Project
   %ul.well-list
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 459361a0d5..1a7bc353bf 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -56,7 +56,7 @@
       .form-group
         = f.label :bio, class: "control-label"
         .col-sm-10
-          = f.text_area :bio, rows: 6, class: "form-control", maxlength: 250
+          = f.text_area :bio, rows: 4, class: "form-control", maxlength: 250
           %span.help-block Tell us about yourself in fewer than 250 characters.
 
     .col-md-5
@@ -94,5 +94,7 @@
           %p Your profile is publicly visible because you joined public project(s)
 
 
-  .form-actions
-    = f.submit 'Save changes', class: "btn btn-save"
+  .row
+    .col-md-7
+      .col-sm-2
+      = f.submit 'Save changes', class: "btn btn-success"

From df13c9cac927af8d9b72d674b44c3d8017e1c846 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 12:05:15 -0700
Subject: [PATCH 080/143] Hide user page sidebar for mobilde devices

---
 app/views/users/show.html.haml | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 5e82d5780c..abd6b22978 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -1,5 +1,7 @@
 .row
-  .col-md-8
+  = link_to '#aside', class: 'show-aside' do
+    %i.fa.fa-angle-left
+  %section.col-md-8
     %h3.page-title
       = image_tag avatar_icon(@user.email, 90), class: "avatar avatar-tile s90", alt: ''
       = @user.name
@@ -19,10 +21,11 @@
       = render 'groups', groups: @groups
       %hr
 
-    .user-calendar
-      %h4.center.light
-        %i.fa.fa-spinner.fa-spin
-    %hr
+    .hidden-xs
+      .user-calendar
+        %h4.center.light
+          %i.fa.fa-spinner.fa-spin
+      %hr
     %h4
       User Activity
 
@@ -33,7 +36,7 @@
               %i.fa.fa-rss
 
     = render @events
-  .col-md-4
+  %aside.col-md-4
     = render 'profile', user: @user
     = render 'projects'
 

From 2e99d7c9157040612669993b54cbb236f199367a Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 12:15:02 -0700
Subject: [PATCH 081/143] Prevent date overflow on issue page on mobile devices

---
 app/assets/stylesheets/generic/mobile.scss | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/app/assets/stylesheets/generic/mobile.scss b/app/assets/stylesheets/generic/mobile.scss
index b3727c3367..1b0e056216 100644
--- a/app/assets/stylesheets/generic/mobile.scss
+++ b/app/assets/stylesheets/generic/mobile.scss
@@ -43,8 +43,10 @@
     }
   }
 
-  .page-title .new-issue-link {
-    display: none;
+  .page-title {
+    .note_created_ago, .new-issue-link {
+      display: none;
+    }
   }
 
   .issue_edited_ago, .note_edited_ago {

From b5c3e1a43158314cc1c624cff6294546ee64b418 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 14:46:22 -0700
Subject: [PATCH 082/143] Add GitLab UI development kit

---
 app/assets/stylesheets/pages/ui_dev_kit.scss |   9 +
 app/controllers/help_controller.rb           |   3 +
 app/views/help/ui.html.haml                  | 192 +++++++++++++++++++
 config/routes.rb                             |   9 +-
 4 files changed, 207 insertions(+), 6 deletions(-)
 create mode 100644 app/assets/stylesheets/pages/ui_dev_kit.scss
 create mode 100644 app/views/help/ui.html.haml

diff --git a/app/assets/stylesheets/pages/ui_dev_kit.scss b/app/assets/stylesheets/pages/ui_dev_kit.scss
new file mode 100644
index 0000000000..277afa1db9
--- /dev/null
+++ b/app/assets/stylesheets/pages/ui_dev_kit.scss
@@ -0,0 +1,9 @@
+.gitlab-ui-dev-kit {
+  > h2 {
+    font-size: 27px;
+    border-bottom: 1px solid #CCC;
+    color: #666;
+    margin: 30px 0;
+    font-weight: bold;
+  }
+}
diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb
index fc498559d6..c4d620d87b 100644
--- a/app/controllers/help_controller.rb
+++ b/app/controllers/help_controller.rb
@@ -15,4 +15,7 @@ class HelpController < ApplicationController
 
   def shortcuts
   end
+
+  def ui
+  end
 end
diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml
new file mode 100644
index 0000000000..cf6833c92c
--- /dev/null
+++ b/app/views/help/ui.html.haml
@@ -0,0 +1,192 @@
+- lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed fermentum nisi sapien, non consequat lectus aliquam ultrices. Suspendisse sodales est euismod nunc condimentum, a consectetur diam ornare."
+
+.gitlab-ui-dev-kit
+  %h1 GitLab UI development kit
+  %p.light
+    Use page inspector in your browser to check element classes and structure
+    of examples below.
+  %hr
+  %ul
+    %li
+      = link_to 'Blocks', '#blocks'
+    %li
+      = link_to 'Lists', '#lists'
+    %li
+      = link_to 'Tables', '#tables'
+    %li
+      = link_to 'Buttons', '#buttons'
+    %li
+      = link_to 'Panels', '#panels'
+    %li
+      = link_to 'Alerts', '#alerts'
+    %li
+      = link_to 'Forms', '#forms'
+
+  %h2#blocks Blocks
+
+  %h3
+    %code .well
+
+
+  .well
+    %h4 Something
+    = lorem
+
+
+  %h2#lists Lists
+
+  %h3
+    %code .well-list
+  %ul.well-list
+    %li
+      One item
+    %li
+      One item
+    %li
+      One item
+
+  %h3
+    %code .panel .well-list
+
+  .panel.panel-default
+    .panel-heading My list
+    %ul.well-list
+      %li
+        One item
+      %li
+        One item
+      %li
+        One item
+
+  %h3
+    %code .bordered-list
+  %ul.bordered-list
+    %li
+      One item
+    %li
+      One item
+    %li
+      One item
+
+
+
+  %h2#tables Tables
+
+  .example
+    %table.table
+      %thead
+        %tr
+          %th #
+          %th First Name
+          %th Last Name
+          %th Username
+      %tbody
+        %tr
+          %td 1
+          %td Mark
+          %td Otto
+          %td @mdo
+        %tr
+          %td 2
+          %td Jacob
+          %td Thornton
+          %td @fat
+        %tr
+          %td 3
+          %td Larry
+          %td the Bird
+          %td @twitter
+
+
+  %h2#buttons Buttons
+
+  .example
+    %button.btn.btn-default{:type => "button"} Default
+    %button.btn.btn-primary{:type => "button"} Primary
+    %button.btn.btn-success{:type => "button"} Success
+    %button.btn.btn-info{:type => "button"} Info
+    %button.btn.btn-warning{:type => "button"} Warning
+    %button.btn.btn-danger{:type => "button"} Danger
+    %button.btn.btn-link{:type => "button"} Link
+
+  %h2#panels Panels
+
+  .row
+    .col-md-6
+      .panel.panel-success
+        .panel-heading Success
+        .panel-body
+          = lorem
+      .panel.panel-primary
+        .panel-heading Primary
+        .panel-body
+          = lorem
+      .panel.panel-info
+        .panel-heading Info
+        .panel-body
+          = lorem
+    .col-md-6
+      .panel.panel-warning
+        .panel-heading Warning
+        .panel-body
+          = lorem
+      .panel.panel-danger
+        .panel-heading Danger
+        .panel-body
+          = lorem
+
+  %h2#alert Alerts
+
+  .row
+    .col-md-6
+      .alert.alert-success
+        = lorem
+      .alert.alert-primary
+        = lorem
+      .alert.alert-info
+        = lorem
+    .col-md-6
+      .alert.alert-warning
+        = lorem
+      .alert.alert-danger
+        = lorem
+
+  %h2#forms Forms
+
+  %h3
+    %code form.horizontal-form
+
+  %form.form-horizontal
+    .form-group
+      %label.col-sm-2.control-label{:for => "inputEmail3"} Email
+      .col-sm-10
+        %input#inputEmail3.form-control{:placeholder => "Email", :type => "email"}/
+    .form-group
+      %label.col-sm-2.control-label{:for => "inputPassword3"} Password
+      .col-sm-10
+        %input#inputPassword3.form-control{:placeholder => "Password", :type => "password"}/
+    .form-group
+      .col-sm-offset-2.col-sm-10
+        .checkbox
+          %label
+            %input{:type => "checkbox"}/
+            Remember me
+    .form-group
+      .col-sm-offset-2.col-sm-10
+        %button.btn.btn-default{:type => "submit"} Sign in
+
+  %h3
+    %code form
+
+  %form
+    .form-group
+      %label{:for => "exampleInputEmail1"} Email address
+      %input#exampleInputEmail1.form-control{:placeholder => "Enter email", :type => "email"}/
+    .form-group
+      %label{:for => "exampleInputPassword1"} Password
+      %input#exampleInputPassword1.form-control{:placeholder => "Password", :type => "password"}/
+    .checkbox
+      %label
+        %input{:type => "checkbox"}/
+        Remember me
+    %button.btn.btn-default{:type => "submit"} Sign in
diff --git a/config/routes.rb b/config/routes.rb
index 5348c86ea9..6dd9ded019 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -7,9 +7,8 @@ Gitlab::Application.routes.draw do
                 authorized_applications: 'oauth/authorized_applications',
                 authorizations: 'oauth/authorizations'
   end
-  #
+
   # Search
-  #
   get 'search' => 'search#show'
   get 'search/autocomplete' => 'search#autocomplete', as: :search_autocomplete
 
@@ -33,13 +32,11 @@ Gitlab::Application.routes.draw do
     receive_pack: Gitlab.config.gitlab_shell.receive_pack
   }), at: '/', constraints: lambda { |request| /[-\/\w\.]+\.git\//.match(request.path_info) }, via: [:get, :post]
 
-  #
   # Help
-  #
-
   get 'help'                  => 'help#index'
   get 'help/:category/:file'  => 'help#show', as: :help_page
   get 'help/shortcuts'
+  get 'help/ui'               => 'help#ui'
 
   #
   # Global snippets
@@ -73,7 +70,7 @@ Gitlab::Application.routes.draw do
       get :callback
       get :jobs
     end
-    
+
     resource :gitorious, only: [:create, :new], controller: :gitorious do
       get :status
       get :callback

From 69d2e1d8291621174cfa397e5f85d882da421031 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 14:56:45 -0700
Subject: [PATCH 083/143] Add UI guide to GitLab development help

---
 doc/development/README.md   |  1 +
 doc/development/ui_guide.md | 12 ++++++++++++
 2 files changed, 13 insertions(+)
 create mode 100644 doc/development/ui_guide.md

diff --git a/doc/development/README.md b/doc/development/README.md
index c31e5d7ae9..d5d264be19 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -5,3 +5,4 @@
 - [Rake tasks](rake_tasks.md) for development
 - [CI setup](ci_setup.md) for testing GitLab
 - [Sidekiq debugging](sidekiq_debugging.md)
+- [UI guide](ui_guide.md) for building GitLab with existing css styles and elements
diff --git a/doc/development/ui_guide.md b/doc/development/ui_guide.md
new file mode 100644
index 0000000000..2f01defc11
--- /dev/null
+++ b/doc/development/ui_guide.md
@@ -0,0 +1,12 @@
+# UI Guide for building GitLab 
+
+## Best practices for creating new pages in GitLab
+
+TODO: write some best practices when develop GitLab features.
+
+## GitLab UI development kit
+
+We created a page inside GitLab where you can check commonly used html and css elements.
+
+When you run GitLab instance locally - just visit http://localhost:3000/help/ui page to see UI examples 
+you can use during GitLab development.

From 1b5ca280d80e537a16cb9d8c22b605181a66c91f Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 15:21:28 -0700
Subject: [PATCH 084/143] Merge two css files with same name

---
 app/assets/stylesheets/generic/markdown_area.scss | 10 ++++++++++
 app/assets/stylesheets/pages/markdown_area.scss   |  9 ---------
 2 files changed, 10 insertions(+), 9 deletions(-)
 delete mode 100644 app/assets/stylesheets/pages/markdown_area.scss

diff --git a/app/assets/stylesheets/generic/markdown_area.scss b/app/assets/stylesheets/generic/markdown_area.scss
index 5a87cc6c61..22b7ce6d83 100644
--- a/app/assets/stylesheets/generic/markdown_area.scss
+++ b/app/assets/stylesheets/generic/markdown_area.scss
@@ -77,3 +77,13 @@
     }
   }
 }
+
+.markdown-area {
+  background: #FFF;
+  border: 1px solid #ddd;
+  min-height: 100px;
+  padding: 5px;
+  font-size: 14px;
+  box-shadow: none;
+  width: 100%;
+}
diff --git a/app/assets/stylesheets/pages/markdown_area.scss b/app/assets/stylesheets/pages/markdown_area.scss
deleted file mode 100644
index 8ee8eaa4ee..0000000000
--- a/app/assets/stylesheets/pages/markdown_area.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-.markdown-area {
-  background: #FFF;
-  border: 1px solid #ddd;
-  min-height: 100px;
-  padding: 5px;
-  font-size: 14px;
-  box-shadow: none;
-  width: 100%;
-}

From f3d78ee31a23b012e1aa6d149a9cab4d9d329d06 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 15:21:47 -0700
Subject: [PATCH 085/143] Add markdown info to UI dev kit page

---
 app/views/help/ui.html.haml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml
index cf6833c92c..58de5b7c86 100644
--- a/app/views/help/ui.html.haml
+++ b/app/views/help/ui.html.haml
@@ -21,6 +21,8 @@
       = link_to 'Alerts', '#alerts'
     %li
       = link_to 'Forms', '#forms'
+    %li
+      = link_to 'Markdown', '#markdown'
 
   %h2#blocks Blocks
 
@@ -190,3 +192,17 @@
         %input{:type => "checkbox"}/
         Remember me
     %button.btn.btn-default{:type => "submit"} Sign in
+
+  %h2#markdown Markdown
+  %h3
+    %code .md or .wiki and others
+
+  Markdown rendering has a bit different css and presented in next UI elements:
+
+  %ul
+    %li comment
+    %li issue, merge request description
+    %li wiki page
+    %li help page
+
+  You can check how markdown rendered at #{link_to 'Markdown help page', help_page_path("markdown", "markdown")}.

From a6bb345d585e8aa9ae80ef4f9745f104085537db Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 16:34:26 -0700
Subject: [PATCH 086/143] Add DevKit and development README links to
 CONTRIBUTING.md

---
 CONTRIBUTING.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 73a8f9eb49..42b5ce22e3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -63,6 +63,8 @@ Merge requests can be filed either at [gitlab.com](https://gitlab.com/gitlab-org
 
 If you are new to GitLab development (or web development in general), search for the label `easyfix` ([gitlab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=easyfix), [github](https://github.com/gitlabhq/gitlabhq/labels/easyfix)). Those are issues easy to fix, marked by the GitLab core-team. If you are unsure how to proceed but want to help, mention one of the core-team members to give you a hint.
 
+To start with GitLab download the [GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit) and see [Development section](doc/development/README.md) in the help file. 
+
 ### Merge request guidelines
 
 If you can, please submit a merge request with the fix or improvements including tests. If you don't know how to fix the issue but can write a test that exposes the issue we will accept that as well. In general bug fixes that include a regression test are merged quickly while new features without proper tests are least likely to receive timely feedback. The workflow to make a merge request is as follows:

From 9b3e156e43b8a14e4eb294a47bda6a477c8573b0 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 17:03:30 -0700
Subject: [PATCH 087/143] Move profile groups page to dashboard

---
 CHANGELOG                                             |  1 +
 .../{profiles => dashboard}/groups_controller.rb      |  6 ++----
 .../{profiles => dashboard}/groups/index.html.haml    |  2 +-
 .../groups/group_members/_group_member.html.haml      |  2 +-
 app/views/layouts/nav/_dashboard.html.haml            |  5 +++++
 app/views/layouts/nav/_profile.html.haml              |  5 -----
 config/routes.rb                                      | 11 ++++++-----
 7 files changed, 16 insertions(+), 16 deletions(-)
 rename app/controllers/{profiles => dashboard}/groups_controller.rb (71%)
 rename app/views/{profiles => dashboard}/groups/index.html.haml (83%)

diff --git a/CHANGELOG b/CHANGELOG
index b8f9599421..d88e45c0fc 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -31,6 +31,7 @@ v 7.9.0 (unreleased)
   - Condense commits already in target branch when updating merge request source branch.
   - Send notifications and leave system comments when bulk updating issues.
   - Automatically link commit ranges to compare page: sha1...sha4 or sha1..sha4 (includes sha1 in comparison)
+  - Move groups page from profile to dashboard
 
 v 7.8.2
   - Fix service migration issue when upgrading from versions prior to 7.3
diff --git a/app/controllers/profiles/groups_controller.rb b/app/controllers/dashboard/groups_controller.rb
similarity index 71%
rename from app/controllers/profiles/groups_controller.rb
rename to app/controllers/dashboard/groups_controller.rb
index ce9dd50df6..61d691e636 100644
--- a/app/controllers/profiles/groups_controller.rb
+++ b/app/controllers/dashboard/groups_controller.rb
@@ -1,6 +1,4 @@
-class Profiles::GroupsController < ApplicationController
-  layout "profile"
-
+class Dashboard::GroupsController < ApplicationController
   def index
     @user_groups = current_user.group_members.page(params[:page]).per(20)
   end
@@ -9,7 +7,7 @@ class Profiles::GroupsController < ApplicationController
     @users_group = group.group_members.where(user_id: current_user.id).first
     if can?(current_user, :destroy, @users_group)
       @users_group.destroy
-      redirect_to(profile_groups_path, info: "You left #{group.name} group.")
+      redirect_to(dashboard_groups_path, info: "You left #{group.name} group.")
     else
       return render_403
     end
diff --git a/app/views/profiles/groups/index.html.haml b/app/views/dashboard/groups/index.html.haml
similarity index 83%
rename from app/views/profiles/groups/index.html.haml
rename to app/views/dashboard/groups/index.html.haml
index daf76636ff..fd7bbb5500 100644
--- a/app/views/profiles/groups/index.html.haml
+++ b/app/views/dashboard/groups/index.html.haml
@@ -23,7 +23,7 @@
               Settings
 
           - if can?(current_user, :destroy, user_group)
-            = link_to leave_profile_group_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-small btn btn-grouped", title: 'Remove user from group' do
+            = link_to leave_dashboard_group_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-small btn btn-grouped", title: 'Remove user from group' do
               %i.fa.fa-sign-out
               Leave
 
diff --git a/app/views/groups/group_members/_group_member.html.haml b/app/views/groups/group_members/_group_member.html.haml
index 21029c3a07..30c3c2b00d 100644
--- a/app/views/groups/group_members/_group_member.html.haml
+++ b/app/views/groups/group_members/_group_member.html.haml
@@ -19,7 +19,7 @@
             %i.fa.fa-pencil-square-o
         - if can?(current_user, :destroy, member)
           - if current_user == member.user
-            = link_to leave_profile_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
+            = link_to leave_dashboard_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
               %i.fa.fa-minus.fa-inverse
           - else
             = link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index 304744ba25..a22ddaf1cf 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -9,6 +9,11 @@
       %i.fa.fa-cube
       %span
         Projects
+  = nav_link(controller: :groups) do
+    = link_to dashboard_groups_path, title: 'Groups' do
+      %i.fa.fa-group
+      %span
+        Groups
   = nav_link(controller: :milestones) do
     = link_to dashboard_milestones_path, title: 'Milestones' do
       %i.fa.fa-clock-o
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
index 0914d2a167..d88e862829 100644
--- a/app/views/layouts/nav/_profile.html.haml
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -43,11 +43,6 @@
       %i.fa.fa-image
       %span
         Design
-  = nav_link(controller: :groups) do
-    = link_to profile_groups_path, title: 'Groups' do
-      %i.fa.fa-group
-      %span
-        Groups
   = nav_link(path: 'profiles#history') do
     = link_to history_profile_path, title: 'History' do
       %i.fa.fa-history
diff --git a/config/routes.rb b/config/routes.rb
index 6dd9ded019..1b855cd7a3 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -193,11 +193,6 @@ Gitlab::Application.routes.draw do
       end
       resources :keys
       resources :emails, only: [:index, :create, :destroy]
-      resources :groups, only: [:index] do
-        member do
-          delete :leave
-        end
-      end
       resource :avatar, only: [:destroy]
     end
   end
@@ -220,6 +215,12 @@ Gitlab::Application.routes.draw do
 
     scope module: :dashboard do
       resources :milestones, only: [:index, :show]
+
+      resources :groups, only: [:index] do
+        member do
+          delete :leave
+        end
+      end
     end
   end
 

From bb7be246f6928368d0bdadfb7a3258d610d48252 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 17:30:01 -0700
Subject: [PATCH 088/143] Show active users(non-blocked) on admin dashboard

---
 app/views/admin/dashboard/index.html.haml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 931b0c5c10..34e4e33626 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -32,9 +32,9 @@
         %span.light.pull-right
           = Milestone.count
       %p
-        Users who signed in during last 30 days
+        Users
         %span.light.pull-right
-          = User.where("current_sign_in_at > ?", 30.days.ago).count
+          = User.count
     .col-md-4
       %h4
         Features
@@ -91,10 +91,10 @@
           = link_to('New Project', new_project_path, class: "btn btn-new")
     .col-sm-4
       .light-well
-        %h4 Users
+        %h4 Active Users
         .data
           = link_to admin_users_path do
-            %h1= User.count
+            %h1= User.active.count
           %hr
           = link_to 'New User', new_admin_user_path, class: "btn btn-new"
     .col-sm-4

From 27e3b47b7f9ba6daaef61677c6743e99c3c6dc60 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 17:35:49 -0700
Subject: [PATCH 089/143] Fix user fixtures for development

---
 db/fixtures/development/05_users.rb | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/db/fixtures/development/05_users.rb b/db/fixtures/development/05_users.rb
index b697f58d4e..24952a1f66 100644
--- a/db/fixtures/development/05_users.rb
+++ b/db/fixtures/development/05_users.rb
@@ -1,30 +1,31 @@
 Gitlab::Seeder.quiet do
   (2..20).each  do |i|
     begin
-      User.seed(:id, [{
-        id: i,
+      User.create!(
         username: Faker::Internet.user_name,
         name: Faker::Name.name,
         email: Faker::Internet.email,
-        confirmed_at: DateTime.now
-      }])
+        confirmed_at: DateTime.now,
+        password: '12345678'
+      )
+
       print '.'
-    rescue ActiveRecord::RecordNotSaved
+    rescue ActiveRecord::RecordInvalid
       print 'F'
     end
   end
 
   (1..5).each do |i|
     begin
-      User.seed do |s|
-        s.username = "user#{i}"
-        s.name = "User #{i}"
-        s.email = "user#{i}@example.com"
-        s.confirmed_at = DateTime.now
-        s.password = '12345678'
-      end
+      User.create!(
+        username: "user#{i}",
+        name: "User #{i}",
+        email: "user#{i}@example.com",
+        confirmed_at: DateTime.now,
+        password: '12345678'
+      )
       print '.'
-    rescue ActiveRecord::RecordNotSaved
+    rescue ActiveRecord::RecordInvalid
       print 'F'
     end
   end

From 21aff22adb37af1fc16667e6691ed5346e72c9e1 Mon Sep 17 00:00:00 2001
From: Martin Bastien 
Date: Sun, 8 Mar 2015 22:26:46 -0400
Subject: [PATCH 090/143] Fix link to bitbucket import documentation

Signed-off-by: Martin Bastien 
---
 app/views/projects/_bitbucket_import_modal.html.haml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/views/projects/_bitbucket_import_modal.html.haml b/app/views/projects/_bitbucket_import_modal.html.haml
index 5c52f91927..07d4d60276 100644
--- a/app/views/projects/_bitbucket_import_modal.html.haml
+++ b/app/views/projects/_bitbucket_import_modal.html.haml
@@ -10,4 +10,4 @@
           you need to
         - else
           your GitLab administrator needs to
-        == #{link_to 'setup OAuth integration', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/butbucket.md'}.
\ No newline at end of file
+        == #{link_to 'setup OAuth integration', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/bitbucket.md'}.

From bb9560a35a7860e6de44c51b6d2300f3ee1e27ae Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 20:45:03 -0700
Subject: [PATCH 091/143] Show total user count on dashboard page

---
 app/views/admin/dashboard/index.html.haml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 34e4e33626..d1c586328a 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -32,9 +32,9 @@
         %span.light.pull-right
           = Milestone.count
       %p
-        Users
+        Active Users
         %span.light.pull-right
-          = User.count
+          = User.active.count
     .col-md-4
       %h4
         Features
@@ -91,10 +91,10 @@
           = link_to('New Project', new_project_path, class: "btn btn-new")
     .col-sm-4
       .light-well
-        %h4 Active Users
+        %h4 Users
         .data
           = link_to admin_users_path do
-            %h1= User.active.count
+            %h1= User.count
           %hr
           = link_to 'New User', new_admin_user_path, class: "btn btn-new"
     .col-sm-4

From 7e4258777f8eed31cfe202bb96178823218f3b1c Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 20:52:22 -0700
Subject: [PATCH 092/143] Move Profile groups tests to Dashboard group tests

---
 features/{profile => dashboard}/group.feature |  16 +--
 .../steps/{profile => dashboard}/group.rb     |   2 +-
 features/steps/shared/paths.rb                |  16 +--
 .../security/dashboard_access_spec.rb         |   8 ++
 spec/features/security/profile_access_spec.rb | 107 ++++++++----------
 5 files changed, 73 insertions(+), 76 deletions(-)
 rename features/{profile => dashboard}/group.feature (85%)
 rename features/steps/{profile => dashboard}/group.rb (95%)

diff --git a/features/profile/group.feature b/features/dashboard/group.feature
similarity index 85%
rename from features/profile/group.feature
rename to features/dashboard/group.feature
index e2fbfde77b..0e4acb325b 100644
--- a/features/profile/group.feature
+++ b/features/dashboard/group.feature
@@ -1,4 +1,4 @@
-@profile
+@dashboard
 Feature: Profile Group
   Background:
     Given I sign in as "John Doe"
@@ -10,18 +10,18 @@ Feature: Profile Group
   @javascript
   Scenario: Owner should be able to leave from group if he is not the last owner
     Given "Mary Jane" is owner of group "Owned"
-    When I visit profile groups page
+    When I visit dashboard groups page
     Then I should see group "Owned" in group list
     Then I should see group "Guest" in group list
     When I click on the "Leave" button for group "Owned"
-    And I visit profile groups page
+    And I visit dashboard groups page
     Then I should not see group "Owned" in group list
     Then I should see group "Guest" in group list
 
   @javascript
   Scenario: Owner should not be able to leave from group if he is the last owner
     Given "Mary Jane" is guest of group "Owned"
-    When I visit profile groups page
+    When I visit dashboard groups page
     Then I should see group "Owned" in group list
     Then I should see group "Guest" in group list
     Then I should not see the "Leave" button for group "Owned"
@@ -29,20 +29,20 @@ Feature: Profile Group
   @javascript
   Scenario: Guest should be able to leave from group
     Given "Mary Jane" is guest of group "Guest"
-    When I visit profile groups page
+    When I visit dashboard groups page
     Then I should see group "Owned" in group list
     Then I should see group "Guest" in group list
     When I click on the "Leave" button for group "Guest"
-    When I visit profile groups page
+    When I visit dashboard groups page
     Then I should see group "Owned" in group list
     Then I should not see group "Guest" in group list
 
   @javascript
   Scenario: Guest should be able to leave from group even if he is the only user in the group
-    When I visit profile groups page
+    When I visit dashboard groups page
     Then I should see group "Owned" in group list
     Then I should see group "Guest" in group list
     When I click on the "Leave" button for group "Guest"
-    When I visit profile groups page
+    When I visit dashboard groups page
     Then I should see group "Owned" in group list
     Then I should not see group "Guest" in group list
diff --git a/features/steps/profile/group.rb b/features/steps/dashboard/group.rb
similarity index 95%
rename from features/steps/profile/group.rb
rename to features/steps/dashboard/group.rb
index 0a10e04e21..09d7717b67 100644
--- a/features/steps/profile/group.rb
+++ b/features/steps/dashboard/group.rb
@@ -1,4 +1,4 @@
-class Spinach::Features::ProfileGroup < Spinach::FeatureSteps
+class Spinach::Features::DashboardGroup < Spinach::FeatureSteps
   include SharedAuthentication
   include SharedGroup
   include SharedPaths
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index 835b644e6c..db6417bf95 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -87,6 +87,14 @@ module SharedPaths
     visit help_path
   end
 
+  step 'I visit dashboard groups page' do
+    visit dashboard_groups_path
+  end
+
+  step 'I should be redirected to the dashboard groups page' do
+    current_path.should == dashboard_groups_path
+  end
+
   # ----------------------------------------
   # Profile
   # ----------------------------------------
@@ -119,14 +127,6 @@ module SharedPaths
     visit history_profile_path
   end
 
-  step 'I visit profile groups page' do
-    visit profile_groups_path
-  end
-
-  step 'I should be redirected to the profile groups page' do
-    current_path.should == profile_groups_path
-  end
-
   # ----------------------------------------
   # Admin
   # ----------------------------------------
diff --git a/spec/features/security/dashboard_access_spec.rb b/spec/features/security/dashboard_access_spec.rb
index d1f00a3dd8..3d2d8a3502 100644
--- a/spec/features/security/dashboard_access_spec.rb
+++ b/spec/features/security/dashboard_access_spec.rb
@@ -52,4 +52,12 @@ describe "Dashboard access", feature: true  do
     it { expect(new_group_path).to be_allowed_for :user }
     it { expect(new_group_path).to be_denied_for :visitor }
   end
+
+  describe "GET /profile/groups" do
+    subject { dashboard_groups_path }
+
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :visitor }
+  end
 end
diff --git a/spec/features/security/profile_access_spec.rb b/spec/features/security/profile_access_spec.rb
index 5f254c42e5..2512a9c0e3 100644
--- a/spec/features/security/profile_access_spec.rb
+++ b/spec/features/security/profile_access_spec.rb
@@ -1,76 +1,65 @@
 require 'spec_helper'
 
-describe "Users Security", feature: true  do
-  describe "Project" do
-    before do
-      @u1 = create(:user)
-    end
+describe "Profile access", feature: true  do
+  before do
+    @u1 = create(:user)
+  end
 
-    describe "GET /login" do
-      it { expect(new_user_session_path).not_to be_404_for :visitor }
-    end
+  describe "GET /login" do
+    it { expect(new_user_session_path).not_to be_404_for :visitor }
+  end
 
-    describe "GET /profile/keys" do
-      subject { profile_keys_path }
+  describe "GET /profile/keys" do
+    subject { profile_keys_path }
 
-      it { is_expected.to be_allowed_for @u1 }
-      it { is_expected.to be_allowed_for :admin }
-      it { is_expected.to be_allowed_for :user }
-      it { is_expected.to be_denied_for :visitor }
-    end
+    it { is_expected.to be_allowed_for @u1 }
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :visitor }
+  end
 
-    describe "GET /profile" do
-      subject { profile_path }
+  describe "GET /profile" do
+    subject { profile_path }
 
-      it { is_expected.to be_allowed_for @u1 }
-      it { is_expected.to be_allowed_for :admin }
-      it { is_expected.to be_allowed_for :user }
-      it { is_expected.to be_denied_for :visitor }
-    end
+    it { is_expected.to be_allowed_for @u1 }
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :visitor }
+  end
 
-    describe "GET /profile/account" do
-      subject { profile_account_path }
+  describe "GET /profile/account" do
+    subject { profile_account_path }
 
-      it { is_expected.to be_allowed_for @u1 }
-      it { is_expected.to be_allowed_for :admin }
-      it { is_expected.to be_allowed_for :user }
-      it { is_expected.to be_denied_for :visitor }
-    end
+    it { is_expected.to be_allowed_for @u1 }
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :visitor }
+  end
 
-    describe "GET /profile/design" do
-      subject { design_profile_path }
+  describe "GET /profile/design" do
+    subject { design_profile_path }
 
-      it { is_expected.to be_allowed_for @u1 }
-      it { is_expected.to be_allowed_for :admin }
-      it { is_expected.to be_allowed_for :user }
-      it { is_expected.to be_denied_for :visitor }
-    end
+    it { is_expected.to be_allowed_for @u1 }
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :visitor }
+  end
 
-    describe "GET /profile/history" do
-      subject { history_profile_path }
+  describe "GET /profile/history" do
+    subject { history_profile_path }
 
-      it { is_expected.to be_allowed_for @u1 }
-      it { is_expected.to be_allowed_for :admin }
-      it { is_expected.to be_allowed_for :user }
-      it { is_expected.to be_denied_for :visitor }
-    end
+    it { is_expected.to be_allowed_for @u1 }
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :visitor }
+  end
 
-    describe "GET /profile/notifications" do
-      subject { profile_notifications_path }
+  describe "GET /profile/notifications" do
+    subject { profile_notifications_path }
 
-      it { is_expected.to be_allowed_for @u1 }
-      it { is_expected.to be_allowed_for :admin }
-      it { is_expected.to be_allowed_for :user }
-      it { is_expected.to be_denied_for :visitor }
-    end
-
-    describe "GET /profile/groups" do
-      subject { profile_groups_path }
-
-      it { is_expected.to be_allowed_for @u1 }
-      it { is_expected.to be_allowed_for :admin }
-      it { is_expected.to be_allowed_for :user }
-      it { is_expected.to be_denied_for :visitor }
-    end
+    it { is_expected.to be_allowed_for @u1 }
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :visitor }
   end
 end

From de11c13ac074baa2b63165a51c59f2925c0dff83 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Sun, 8 Mar 2015 22:39:37 -0700
Subject: [PATCH 093/143] Fix dashboard groups test

---
 features/dashboard/group.feature | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/features/dashboard/group.feature b/features/dashboard/group.feature
index 0e4acb325b..92c1379ba7 100644
--- a/features/dashboard/group.feature
+++ b/features/dashboard/group.feature
@@ -1,5 +1,5 @@
 @dashboard
-Feature: Profile Group
+Feature: Dashboard Group
   Background:
     Given I sign in as "John Doe"
     And "John Doe" is owner of group "Owned"

From 224e104d8dc79e081fd897a1e52799dc1a0082bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hannes=20Rosen=C3=B6gger?= <123haynes@gmail.com>
Date: Mon, 9 Mar 2015 12:52:45 +0100
Subject: [PATCH 094/143] fix mass SQL statements on initial push

This commit disables process_commit_messages()
for the initial push to the default branch.
This fixes the mass SQL statements (~500000) that were executed during
the initial push of the linux kernel for example.
---
 CHANGELOG                              | 1 +
 app/services/git_push_service.rb       | 4 +++-
 spec/services/git_push_service_spec.rb | 9 ---------
 3 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index b8f9599421..588e645c69 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 Please view this file on the master branch, on stable branches it's out of date.
 
 v 7.9.0 (unreleased)
+  - Fix mass SQL statements on initial push (Hannes Rosenögger)
   - Add tag push notifications and normalize HipChat and Slack messages to be consistent (Stan Hu)
   - Add comment notification events to HipChat and Slack services (Stan Hu)
   - Add issue and merge request events to HipChat and Slack services (Stan Hu)
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 13def12776..4e1afea6d5 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -42,8 +42,10 @@ class GitPushService
           # as a heuristic. This may include more commits than are actually pushed, but
           # that shouldn't matter because we check for existing cross-references later.
           @push_commits = project.repository.commits_between(project.default_branch, newrev)
+
+          # don't process commits for the initial push to the default branch
+          process_commit_messages(ref)
         end
-        process_commit_messages(ref)
       elsif push_to_existing_branch?(ref, oldrev)
         # Collect data for this git push
         @push_commits = project.repository.commits_between(oldrev, newrev)
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index e264072b57..1b1e3ca5f8 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -197,15 +197,6 @@ describe GitPushService do
 
       service.execute(project, user, @blankrev, @newrev, 'refs/heads/other')
     end
-
-    it "finds references in the first push to a default branch" do
-      allow(project.repository).to receive(:commits_between).with(@blankrev, @newrev).and_return([])
-      allow(project.repository).to receive(:commits).with(@newrev).and_return([commit])
-
-      expect(Note).to receive(:create_cross_reference_note).with(issue, commit, commit_author, project)
-
-      service.execute(project, user, @blankrev, @newrev, 'refs/heads/master')
-    end
   end
 
   describe "closing issues from pushed commits" do

From fc64b3f7b78fefde211caf56bb4f0b06edc0b045 Mon Sep 17 00:00:00 2001
From: Kuo-Cheng Yeu 
Date: Mon, 9 Mar 2015 23:20:44 +0800
Subject: [PATCH 095/143] remove duplicate right braces ('}') in configuration
 examples of GitHub, GitLab, and Google.

---
 doc/integration/github.md | 4 ++--
 doc/integration/gitlab.md | 4 ++--
 doc/integration/google.md | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/doc/integration/github.md b/doc/integration/github.md
index a9f1bc31bb..b64501c2aa 100644
--- a/doc/integration/github.md
+++ b/doc/integration/github.md
@@ -53,7 +53,7 @@ GitHub will generate an application ID and secret key for you to use.
           "app_id" => "YOUR_APP_ID",
           "app_secret" => "YOUR_APP_SECRET",
           "url" => "https://github.com/",
-          "args" => { "scope" => "user:email" } }
+          "args" => { "scope" => "user:email" }
         }
       ]
     ```
@@ -76,4 +76,4 @@ GitHub will generate an application ID and secret key for you to use.
 
 On the sign in page there should now be a GitHub icon below the regular sign in form. 
 Click the icon to begin the authentication process. GitHub will ask the user to sign in and authorize the GitLab application. 
-If everything goes well the user will be returned to GitLab and will be signed in.
\ No newline at end of file
+If everything goes well the user will be returned to GitLab and will be signed in.
diff --git a/doc/integration/gitlab.md b/doc/integration/gitlab.md
index 49ffaa62af..216f1f11a9 100644
--- a/doc/integration/gitlab.md
+++ b/doc/integration/gitlab.md
@@ -58,7 +58,7 @@ GitLab.com will generate an application ID and secret key for you to use.
           "name" => "gitlab",
           "app_id" => "YOUR_APP_ID",
           "app_secret" => "YOUR_APP_SECRET",
-          "args" => { "scope" => "api" } }
+          "args" => { "scope" => "api" }
         }
       ]
     ```
@@ -81,4 +81,4 @@ GitLab.com will generate an application ID and secret key for you to use.
 
 On the sign in page there should now be a GitLab.com icon below the regular sign in form. 
 Click the icon to begin the authentication process. GitLab.com will ask the user to sign in and authorize the GitLab application. 
-If everything goes well the user will be returned to your GitLab instance and will be signed in.
\ No newline at end of file
+If everything goes well the user will be returned to your GitLab instance and will be signed in.
diff --git a/doc/integration/google.md b/doc/integration/google.md
index d7b741ece6..e1c14c7c94 100644
--- a/doc/integration/google.md
+++ b/doc/integration/google.md
@@ -55,7 +55,7 @@ To enable the Google OAuth2 OmniAuth provider you must register your application
           "name" => "google_oauth2",
           "app_id" => "YOUR_APP_ID",
           "app_secret" => "YOUR_APP_SECRET",
-          "args" => { "access_type" => "offline", "approval_prompt" => '' } }
+          "args" => { "access_type" => "offline", "approval_prompt" => '' }
         }
       ]
     ```

From dd24c3d4b9ab153cd74e551772412122f8c643c1 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 13:02:06 -0700
Subject: [PATCH 096/143] Improve user block/unblock UI in admin area

---
 app/controllers/admin/users_controller.rb |  4 +-
 app/views/admin/users/show.html.haml      | 77 ++++++++++++-----------
 2 files changed, 43 insertions(+), 38 deletions(-)

diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index ecedb31a7f..693970e534 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -24,7 +24,7 @@ class Admin::UsersController < Admin::ApplicationController
 
   def block
     if user.block
-      redirect_to :back, alert: "Successfully blocked"
+      redirect_to :back, notice: "Successfully blocked"
     else
       redirect_to :back, alert: "Error occurred. User was not blocked"
     end
@@ -32,7 +32,7 @@ class Admin::UsersController < Admin::ApplicationController
 
   def unblock
     if user.activate
-      redirect_to :back, alert: "Successfully unblocked"
+      redirect_to :back, notice: "Successfully unblocked"
     else
       redirect_to :back, alert: "Error occurred. User was not unblocked"
     end
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index 9026789750..bae9a97bf3 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -108,45 +108,50 @@
       .col-md-6
         - unless @user == current_user
           - if @user.blocked?
-            .alert.alert-info
-              %h4 This user is blocked
-              %p Blocking user has the following effects:
-              %ul
-                %li User will not be able to login
-                %li User will not be able to access git repositories
-                %li User will be removed from joined projects and groups
-                %li Personal projects will be left
-                %li Owned groups will be left
-              %br
-              = link_to 'Unblock user', unblock_admin_user_path(@user), method: :put, class: "btn btn-new", data: { confirm: 'Are you sure?' }
+            .panel.panel-info
+              .panel-heading
+                This user is blocked
+              .panel-body
+                %p Blocking user has the following effects:
+                %ul
+                  %li User will not be able to login
+                  %li User will not be able to access git repositories
+                  %li User will be removed from joined projects and groups
+                  %li Personal projects will be left
+                  %li Owned groups will be left
+                %br
+                = link_to 'Unblock user', unblock_admin_user_path(@user), method: :put, class: "btn btn-info", data: { confirm: 'Are you sure?' }
           - else
-            .alert.alert-warning
-              %h4 Block this user
-              %p Blocking user has the following effects:
-              %ul
-                %li User will not be able to login
-                %li User will not be able to access git repositories
-                %li User will be removed from joined projects and groups
-                %li Personal projects will be left
-                %li Owned groups will be left
-              %br
-              = link_to 'Block user', block_admin_user_path(@user), data: { confirm: 'USER WILL BE BLOCKED! Are you sure?' }, method: :put, class: "btn btn-remove"
+            .panel.panel-warning
+              .panel-heading
+                Block this user
+              .panel-body
+                %p Blocking user has the following effects:
+                %ul
+                  %li User will not be able to login
+                  %li User will not be able to access git repositories
+                  %li User will be removed from joined projects and groups
+                  %li Personal projects will be left
+                  %li Owned groups will be left
+                %br
+                = link_to 'Block user', block_admin_user_path(@user), data: { confirm: 'USER WILL BE BLOCKED! Are you sure?' }, method: :put, class: "btn btn-warning"
 
-          .alert.alert-danger
-            %h4
+          .panel.panel-danger
+            .panel-heading
               Remove user
-            %p Deleting a user has the following effects:
-            %ul
-              %li All user content like authored issues, snippets, comments will be removed
-              - rp = @user.personal_projects.count
-              - unless rp.zero?
-                %li #{pluralize rp, 'personal project'} will be removed and cannot be restored
-              - if @user.solo_owned_groups.present?
-                %li
-                  Next groups with all content will be removed:
-                  %strong #{@user.solo_owned_groups.map(&:name).join(', ')}
-            %br
-            = link_to 'Remove user', [:admin, @user], data: { confirm: "USER #{@user.name} WILL BE REMOVED! Are you sure?" }, method: :delete, class: "btn btn-remove"
+            .panel-body
+              %p Deleting a user has the following effects:
+              %ul
+                %li All user content like authored issues, snippets, comments will be removed
+                - rp = @user.personal_projects.count
+                - unless rp.zero?
+                  %li #{pluralize rp, 'personal project'} will be removed and cannot be restored
+                - if @user.solo_owned_groups.present?
+                  %li
+                    Next groups with all content will be removed:
+                    %strong #{@user.solo_owned_groups.map(&:name).join(', ')}
+              %br
+              = link_to 'Remove user', [:admin, @user], data: { confirm: "USER #{@user.name} WILL BE REMOVED! Are you sure?" }, method: :delete, class: "btn btn-remove"
 
   #profile.tab-pane
     .row

From d36ee3190aa1fb8c1238967a3049d5b8271c9030 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 14:12:03 -0700
Subject: [PATCH 097/143] Add starred projects page to dashboard

---
 CHANGELOG                                     |  1 +
 app/assets/javascripts/dispatcher.js.coffee   |  3 +++
 .../dashboard/projects_controller.rb          | 27 +++++++++++++++++++
 app/views/dashboard/_sidebar.html.haml        |  4 +--
 .../dashboard/projects/starred.html.haml      | 23 ++++++++++++++++
 app/views/events/_events.html.haml            |  2 +-
 app/views/layouts/nav/_dashboard.html.haml    |  5 ++++
 config/routes.rb                              |  6 +++++
 8 files changed, 68 insertions(+), 3 deletions(-)
 create mode 100644 app/controllers/dashboard/projects_controller.rb
 create mode 100644 app/views/dashboard/projects/starred.html.haml

diff --git a/CHANGELOG b/CHANGELOG
index 0333b1dc50..b210a6b015 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -33,6 +33,7 @@ v 7.9.0 (unreleased)
   - Send notifications and leave system comments when bulk updating issues.
   - Automatically link commit ranges to compare page: sha1...sha4 or sha1..sha4 (includes sha1 in comparison)
   - Move groups page from profile to dashboard
+  - Starred projects page at dashboard 
 
 v 7.8.2
   - Fix service migration issue when upgrading from versions prior to 7.3
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index bf94fa3aaa..928232e95b 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -55,6 +55,9 @@ class Dispatcher
       when 'dashboard:show'
         new Dashboard()
         new Activities()
+      when 'dashboard:projects:starred'
+        new Activities()
+        new ProjectsList()
       when 'projects:commit:show'
         new Commit()
         new Diff()
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
new file mode 100644
index 0000000000..56e6fcc41c
--- /dev/null
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -0,0 +1,27 @@
+class Dashboard::ProjectsController < ApplicationController
+  before_filter :event_filter
+
+  def starred
+    @projects = current_user.starred_projects
+    @projects = @projects.includes(:namespace, :forked_from_project, :tags)
+    @projects = @projects.sort(@sort = params[:sort])
+    @groups = []
+
+    respond_to do |format|
+      format.html
+
+      format.json do
+        load_events
+        pager_json("events/_events", @events.count)
+      end
+    end
+  end
+
+  private
+
+  def load_events
+    @events = Event.in_projects(@projects.pluck(:id))
+    @events = @event_filter.apply_filter(@events).with_associations
+    @events = @events.limit(20).offset(params[:offset] || 0)
+  end
+end
diff --git a/app/views/dashboard/_sidebar.html.haml b/app/views/dashboard/_sidebar.html.haml
index a980f49542..983da4aba0 100644
--- a/app/views/dashboard/_sidebar.html.haml
+++ b/app/views/dashboard/_sidebar.html.haml
@@ -10,9 +10,9 @@
 
 .tab-content
   .tab-pane.active#projects
-    = render "projects", projects: @projects
+    = render "dashboard/projects", projects: @projects
   .tab-pane#groups
-    = render "groups", groups: @groups
+    = render "dashboard/groups", groups: @groups
 
 .prepend-top-20
   = render 'shared/promo'
diff --git a/app/views/dashboard/projects/starred.html.haml b/app/views/dashboard/projects/starred.html.haml
new file mode 100644
index 0000000000..94de609256
--- /dev/null
+++ b/app/views/dashboard/projects/starred.html.haml
@@ -0,0 +1,23 @@
+- if @projects.any?
+  .dashboard.row
+    %section.activities.col-md-8
+      = render 'dashboard/activities'
+    %aside.col-md-4
+      .panel.panel-default
+        .panel-heading.clearfix
+          .input-group
+            = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
+            - if current_user.can_create_project?
+              .input-group-addon.dash-new-project
+                = link_to new_project_path do
+                  %strong New project
+
+        = render 'shared/projects_list', projects: @projects,
+          projects_limit: 20, stars: true, avatar: false
+
+    = link_to '#aside', class: 'show-aside' do
+      %i.fa.fa-angle-left
+
+- else
+  %h3 You dont have starred projects yet
+  %p.slead Visit project page and press on star icon and it will appear on this page.
diff --git a/app/views/events/_events.html.haml b/app/views/events/_events.html.haml
index 3d62d47886..68c19df092 100644
--- a/app/views/events/_events.html.haml
+++ b/app/views/events/_events.html.haml
@@ -1 +1 @@
-= render @events
+= render partial: 'events/event', collection: @events
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index a22ddaf1cf..b21f25e87c 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -9,6 +9,11 @@
       %i.fa.fa-cube
       %span
         Projects
+  = nav_link(path: 'projects#starred') do
+    = link_to starred_dashboard_projects_path, title: 'Starred Projects' do
+      %i.fa.fa-star
+      %span
+        Starred Projects
   = nav_link(controller: :groups) do
     = link_to dashboard_groups_path, title: 'Groups' do
       %i.fa.fa-group
diff --git a/config/routes.rb b/config/routes.rb
index 1b855cd7a3..637b855e66 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -221,6 +221,12 @@ Gitlab::Application.routes.draw do
           delete :leave
         end
       end
+
+      resources :projects, only: [] do
+        collection do
+          get :starred
+        end
+      end
     end
   end
 

From b8d73315f5e094906111ab16607b5fa2685d2ea8 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 14:25:14 -0700
Subject: [PATCH 098/143] Add tests for starred projects page

---
 features/dashboard/starred_projects.feature  | 12 ++++++++++++
 features/steps/dashboard/starred_projects.rb | 15 +++++++++++++++
 features/steps/shared/paths.rb               |  4 ++++
 3 files changed, 31 insertions(+)
 create mode 100644 features/dashboard/starred_projects.feature
 create mode 100644 features/steps/dashboard/starred_projects.rb

diff --git a/features/dashboard/starred_projects.feature b/features/dashboard/starred_projects.feature
new file mode 100644
index 0000000000..9dfd2fbab9
--- /dev/null
+++ b/features/dashboard/starred_projects.feature
@@ -0,0 +1,12 @@
+@dashboard
+Feature: Dashboard Starred Projects
+  Background:
+    Given I sign in as a user
+    And public project "Community"
+    And I starred project "Community"
+    And I own project "Shop"
+    And I visit dashboard starred projects page
+
+  Scenario: I should see projects list
+    Then I should see project "Community"
+    And I should not see project "Shop"
diff --git a/features/steps/dashboard/starred_projects.rb b/features/steps/dashboard/starred_projects.rb
new file mode 100644
index 0000000000..b9ad2f13e2
--- /dev/null
+++ b/features/steps/dashboard/starred_projects.rb
@@ -0,0 +1,15 @@
+class Spinach::Features::DashboardStarredProjects < Spinach::FeatureSteps
+  include SharedAuthentication
+  include SharedPaths
+  include SharedProject
+
+  step 'I starred project "Community"' do
+    current_user.toggle_star(Project.find_by(name: 'Community'))
+  end
+
+  step 'I should not see project "Shop"' do
+    within 'aside' do
+      page.should_not have_content('Shop')
+    end
+  end
+end
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index db6417bf95..bb6c336d7c 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -95,6 +95,10 @@ module SharedPaths
     current_path.should == dashboard_groups_path
   end
 
+  step 'I visit dashboard starred projects page' do
+    visit starred_dashboard_projects_path
+  end
+
   # ----------------------------------------
   # Profile
   # ----------------------------------------

From c6b242112781120233a3627098e50689f6ccf9f8 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 15:20:32 -0700
Subject: [PATCH 099/143] Render milestone progress with one helper method

---
 app/helpers/milestones_helper.rb                   | 11 +++++++++++
 app/views/dashboard/milestones/index.html.haml     |  3 +--
 app/views/dashboard/milestones/show.html.haml      |  3 +--
 app/views/groups/milestones/index.html.haml        |  3 +--
 app/views/groups/milestones/show.html.haml         |  3 +--
 app/views/projects/milestones/_milestone.html.haml |  3 +--
 app/views/projects/milestones/show.html.haml       |  3 +--
 7 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb
index 3383b1ae5b..59fdc0d49c 100644
--- a/app/helpers/milestones_helper.rb
+++ b/app/helpers/milestones_helper.rb
@@ -8,4 +8,15 @@ module MilestonesHelper
       dashboard_milestones_path(opts)
     end
   end
+
+  def milestone_progress_bar(milestone)
+    options = {
+      class: 'progress-bar progress-bar-success',
+      style: "width: #{milestone.percent_complete}%;"
+    }
+
+    content_tag :div, class: 'progress' do
+      content_tag :div, nil, options
+    end
+  end
 end
diff --git a/app/views/dashboard/milestones/index.html.haml b/app/views/dashboard/milestones/index.html.haml
index 65fc589851..caf3b68586 100644
--- a/app/views/dashboard/milestones/index.html.haml
+++ b/app/views/dashboard/milestones/index.html.haml
@@ -28,8 +28,7 @@
                   = pluralize milestone.merge_requests_count, 'Merge Request'
                  
                 %span.light #{milestone.percent_complete}% complete
-              .progress.progress-info
-                .progress-bar{style: "width: #{milestone.percent_complete}%;"}
+              = milestone_progress_bar(milestone)
               %div
                 %br
                 - milestone.milestones.each do |milestone|
diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml
index a45a52001b..57cce9ab74 100644
--- a/app/views/dashboard/milestones/show.html.haml
+++ b/app/views/dashboard/milestones/show.html.haml
@@ -39,8 +39,7 @@
     #{@dashboard_milestone.closed_items_count} closed
     –
     #{@dashboard_milestone.open_items_count} open
-  .progress.progress-info
-    .progress-bar{style: "width: #{@dashboard_milestone.percent_complete}%;"}
+  = milestone_progress_bar(@dashboard_milestone)
 
 %ul.nav.nav-tabs
   %li.active
diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml
index fcbcb309aa..9febaab04a 100644
--- a/app/views/groups/milestones/index.html.haml
+++ b/app/views/groups/milestones/index.html.haml
@@ -36,8 +36,7 @@
                   = pluralize milestone.merge_requests_count, 'Merge Request'
                  
                 %span.light #{milestone.percent_complete}% complete
-              .progress.progress-info
-                .progress-bar{style: "width: #{milestone.percent_complete}%;"}
+              = milestone_progress_bar(milestone)
               %div
                 %br
                 - milestone.milestones.each do |milestone|
diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml
index e3606d167a..dd2d84499b 100644
--- a/app/views/groups/milestones/show.html.haml
+++ b/app/views/groups/milestones/show.html.haml
@@ -45,8 +45,7 @@
     #{@group_milestone.closed_items_count} closed
     –
     #{@group_milestone.open_items_count} open
-  .progress.progress-info
-    .progress-bar{style: "width: #{@group_milestone.percent_complete}%;"}
+  = milestone_progress_bar(@group_milestone)
 
 %ul.nav.nav-tabs
   %li.active
diff --git a/app/views/projects/milestones/_milestone.html.haml b/app/views/projects/milestones/_milestone.html.haml
index d32b2ba271..dcf56541db 100644
--- a/app/views/projects/milestones/_milestone.html.haml
+++ b/app/views/projects/milestones/_milestone.html.haml
@@ -23,5 +23,4 @@
           = pluralize milestone.merge_requests.count, 'Merge Request'
          
         %span.light #{milestone.percent_complete}% complete
-      .progress.progress-info
-        .progress-bar{style: "width: #{milestone.percent_complete}%;"}
+      = milestone_progress_bar(milestone)
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index fea96f3701..110d896734 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -43,8 +43,7 @@
      
     %span.light #{@milestone.percent_complete}% complete
     %span.pull-right= @milestone.expires_at
-  .progress.progress-info
-    .progress-bar{style: "width: #{@milestone.percent_complete}%;"}
+  = milestone_progress_bar(@milestone)
 
 
 %ul.nav.nav-tabs

From 3e6147ada4a7a252d5e9ca604a43d85b7756a5ea Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 16:24:45 -0700
Subject: [PATCH 100/143] Make milestone titles in list to be bold

---
 app/assets/stylesheets/pages/milestone.scss | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss
index 29ad4e24f0..15e3948e40 100644
--- a/app/assets/stylesheets/pages/milestone.scss
+++ b/app/assets/stylesheets/pages/milestone.scss
@@ -1,3 +1,9 @@
 .issues-sortable-list .str-truncated {
   max-width: 90%;
 }
+
+li.milestone {
+  h4 {
+    font-weight: bold;
+  }
+}

From 23fabc081d7476339e96ec0dfdf7cd6744da5375 Mon Sep 17 00:00:00 2001
From: DJ Mountney 
Date: Mon, 9 Mar 2015 16:36:41 -0700
Subject: [PATCH 101/143] Fixing import redirect loop

While importing, don't redirect import actions to the project page, even if the repository exists
---
 app/controllers/projects/imports_controller.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb
index 79d9910ce8..b64491b466 100644
--- a/app/controllers/projects/imports_controller.rb
+++ b/app/controllers/projects/imports_controller.rb
@@ -37,7 +37,7 @@ class Projects::ImportsController < Projects::ApplicationController
   private
 
   def require_no_repo
-    if @project.repository_exists?
+    if @project.repository_exists? && !@project.import_in_progress?
       redirect_to(namespace_project_path(@project.namespace, @project)) and return
     end
   end

From 6b76ffc222e063cf4450aacb71805068e044beba Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 17:06:08 -0700
Subject: [PATCH 102/143] Apply more styles from Flatly theme

Also add bottom margin for footer links on login page
---
 app/assets/stylesheets/base/gl_variables.scss | 36 +++++++++++--------
 app/assets/stylesheets/generic/common.scss    |  9 +++--
 app/assets/stylesheets/generic/forms.scss     |  2 +-
 app/assets/stylesheets/pages/events.scss      |  3 +-
 app/assets/stylesheets/pages/tree.scss        |  2 +-
 .../layouts/_public_head_panel.html.haml      |  2 +-
 6 files changed, 31 insertions(+), 23 deletions(-)

diff --git a/app/assets/stylesheets/base/gl_variables.scss b/app/assets/stylesheets/base/gl_variables.scss
index 2aa57e46a0..6244f7ccc0 100644
--- a/app/assets/stylesheets/base/gl_variables.scss
+++ b/app/assets/stylesheets/base/gl_variables.scss
@@ -15,6 +15,12 @@
 // $gray:                   lighten($gray-base, 33.5%) // #555
 // $gray-light:             lighten($gray-base, 46.7%) // #777
 // $gray-lighter:           lighten($gray-base, 93.5%) // #eee
+$gray-base:              #000;
+$gray-darker:            lighten($gray-base, 13.5%); // #222
+$gray-dark:              #7b8a8b;   // #333
+$gray:                   #95a5a6; // #555
+$gray-light:             #b4bcc2;   // #999
+$gray-lighter:           #ecf0f1; // #eee
 
 $brand-primary:  $gl-primary;
 $brand-success:  $gl-success;
@@ -30,7 +36,7 @@ $brand-danger:   $gl-danger;
 //** Background color for ``.
 // $body-bg:               #fff
 //** Global text color on ``.
-// $text-color:            $gray-dark
+$text-color:            $brand-primary;
 
 //** Global textual link color.
 $link-color:            $gl-link-color;
@@ -187,9 +193,9 @@ $padding-base-horizontal:   14px;
 // $input-bg-disabled:              $gray-lighter
 
 //** Text color for ``s
-// $input-color:                    $gray
+$input-color:                    $text-color;
 //** `` border color
-// $input-border:                   #ccc
+$input-border:                   #dce4ec;
 
 // TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
 //** Default `.form-control` border radius
@@ -201,7 +207,7 @@ $padding-base-horizontal:   14px;
 // $input-border-radius-small:      $border-radius-small
 
 //** Border color for inputs on focus
-// $input-border-focus:             #66afe9
+$input-border-focus:             $brand-info;
 
 //** Placeholder text color
 // $input-color-placeholder:        #999
@@ -213,7 +219,7 @@ $padding-base-horizontal:   14px;
 //** Small `.form-control` height
 // $input-height-small:             (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2)
 
-// $legend-color:                   $gray-dark
+$legend-color:                   $text-color;
 // $legend-border-color:            #e5e5e5
 
 //** Background color for textual input addons
@@ -709,7 +715,7 @@ $panel-border-radius:            0;
 // $panel-inner-border:          #ddd
 // $panel-footer-bg:             #f5f5f5
 
-// $panel-default-text:          $gray-dark
+$panel-default-text:          $text-color;
 // $panel-default-border:        #ddd
 // $panel-default-heading-bg:    #f5f5f5
 
@@ -757,8 +763,8 @@ $panel-border-radius:            0;
 //
 //##
 
-// $well-bg:                     #f5f5f5
-// $well-border:                 darken($well-bg, 7%)
+$well-bg:                     $gray-lighter;
+$well-border:                 transparent;
 
 
 //== Badges
@@ -826,15 +832,15 @@ $panel-border-radius:            0;
 //
 //##
 
-// $code-color:                  #c7254e
-// $code-bg:                     #f9f2f4
+$code-color:                  #c7254e;
+$code-bg:                     #f9f2f4;
 
-// $kbd-color:                   #fff
-// $kbd-bg:                      #333
+$kbd-color:                   #fff;
+$kbd-bg:                      #333;
 
-// $pre-bg:                      #f5f5f5
-// $pre-color:                   $gray-dark
-// $pre-border-color:            #ccc
+$pre-bg:                      $gray-lighter;
+$pre-color:                   $gray-dark;
+$pre-border-color:            #ccc;
 // $pre-scrollable-max-height:   340px
 
 
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index 431f1d68a2..821cbd0890 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -319,7 +319,7 @@ table {
 }
 
 .btn-sign-in {
-  margin-top: 7px;
+  margin-top: 5px;
   text-shadow: none;
 }
 
@@ -337,8 +337,11 @@ table {
   overflow-x: auto;
 }
 
-.footer-links a {
-  margin-right: 15px;
+.footer-links {
+  margin-bottom: 20px;
+  a {
+    margin-right: 15px;
+  }
 }
 
 .search_box {
diff --git a/app/assets/stylesheets/generic/forms.scss b/app/assets/stylesheets/generic/forms.scss
index c8982cdc00..19bc11086e 100644
--- a/app/assets/stylesheets/generic/forms.scss
+++ b/app/assets/stylesheets/generic/forms.scss
@@ -29,7 +29,7 @@ fieldset legend {
   padding: 17px 20px 18px;
   margin-top: 18px;
   margin-bottom: 18px;
-  background-color: whitesmoke;
+  background-color: #ecf0f1;
   border-top: 1px solid #e5e5e5;
 }
 
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index a477359dc8..1c03f1240f 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -46,7 +46,6 @@
   border-bottom: 1px solid #eee;
   .event-title {
     @include str-truncated(72%);
-    color: #333;
     font-weight: 500;
     font-size: 14px;
     .author_name {
@@ -185,7 +184,7 @@
 }
 
 .event_filter {
-  
+
   li a {
     padding: 5px 10px;
     background: rgba(0,0,0,0.045);
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index 3305abc7d2..a4337c11ab 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -41,7 +41,7 @@
       vertical-align: middle;
 
       i {
-        color: $gl-primary;
+        color: $gl-info;
       }
 
       img {
diff --git a/app/views/layouts/_public_head_panel.html.haml b/app/views/layouts/_public_head_panel.html.haml
index bd6bb3c720..3d6d2bfc00 100644
--- a/app/views/layouts/_public_head_panel.html.haml
+++ b/app/views/layouts/_public_head_panel.html.haml
@@ -12,7 +12,7 @@
 
       - unless current_controller?('sessions')
         .pull-right.hidden-xs
-          = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-new'
+          = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-new append-right-10'
 
         .navbar-collapse.collapse
           %ul.nav.navbar-nav

From ddd381c9a51b3408cf303283c466c7f70baf7e6a Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 17:38:42 -0700
Subject: [PATCH 103/143] Add criteria for requesting CVE

---
 doc/release/security.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/release/security.md b/doc/release/security.md
index b67e0f37a0..1575fcf270 100644
--- a/doc/release/security.md
+++ b/doc/release/security.md
@@ -22,7 +22,7 @@ Please report suspected security vulnerabilities in private to 
Date: Mon, 9 Mar 2015 17:59:32 -0700
Subject: [PATCH 104/143] Fix wrong body padding and pre color

---
 app/assets/stylesheets/base/gl_variables.scss | 2 +-
 app/assets/stylesheets/base/layout.scss       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/app/assets/stylesheets/base/gl_variables.scss b/app/assets/stylesheets/base/gl_variables.scss
index 6244f7ccc0..455e009397 100644
--- a/app/assets/stylesheets/base/gl_variables.scss
+++ b/app/assets/stylesheets/base/gl_variables.scss
@@ -839,7 +839,7 @@ $kbd-color:                   #fff;
 $kbd-bg:                      #333;
 
 $pre-bg:                      $gray-lighter;
-$pre-color:                   $gray-dark;
+$pre-color:                   $text-color;
 $pre-border-color:            #ccc;
 // $pre-scrollable-max-height:   340px
 
diff --git a/app/assets/stylesheets/base/layout.scss b/app/assets/stylesheets/base/layout.scss
index 1085e68b7d..62c11b0636 100644
--- a/app/assets/stylesheets/base/layout.scss
+++ b/app/assets/stylesheets/base/layout.scss
@@ -4,7 +4,7 @@ html {
   &.touch .tooltip { display: none !important; }
 
   body {
-    padding-top: 47px;
+    padding-top: 46px;
   }
 }
 

From 86a17390dd923351ed51b9b94d34460d7a5c8214 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 18:09:23 -0700
Subject: [PATCH 105/143] Make broadcast message look like a warning by default

---
 app/assets/stylesheets/generic/common.scss | 12 ------------
 app/assets/stylesheets/pages/admin.scss    | 11 +++++++++++
 2 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index 821cbd0890..a854bd8663 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -306,18 +306,6 @@ table {
   width: 100%;
 }
 
-.broadcast-message {
-  padding: 10px;
-  text-align: center;
-  background: #555;
-  color: #BBB;
-}
-
-.broadcast-message-preview {
-  @extend .broadcast-message;
-  margin-bottom: 20px;
-}
-
 .btn-sign-in {
   margin-top: 5px;
   text-shadow: none;
diff --git a/app/assets/stylesheets/pages/admin.scss b/app/assets/stylesheets/pages/admin.scss
index a51deee797..144852e787 100644
--- a/app/assets/stylesheets/pages/admin.scss
+++ b/app/assets/stylesheets/pages/admin.scss
@@ -50,3 +50,14 @@
     line-height: 2;
   }
 }
+
+.broadcast-message {
+  @extend .alert-warning;
+  padding: 10px;
+  text-align: center;
+}
+
+.broadcast-message-preview {
+  @extend .broadcast-message;
+  margin-bottom: 20px;
+}

From 9720240be264e12aebb3b2b3b0051e587de78414 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 18:25:32 -0700
Subject: [PATCH 106/143] Increate default font-size from 13 to 14px

---
 app/assets/stylesheets/base/variables.scss        |  2 +-
 app/assets/stylesheets/generic/common.scss        |  2 +-
 app/assets/stylesheets/generic/markdown_area.scss |  2 --
 app/assets/stylesheets/generic/nav_sidebar.scss   |  2 +-
 app/assets/stylesheets/pages/commit.scss          |  9 ---------
 app/assets/stylesheets/pages/commits.scss         |  1 +
 app/assets/stylesheets/pages/events.scss          |  4 ++--
 app/assets/stylesheets/pages/help.scss            |  2 --
 app/assets/stylesheets/pages/issues.scss          |  1 +
 app/assets/stylesheets/pages/merge_requests.scss  |  1 +
 app/assets/stylesheets/pages/notes.scss           | 11 ++++-------
 11 files changed, 12 insertions(+), 25 deletions(-)

diff --git a/app/assets/stylesheets/base/variables.scss b/app/assets/stylesheets/base/variables.scss
index 30e084ecd6..54af78ee08 100644
--- a/app/assets/stylesheets/base/variables.scss
+++ b/app/assets/stylesheets/base/variables.scss
@@ -3,7 +3,7 @@ $hover: #FFF3EB;
 $box_bg: #F9F9F9;
 $gl-link-color: #446e9b;
 $nprogress-color: #c0392b;
-$gl-font-size: 13px;
+$gl-font-size: 14px;
 $list-font-size: 15px;
 $sidebar_width: 230px;
 $avatar_radius: 50%;
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index a854bd8663..af8e90eb1a 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -24,7 +24,7 @@
 
 .slead {
   color: #666;
-  font-size: 14px;
+  font-size: 15px;
   margin-bottom: 12px;
   font-weight: normal;
   line-height: 24px;
diff --git a/app/assets/stylesheets/generic/markdown_area.scss b/app/assets/stylesheets/generic/markdown_area.scss
index 22b7ce6d83..eb39b6bb7e 100644
--- a/app/assets/stylesheets/generic/markdown_area.scss
+++ b/app/assets/stylesheets/generic/markdown_area.scss
@@ -57,7 +57,6 @@
   border: 1px solid #ddd;
   min-height: 100px;
   padding: 5px;
-  font-size: 14px;
   box-shadow: none;
 }
 
@@ -83,7 +82,6 @@
   border: 1px solid #ddd;
   min-height: 100px;
   padding: 5px;
-  font-size: 14px;
   box-shadow: none;
   width: 100%;
 }
diff --git a/app/assets/stylesheets/generic/nav_sidebar.scss b/app/assets/stylesheets/generic/nav_sidebar.scss
index 335f137966..b96063827c 100644
--- a/app/assets/stylesheets/generic/nav_sidebar.scss
+++ b/app/assets/stylesheets/generic/nav_sidebar.scss
@@ -154,7 +154,7 @@
 
 .collapse-nav a {
   position: fixed;
-  top: 47px;
+  top: 46px;
   padding: 5px 13px 3px 13px;
   left: 197px;
   background: #EEE;
diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss
index 0e2d9571a4..f46d6542c0 100644
--- a/app/assets/stylesheets/pages/commit.scss
+++ b/app/assets/stylesheets/pages/commit.scss
@@ -45,15 +45,6 @@
   }
 }
 
-.commit-committer-link,
-.commit-author-link {
-  font-size: 13px;
-  color: #555;
-  &:hover {
-    color: #999;
-  }
-}
-
 .commit-box {
   margin: 10px 0;
   border-top: 1px solid #ddd;
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 683aca7359..e167d044e4 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -100,6 +100,7 @@ li.commit {
   .commit-row-info {
     color: #777;
     line-height: 24px;
+    font-size: 13px;
 
     a {
       color: #777;
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index 1c03f1240f..3e9e36e477 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -53,6 +53,7 @@
     }
   }
   .event-body {
+    font-size: 13px;
     margin-left: 35px;
     margin-right: 80px;
     color: #777;
@@ -184,11 +185,10 @@
 }
 
 .event_filter {
-
   li a {
+    font-size: 13px;
     padding: 5px 10px;
     background: rgba(0,0,0,0.045);
     margin-left: 4px;
   }
-
 }
diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss
index 07c62f98c3..6da7a2511a 100644
--- a/app/assets/stylesheets/pages/help.scss
+++ b/app/assets/stylesheets/pages/help.scss
@@ -12,7 +12,6 @@
     color: #888;
 
     a {
-      font-size: 14px;
       margin-right: 3px;
     }
   }
@@ -29,7 +28,6 @@
 
   th {
     padding-top: 15px;
-    font-size: 14px;
     line-height: 1.5;
     color: #333;
     text-align: left
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 46522e9ece..4ea34cc1da 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -11,6 +11,7 @@
 
     .issue-info {
       color: #999;
+      font-size: 13px;
     }
 
     .issue-check {
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 01f6a70522..9bd34b7376 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -96,6 +96,7 @@
 
     .merge-request-info {
       color: #999;
+      font-size: 13px;
 
       .merge-request-labels {
         display: inline-block;
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 73f23626d5..384ff6d740 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -38,13 +38,11 @@ ul.notes {
     .author {
       color: #333;
       font-weight: bold;
-      font-size: 14px;
       &:hover {
         color: $gl-link-color;
       }
     }
     .author-username {
-      font-size: 14px;
     }
   }
 
@@ -57,9 +55,6 @@ ul.notes {
   .note {
     display: block;
     position:relative;
-    .attachment {
-      font-size: 14px;
-    }
     .note-body {
       overflow: auto;
       .note-text {
@@ -184,6 +179,7 @@ ul.notes {
     margin-left: -60px;
     position: absolute;
     z-index: 10;
+    width: 32px;
 
     transition: all 0.2s ease;
 
@@ -192,8 +188,9 @@ ul.notes {
     filter: alpha(opacity=0);
 
     &:hover {
-      font-size: 24px;
-      background: $gl-primary;
+      width: 38px;
+      font-size: 20px;
+      background: $gl-info;
       color: #FFF;
       @include show-add-diff-note;
     }

From fcaf0a89e8f4be206b0378c32fd683e1cf15f804 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 18:28:30 -0700
Subject: [PATCH 107/143] Fix heading small color to darker one

---
 app/assets/stylesheets/base/gl_variables.scss | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/assets/stylesheets/base/gl_variables.scss b/app/assets/stylesheets/base/gl_variables.scss
index 455e009397..ce21ffae23 100644
--- a/app/assets/stylesheets/base/gl_variables.scss
+++ b/app/assets/stylesheets/base/gl_variables.scss
@@ -855,7 +855,7 @@ $pre-border-color:            #ccc;
 //** Abbreviations and acronyms border color
 // $abbr-border-color:           $gray-light
 //** Headings small color
-// $headings-small-color:        $gray-light
+$headings-small-color:        $gray-dark;
 //** Blockquote small color
 // $blockquote-small-color:      $gray-light
 //** Blockquote font size

From 3bce263a3d535927932a3ba174b6dfc2e41743a3 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 18:45:36 -0700
Subject: [PATCH 108/143] Reduce base vertical padding

---
 app/assets/stylesheets/base/gl_variables.scss | 2 +-
 app/assets/stylesheets/generic/selects.scss   | 4 +---
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/app/assets/stylesheets/base/gl_variables.scss b/app/assets/stylesheets/base/gl_variables.scss
index 455e009397..1db490d75f 100644
--- a/app/assets/stylesheets/base/gl_variables.scss
+++ b/app/assets/stylesheets/base/gl_variables.scss
@@ -99,7 +99,7 @@ $font-size-base:          $gl-font-size;
 //
 //## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
 
-$padding-base-vertical:     8px;
+$padding-base-vertical:     6px;
 $padding-base-horizontal:   14px;
 
 // $padding-large-vertical:    10px
diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss
index 2773ee11fd..af0ecb192d 100644
--- a/app/assets/stylesheets/generic/selects.scss
+++ b/app/assets/stylesheets/generic/selects.scss
@@ -4,10 +4,8 @@
     background: #FFF;
     border-color: #BBB;
     padding: 6px 14px;
-    font-size: 13px;
-    line-height: 18px;
+    line-height: 1.42857143;
     height: auto;
-    margin: 2px 0;
 
     .select2-arrow {
       background: #FFF;

From de629b4835f3ac6feac6bd567cee3ec79eb2b7d0 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 19:02:30 -0700
Subject: [PATCH 109/143] Blocking user does not remove him/her from
 project/groups but show blocked label

---
 CHANGELOG                                     |  1 +
 app/models/user.rb                            | 20 +------------------
 app/services/notification_service.rb          |  1 +
 app/views/admin/users/show.html.haml          |  1 -
 .../group_members/_group_member.html.haml     |  3 +++
 .../team_members/_team_member.html.haml       |  5 +++--
 6 files changed, 9 insertions(+), 22 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index b210a6b015..81468d4013 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -34,6 +34,7 @@ v 7.9.0 (unreleased)
   - Automatically link commit ranges to compare page: sha1...sha4 or sha1..sha4 (includes sha1 in comparison)
   - Move groups page from profile to dashboard
   - Starred projects page at dashboard 
+  - Blocking user does not remove him/her from project/groups but show blocked label
 
 v 7.8.2
   - Fix service migration issue when upgrading from versions prior to 7.3
diff --git a/app/models/user.rb b/app/models/user.rb
index 51dd6332fd..0d40ac8309 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -154,24 +154,6 @@ class User < ActiveRecord::Base
   delegate :path, to: :namespace, allow_nil: true, prefix: true
 
   state_machine :state, initial: :active do
-    after_transition any => :blocked do |user, transition|
-      # Remove user from all projects and
-      user.project_members.find_each do |membership|
-        # skip owned resources
-        next if membership.project.owner == user
-
-        return false unless membership.destroy
-      end
-
-      # Remove user from all groups
-      user.group_members.find_each do |membership|
-        # skip owned resources
-        next if membership.group.last_owner?(user)
-
-        return false unless membership.destroy
-      end
-    end
-
     event :block do
       transition active: :blocked
     end
@@ -626,7 +608,7 @@ class User < ActiveRecord::Base
   def contributed_projects_ids
     Event.where(author_id: self).
       where("created_at > ?", Time.now - 1.year).
-      where("action = :pushed OR (target_type = 'MergeRequest' AND action = :created)", 
+      where("action = :pushed OR (target_type = 'MergeRequest' AND action = :created)",
         pushed: Event::PUSHED, created: Event::CREATED).
       reorder(project_id: :desc).
       select(:project_id).
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 2fc63b9f4b..0063b7ce40 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -268,6 +268,7 @@ class NotificationService
   # Also remove duplications and nil recipients
   def reject_muted_users(users, project = nil)
     users = users.to_a.compact.uniq
+    users = users.reject(&:blocked?)
 
     users.reject do |user|
       next user.notification.disabled? unless project
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index bae9a97bf3..90c9f8c2f9 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -116,7 +116,6 @@
                 %ul
                   %li User will not be able to login
                   %li User will not be able to access git repositories
-                  %li User will be removed from joined projects and groups
                   %li Personal projects will be left
                   %li Owned groups will be left
                 %br
diff --git a/app/views/groups/group_members/_group_member.html.haml b/app/views/groups/group_members/_group_member.html.haml
index 30c3c2b00d..6267006f63 100644
--- a/app/views/groups/group_members/_group_member.html.haml
+++ b/app/views/groups/group_members/_group_member.html.haml
@@ -8,6 +8,9 @@
     %span.cgray= user.username
     - if user == current_user
       %span.label.label-success It's you
+    - if user.blocked?
+      %label.label.label-danger
+        %strong Blocked
 
   - if show_roles
     %span.pull-right
diff --git a/app/views/projects/team_members/_team_member.html.haml b/app/views/projects/team_members/_team_member.html.haml
index 61c50af31b..eb81544740 100644
--- a/app/views/projects/team_members/_team_member.html.haml
+++ b/app/views/projects/team_members/_team_member.html.haml
@@ -12,6 +12,7 @@
   = image_tag avatar_icon(user.email, 32), class: "avatar s32"
   %p
     %strong= user.name
+    - if user.blocked?
+      %label.label.label-danger
+        %strong Blocked
   %span.cgray= user.username
-
-

From 21c99e6a7797edb6a857e90c83fee3e5f1051adc Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets 
Date: Mon, 9 Mar 2015 19:21:42 -0700
Subject: [PATCH 110/143] Fix font size for collapse button

---
 app/assets/stylesheets/generic/nav_sidebar.scss | 1 +
 1 file changed, 1 insertion(+)

diff --git a/app/assets/stylesheets/generic/nav_sidebar.scss b/app/assets/stylesheets/generic/nav_sidebar.scss
index b96063827c..4bf2c609be 100644
--- a/app/assets/stylesheets/generic/nav_sidebar.scss
+++ b/app/assets/stylesheets/generic/nav_sidebar.scss
@@ -157,6 +157,7 @@
   top: 46px;
   padding: 5px 13px 3px 13px;
   left: 197px;
+  font-size: 13px;
   background: #EEE;
   color: black;
   border: 1px solid rgba(0,0,0,0.035);

From b26ab0ceeb60723b8a75078c4d49ed99c9ea3866 Mon Sep 17 00:00:00 2001
From: Stan Hu 
Date: Mon, 9 Mar 2015 15:10:59 -0700
Subject: [PATCH 111/143] This MR extends the commit calendar so it searches
 for commits made with every email address the user has associated with his
 account.

This fixes one of the problems mentioned in gitlab-org/gitlab-ce#1162 and makes the behavior of the commit calendar as described in the profile.
"All email addresses will be used to identify your commits."
---
 app/models/repository.rb       |  3 ++-
 spec/models/repository_spec.rb | 23 +++++++++++++++++++++++
 spec/support/repo_helpers.rb   | 19 +++++++++++++++++++
 3 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/app/models/repository.rb b/app/models/repository.rb
index 5b52739df2..6117db418a 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -146,7 +146,8 @@ class Repository
   end
 
   def timestamps_by_user_log(user)
-    args = %W(git log --author=#{user.email} --since=#{(Date.today - 1.year).to_s} --branches --pretty=format:%cd --date=short)
+    author_emails = '(' + user.all_emails.map{ |e| Regexp.escape(e) }.join('|') + ')'
+    args = %W(git log -E --author=#{author_emails} --since=#{(Date.today - 1.year).to_s} --branches --pretty=format:%cd --date=short)
     dates = Gitlab::Popen.popen(args, path_to_repo).first.split("\n")
 
     if dates.present?
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index eeb0f3d9ee..b3a38f6c5b 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -18,4 +18,27 @@ describe Repository do
 
     it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
   end
+
+  context :timestamps_by_user_log do
+    before do
+      Date.stub(:today).and_return(Date.new(2015, 03, 01))
+    end
+
+    describe 'single e-mail for user' do
+      let(:user) { create(:user, email: sample_commit.author_email) }
+
+      subject { repository.timestamps_by_user_log(user) }
+
+      it { is_expected.to eq(["2014-08-06", "2014-07-31", "2014-07-31"]) }
+    end
+
+    describe 'multiple emails for user' do
+      let(:email_alias) { create(:email, email: another_sample_commit.author_email) }
+      let(:user) { create(:user, email: sample_commit.author_email, emails: [email_alias]) }
+
+      subject { repository.timestamps_by_user_log(user) }
+
+      it { is_expected.to eq(["2015-01-10", "2014-08-06", "2014-07-31", "2014-07-31"]) }
+    end
+  end
 end
diff --git a/spec/support/repo_helpers.rb b/spec/support/repo_helpers.rb
index 4c4775da69..aadf791bf3 100644
--- a/spec/support/repo_helpers.rb
+++ b/spec/support/repo_helpers.rb
@@ -43,6 +43,25 @@ eos
     )
   end
 
+  def another_sample_commit
+    OpenStruct.new(
+        id: "e56497bb5f03a90a51293fc6d516788730953899",
+        parent_id: '4cd80ccab63c82b4bad16faa5193fbd2aa06df40',
+        author_full_name: "Sytse Sijbrandij",
+        author_email: "sytse@gitlab.com",
+        files_changed_count: 1,
+        message: <
Date: Tue, 10 Mar 2015 00:51:16 -0700
Subject: [PATCH 112/143] Improve tree view UI

---
 app/assets/stylesheets/pages/tree.scss | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index a4337c11ab..ce02cdb165 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -40,8 +40,8 @@
       max-width: 320px;
       vertical-align: middle;
 
-      i {
-        color: $gl-info;
+      i, a {
+        color: $gl-link-color;
       }
 
       img {
@@ -61,13 +61,18 @@
 
   .tree_author {
     padding-right: 8px;
+
+    .commit-author-name {
+      color: gray;
+    }
   }
 
   .tree_commit {
     color: gray;
 
     .tree-commit-link {
-      color: #444;
+      color: gray;
+
       &:hover {
         text-decoration: underline;
       }

From b7a31a4b024e2c5f607003f1c42e2cd46adb2ff4 Mon Sep 17 00:00:00 2001
From: Nicole Cordes 
Date: Wed, 3 Sep 2014 22:28:04 +0200
Subject: [PATCH 113/143] Generate valid json for hooks

It seems that ruby can handle 'nil' value but other json processors
(like PHP) throw an error. This is always generated for empty arrays.
---
 CHANGELOG                            | 1 +
 app/services/system_hooks_service.rb | 2 +-
 lib/gitlab/push_data_builder.rb      | 1 +
 3 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG b/CHANGELOG
index 81468d4013..1842a28f84 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -35,6 +35,7 @@ v 7.9.0 (unreleased)
   - Move groups page from profile to dashboard
   - Starred projects page at dashboard 
   - Blocking user does not remove him/her from project/groups but show blocked label
+  - Improve json validation in hook data
 
 v 7.8.2
   - Fix service migration issue when upgrading from versions prior to 7.3
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index 46f6e91e80..c5d0b08845 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -41,7 +41,7 @@ class SystemHooksService
         path_with_namespace: model.path_with_namespace,
         project_id: model.id,
         owner_name: owner.name,
-        owner_email: owner.respond_to?(:email) ?  owner.email : nil,
+        owner_email: owner.respond_to?(:email) ?  owner.email : "",
         project_visibility: Project.visibility_levels.key(model.visibility_level_field).downcase
       })
     when User
diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb
index 5cefa67d3a..ea06e1f733 100644
--- a/lib/gitlab/push_data_builder.rb
+++ b/lib/gitlab/push_data_builder.rb
@@ -58,6 +58,7 @@ module Gitlab
           data[:commits] << commit.hook_attrs(project)
         end
 
+        data[:commits] = "" if data[:commits].count == 0
         data
       end
 

From 6653cd7312fb4d88cc77af0d29d588c329d66cca Mon Sep 17 00:00:00 2001
From: Douwe Maan 
Date: Tue, 10 Mar 2015 11:20:57 +0100
Subject: [PATCH 114/143] Mention EmailsOnPush changes in changelog.

---
 CHANGELOG | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/CHANGELOG b/CHANGELOG
index 81468d4013..9b9e583255 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -35,6 +35,15 @@ v 7.9.0 (unreleased)
   - Move groups page from profile to dashboard
   - Starred projects page at dashboard 
   - Blocking user does not remove him/her from project/groups but show blocked label
+  - Change subject of EmailsOnPush emails to include namespace, project and branch.
+  - Change subject of EmailsOnPush emails to include first commit message when multiple were pushed.
+  - Remove confusing footer from EmailsOnPush mail body.
+  - Add list of changed files to EmailsOnPush emails. 
+  - Add option to send EmailsOnPush emails from committer email if domain matches. 
+  - Add option to disable code diffs in EmailOnPush emails.
+  - Wrap commit message in EmailsOnPush email.
+  - Send EmailsOnPush emails when deleting commits using force push.  
+  - Fix EmailsOnPush email comparison link to include first commit.
 
 v 7.8.2
   - Fix service migration issue when upgrading from versions prior to 7.3

From ed4c7190ed47f0311ba5f5a140b2c71a694b05db Mon Sep 17 00:00:00 2001
From: Valery Sizov 
Date: Fri, 6 Mar 2015 16:39:20 +0200
Subject: [PATCH 115/143] Fix importers with OCC

---
 app/controllers/import/base_controller.rb      | 18 ++++++++----------
 ...0306023112_add_unique_index_to_namespace.rb |  9 +++++++++
 db/schema.rb                                   |  8 ++++----
 3 files changed, 21 insertions(+), 14 deletions(-)
 create mode 100644 db/migrate/20150306023112_add_unique_index_to_namespace.rb

diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb
index 7dc0cac8d4..edb8bd4160 100644
--- a/app/controllers/import/base_controller.rb
+++ b/app/controllers/import/base_controller.rb
@@ -3,19 +3,17 @@ class Import::BaseController < ApplicationController
   private
 
   def get_or_create_namespace
-    existing_namespace = Namespace.find_by_path_or_name(@target_namespace)
-
-    if existing_namespace
-      if existing_namespace.owner == current_user
-        namespace = existing_namespace
-      else
+    begin
+      namespace = Group.create!(name: @target_namespace, path: @target_namespace, owner: current_user)
+      namespace.add_owner(current_user)
+    rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
+      namespace = Namespace.find_by_path_or_name(@target_namespace)
+      unless namespace.owner == current_user
         @already_been_taken = true
         return false
       end
-    else
-      namespace = Group.create(name: @target_namespace, path: @target_namespace, owner: current_user)
-      namespace.add_owner(current_user)
-      namespace
     end
+
+    namespace
   end
 end
diff --git a/db/migrate/20150306023112_add_unique_index_to_namespace.rb b/db/migrate/20150306023112_add_unique_index_to_namespace.rb
new file mode 100644
index 0000000000..b1f7822b4d
--- /dev/null
+++ b/db/migrate/20150306023112_add_unique_index_to_namespace.rb
@@ -0,0 +1,9 @@
+class AddUniqueIndexToNamespace < ActiveRecord::Migration
+  def change
+    remove_index :namespaces, :name
+    remove_index :namespaces, :path
+
+    add_index :namespaces, :name, unique: true
+    add_index :namespaces, :path, unique: true
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index a686bb4b3c..3afbc082b7 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20150225065047) do
+ActiveRecord::Schema.define(version: 20150306023112) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -242,9 +242,9 @@ ActiveRecord::Schema.define(version: 20150225065047) do
   end
 
   add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree
-  add_index "namespaces", ["name"], name: "index_namespaces_on_name", using: :btree
+  add_index "namespaces", ["name"], name: "index_namespaces_on_name", unique: true, using: :btree
   add_index "namespaces", ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree
-  add_index "namespaces", ["path"], name: "index_namespaces_on_path", using: :btree
+  add_index "namespaces", ["path"], name: "index_namespaces_on_path", unique: true, using: :btree
   add_index "namespaces", ["type"], name: "index_namespaces_on_type", using: :btree
 
   create_table "notes", force: true do |t|
@@ -334,12 +334,12 @@ ActiveRecord::Schema.define(version: 20150225065047) do
     t.string   "import_url"
     t.integer  "visibility_level",       default: 0,        null: false
     t.boolean  "archived",               default: false,    null: false
-    t.string   "avatar"
     t.string   "import_status"
     t.float    "repository_size",        default: 0.0
     t.integer  "star_count",             default: 0,        null: false
     t.string   "import_type"
     t.string   "import_source"
+    t.string   "avatar"
   end
 
   add_index "projects", ["created_at", "id"], name: "index_projects_on_created_at_and_id", using: :btree

From 383c56efa1882d9cab956de5b5b72e51691c3f0c Mon Sep 17 00:00:00 2001
From: Douwe Maan 
Date: Tue, 10 Mar 2015 11:51:36 +0100
Subject: [PATCH 116/143] Use Gitlab::Git helper methods and constants as much
 as possible.

---
 app/controllers/projects/tags_controller.rb   |  2 +-
 app/mailers/emails/projects.rb                |  2 +-
 app/models/event.rb                           | 12 +++++------
 app/models/project_services/asana_service.rb  |  2 +-
 .../project_services/campfire_service.rb      |  6 +++---
 .../project_services/hipchat_service.rb       | 13 ++++--------
 .../project_services/pushover_service.rb      |  6 +++---
 .../slack_service/push_message.rb             | 13 ++++--------
 .../project_services/teamcity_service.rb      |  2 +-
 app/services/create_tag_service.rb            |  4 ++--
 app/services/event_create_service.rb          |  8 ++++----
 app/services/git_push_service.rb              | 16 +++++----------
 .../merge_requests/refresh_service.rb         |  4 ++--
 app/workers/emails_on_push_worker.rb          |  2 +-
 app/workers/irker_worker.rb                   |  6 +++---
 app/workers/post_receive.rb                   |  8 +-------
 lib/gitlab/git.rb                             | 20 +++++++++++++++++--
 lib/gitlab/git_access.rb                      | 10 +++++-----
 lib/gitlab/push_data_builder.rb               |  7 ++++---
 .../project_services/hipchat_service_spec.rb  |  2 +-
 .../slack_service/push_message_spec.rb        |  6 +++---
 21 files changed, 73 insertions(+), 78 deletions(-)

diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 08c7ce3f37..03fface2d2 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -27,7 +27,7 @@ class Projects::TagsController < Projects::ApplicationController
     tag = @repository.find_tag(params[:id])
 
     if tag && @repository.rm_tag(tag.name)
-      EventCreateService.new.push_ref(@project, current_user, tag, 'rm', 'refs/tags')
+      EventCreateService.new.push_ref(@project, current_user, tag, 'rm', Gitlab::Git::TAG_REF_PREFIX)
     end
 
     respond_to do |format|
diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb
index 9ea121d83a..b55129de29 100644
--- a/app/mailers/emails/projects.rb
+++ b/app/mailers/emails/projects.rb
@@ -23,7 +23,7 @@ module Emails
       @compare = compare
       @commits = Commit.decorate(compare.commits)
       @diffs   = compare.diffs
-      @branch  = branch.gsub("refs/heads/", "")
+      @branch  = Gitlab::Git.ref_name(branch)
       @disable_diffs = disable_diffs
 
       @subject = "[#{@project.path_with_namespace}][#{@branch}] "
diff --git a/app/models/event.rb b/app/models/event.rb
index 5579ab1dbb..8d20d7ef25 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -190,19 +190,19 @@ class Event < ActiveRecord::Base
   end
 
   def tag?
-    data[:ref]["refs/tags"]
+    Gitlab::Git.tag_ref?(data[:ref])
   end
 
   def branch?
-    data[:ref]["refs/heads"]
+    Gitlab::Git.branch_ref?(data[:ref])
   end
 
   def new_ref?
-    commit_from =~ /^00000/
+    Gitlab::Git.blank_ref?(commit_from)
   end
 
   def rm_ref?
-    commit_to =~ /^00000/
+    Gitlab::Git.blank_ref?(commit_to)
   end
 
   def md_ref?
@@ -226,11 +226,11 @@ class Event < ActiveRecord::Base
   end
 
   def branch_name
-    @branch_name ||= data[:ref].gsub("refs/heads/", "")
+    @branch_name ||= Gitlab::Git.ref_name(data[:ref])
   end
 
   def tag_name
-    @tag_name ||= data[:ref].gsub("refs/tags/", "")
+    @tag_name ||= Gitlab::Git.ref_name(data[:ref])
   end
 
   # Max 20 commits from push DESC
diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb
index 6a62220738..d52214cdd6 100644
--- a/app/models/project_services/asana_service.rb
+++ b/app/models/project_services/asana_service.rb
@@ -77,7 +77,7 @@ automatically inspected. Leave blank to include all branches.'
     end
 
     user = data[:user_name]
-    branch = data[:ref].gsub('refs/heads/', '')
+    branch = Gitlab::Git.ref_name(data[:ref])
 
     branch_restriction = restrict_to_branch.to_s
 
diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb
index 1c63444fbf..e591afdda6 100644
--- a/app/models/project_services/campfire_service.rb
+++ b/app/models/project_services/campfire_service.rb
@@ -64,7 +64,7 @@ class CampfireService < Service
   end
 
   def build_message(push)
-    ref = push[:ref].gsub("refs/heads/", "")
+    ref = Gitlab::Git.ref_name(push[:ref])
     before = push[:before]
     after = push[:after]
 
@@ -72,9 +72,9 @@ class CampfireService < Service
     message << "[#{project.name_with_namespace}] "
     message << "#{push[:user_name]} "
 
-    if before.include?('000000')
+    if Gitlab::Git.blank_ref?(before)
       message << "pushed new branch #{ref} \n"
-    elsif after.include?('000000')
+    elsif Gitlab::Git.blank_ref?(after)
       message << "removed branch #{ref} \n"
     else
       message << "pushed #{push[:total_commits_count]} commits to #{ref}. "
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index 90ba7e080f..d264a56ebd 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -79,24 +79,19 @@ class HipchatService < Service
   end
 
   def create_push_message(push)
-    if push[:ref].starts_with?('refs/tags/')
-      ref_type = 'tag'
-      ref = push[:ref].gsub('refs/tags/', '')
-    else
-      ref_type = 'branch'
-      ref = push[:ref].gsub('refs/heads/', '')
-    end
+    ref_type = Gitlab::Git.tag_ref?(push[:ref]) ? 'tag' : 'branch'
+    ref = Gitlab::Git.ref_name(push[:ref])
 
     before = push[:before]
     after = push[:after]
 
     message = ""
     message << "#{push[:user_name]} "
-    if before.include?('000000')
+    if Gitlab::Git.blank_ref?(before)
       message << "pushed new #{ref_type} #{ref}"\
                  " to #{project_link}\n"
-    elsif after.include?('000000')
+    elsif Gitlab::Git.blank_ref?(after)
       message << "removed #{ref_type} #{ref} from #{project_name} \n"
     else
       message << "pushed to #{ref_type} "\
diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb
index 8cd65724cb..dfc5677c9d 100644
--- a/app/services/create_tag_service.rb
+++ b/app/services/create_tag_service.rb
@@ -21,7 +21,7 @@ class CreateTagService < BaseService
     new_tag = repository.find_tag(tag_name)
 
     if new_tag
-      EventCreateService.new.push_ref(project, current_user, new_tag, 'add', 'refs/tags')
+      EventCreateService.new.push_ref(project, current_user, new_tag, 'add', Gitlab::Git::TAG_REF_PREFIX)
 
       push_data = create_push_data(project, current_user, new_tag)
       project.execute_hooks(push_data.dup, :tag_push_hooks)
@@ -41,7 +41,7 @@ class CreateTagService < BaseService
 
   def create_push_data(project, user, tag)
     data = Gitlab::PushDataBuilder.
-      build(project, user, Gitlab::Git::BLANK_SHA, tag.target, 'refs/tags/' + tag.name, [])
+      build(project, user, Gitlab::Git::BLANK_SHA, tag.target, "#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}", [])
     data[:object_kind] = "tag_push"
     data
   end
diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb
index ba9547b924..dc52d6d89d 100644
--- a/app/services/event_create_service.rb
+++ b/app/services/event_create_service.rb
@@ -62,19 +62,19 @@ class EventCreateService
     create_event(project, current_user, Event::CREATED)
   end
 
-  def push_ref(project, current_user, ref, action = 'add', prefix = 'refs/heads')
+  def push_ref(project, current_user, ref, action = 'add', prefix = Gitlab::Git::BRANCH_REF_PREFIX)
     commit = project.repository.commit(ref.target)
 
     if action.to_s == 'add'
-      before = '00000000'
+      before = Gitlab::Git::BLANK_SHA
       after = commit.id
     else
       before = commit.id
-      after = '00000000'
+      after = Gitlab::Git::BLANK_SHA
     end
 
     data = {
-      ref: "#{prefix}/#{ref.name}",
+      ref: "#{prefix}#{ref.name}",
       before: before,
       after: after
     }
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 4e1afea6d5..bfabfd7ade 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -107,30 +107,24 @@ class GitPushService
   end
 
   def push_to_existing_branch?(ref, oldrev)
-    ref_parts = ref.split('/')
-
     # Return if this is not a push to a branch (e.g. new commits)
-    ref_parts[1].include?('heads') && oldrev != Gitlab::Git::BLANK_SHA
+    Gitlab::Git.branch_ref?(ref) && oldrev != Gitlab::Git::BLANK_SHA
   end
 
   def push_to_new_branch?(ref, oldrev)
-    ref_parts = ref.split('/')
-
-    ref_parts[1].include?('heads') && oldrev == Gitlab::Git::BLANK_SHA
+    Gitlab::Git.branch_ref?(ref) && Gitlab::Git.blank_ref?(oldrev)
   end
 
   def push_remove_branch?(ref, newrev)
-    ref_parts = ref.split('/')
-
-    ref_parts[1].include?('heads') && newrev == Gitlab::Git::BLANK_SHA
+    Gitlab::Git.branch_ref?(ref) && Gitlab::Git.blank_ref?(newrev)
   end
 
   def push_to_branch?(ref)
-    ref.include?('refs/heads')
+    Gitlab::Git.branch_ref?(ref)
   end
 
   def is_default_branch?(ref)
-    ref == "refs/heads/#{project.default_branch}"
+    Gitlab::Git.branch_ref?(ref) && Gitlab::Git.ref_name(ref) == project.default_branch
   end
 
   def commit_user(commit)
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index ea84647276..cab8a1e880 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -1,10 +1,10 @@
 module MergeRequests
   class RefreshService < MergeRequests::BaseService
     def execute(oldrev, newrev, ref)
-      return true unless ref =~ /heads/
+      return true unless Gitlab::Git.branch_ref?(ref)
 
       @oldrev, @newrev = oldrev, newrev
-      @branch_name = ref.gsub("refs/heads/", "")
+      @branch_name = Gitlab::Git.ref_name(ref)
       @fork_merge_requests = @project.fork_merge_requests.opened
       @commits = @project.repository.commits_between(oldrev, newrev)
 
diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb
index 2e78381482..e59ca81def 100644
--- a/app/workers/emails_on_push_worker.rb
+++ b/app/workers/emails_on_push_worker.rb
@@ -8,7 +8,7 @@ class EmailsOnPushWorker
     branch = push_data["ref"]
     author_id = push_data["user_id"]
 
-    if before_sha =~ /^000000/ || after_sha =~ /^000000/
+    if Gitlab::Git.blank_ref?(before_sha) || Gitlab::Git.blank_ref?(after_sha)
       # skip if new branch was pushed or branch was removed
       return true
     end
diff --git a/app/workers/irker_worker.rb b/app/workers/irker_worker.rb
index 613bae351d..e1a99d9cad 100644
--- a/app/workers/irker_worker.rb
+++ b/app/workers/irker_worker.rb
@@ -57,9 +57,9 @@ class IrkerWorker
   end
 
   def send_branch_updates(push_data, project, repo_name, committer, branch)
-    if push_data['before'] =~ /^000000/
+    if push_data['before'] == Gitlab::Git::BLANK_SHA
       send_new_branch project, repo_name, committer, branch
-    elsif push_data['after'] =~ /^000000/
+    elsif push_data['after'] == Gitlab::Git::BLANK_SHA
       send_del_branch repo_name, committer, branch
     end
   end
@@ -83,7 +83,7 @@ class IrkerWorker
     return if push_data['total_commits_count'] == 0
 
     # Next message is for number of commit pushed, if any
-    if push_data['before'] =~ /^000000/
+    if push_data['before'] == Gitlab::Git::BLANK_SHA
       # Tweak on push_data["before"] in order to have a nice compare URL
       push_data['before'] = before_on_new_branch push_data, project
     end
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index 1406cba2db..ecc6c8e53a 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -33,7 +33,7 @@ class PostReceive
         return false
       end
 
-      if tag?(ref)
+      if Gitlab::Git.tag_ref?(ref)
         GitTagPushService.new.execute(project, @user, oldrev, newrev, ref)
       else
         GitPushService.new.execute(project, @user, oldrev, newrev, ref)
@@ -44,10 +44,4 @@ class PostReceive
   def log(message)
     Gitlab::GitLogger.error("POST-RECEIVE: #{message}")
   end
-
-  private
-
-  def tag?(ref)
-    !!(/refs\/tags\/(.*)/.match(ref))
-  end
 end
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index 4a712c6345..0c350d7c67 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -1,9 +1,25 @@
 module Gitlab
   module Git
     BLANK_SHA = '0' * 40
+    TAG_REF_PREFIX = "refs/tags/"
+    BRANCH_REF_PREFIX = "refs/heads/"
 
-    def self.extract_ref_name(ref)
-      ref.gsub(/\Arefs\/(tags|heads)\//, '')
+    class << self
+      def ref_name(ref)
+        ref.gsub(/\Arefs\/(tags|heads)\//, '')
+      end
+
+      def tag_ref?(ref)
+        ref.start_with?(TAG_REF_PREFIX)
+      end
+
+      def branch_ref?(ref)
+        ref.start_with?(BRANCH_REF_PREFIX)
+      end
+
+      def blank_ref?(ref)
+        ref == BLANK_SHA
+      end
     end
   end
 end
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index 9b31190a88..cb69e4b13d 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -115,7 +115,7 @@ module Gitlab
       # we dont allow force push to protected branch
       if forced_push?(project, oldrev, newrev)
         :force_push_code_to_protected_branches
-      elsif newrev == Gitlab::Git::BLANK_SHA
+      elsif Gitlab::Git.blank_ref?(newrev)
         # and we dont allow remove of protected branch
         :remove_protected_branches
       elsif project.developers_can_push_to_protected_branch?(branch_name)
@@ -135,8 +135,8 @@ module Gitlab
 
     def branch_name(ref)
       ref = ref.to_s
-      if ref.start_with?('refs/heads')
-        ref.sub(%r{\Arefs/heads/}, '')
+      if Gitlab::Git.branch_ref?(ref)
+        Gitlab::Git.ref_name(ref)
       else
         nil
       end
@@ -144,8 +144,8 @@ module Gitlab
 
     def tag_name(ref)
       ref = ref.to_s
-      if ref.start_with?('refs/tags')
-        ref.sub(%r{\Arefs/tags/}, '')
+      if Gitlab::Git.tag_ref?(ref)
+        Gitlab::Git.ref_name(ref)
       else
         nil
       end
diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb
index 5cefa67d3a..9fb0bf6594 100644
--- a/lib/gitlab/push_data_builder.rb
+++ b/lib/gitlab/push_data_builder.rb
@@ -65,12 +65,13 @@ module Gitlab
       # existing project and commits to test web hooks
       def build_sample(project, user)
         commits = project.repository.commits(project.default_branch, nil, 3)
-        build(project, user, commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", commits)
+        ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{project.default_branch}"
+        build(project, user, commits.last.id, commits.first.id, ref, commits)
       end
 
       def checkout_sha(repository, newrev, ref)
-        if newrev != Gitlab::Git::BLANK_SHA && ref.start_with?('refs/tags/')
-          tag_name = Gitlab::Git.extract_ref_name(ref)
+        if newrev != Gitlab::Git::BLANK_SHA && Gitlab::Git.tag_ref?(ref)
+          tag_name = Gitlab::Git.ref_name(ref)
           tag = repository.find_tag(tag_name)
 
           if tag
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index b9f2bee148..8ab847e643 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -63,7 +63,7 @@ describe HipchatService do
     end
 
     context 'tag_push events' do
-      let(:push_sample_data) { Gitlab::PushDataBuilder.build(project, user, '000000', '111111', 'refs/tags/test', []) }
+      let(:push_sample_data) { Gitlab::PushDataBuilder.build(project, user, Gitlab::Git::BLANK_SHA, '1' * 40, 'refs/tags/test', []) }
 
       it "should call Hipchat API for tag push events" do
         hipchat.execute(push_sample_data)
diff --git a/spec/models/project_services/slack_service/push_message_spec.rb b/spec/models/project_services/slack_service/push_message_spec.rb
index 3ef065459d..10963481a1 100644
--- a/spec/models/project_services/slack_service/push_message_spec.rb
+++ b/spec/models/project_services/slack_service/push_message_spec.rb
@@ -43,7 +43,7 @@ describe SlackService::PushMessage do
     let(:args) {
       {
           after: 'after',
-          before: '000000',
+          before: Gitlab::Git::BLANK_SHA,
           project_name: 'project_name',
           ref: 'refs/tags/new_tag',
           user_name: 'user_name',
@@ -61,7 +61,7 @@ describe SlackService::PushMessage do
 
   context 'new branch' do
     before do
-      args[:before] = '000000'
+      args[:before] = Gitlab::Git::BLANK_SHA
     end
 
     it 'returns a message regarding a new branch' do
@@ -75,7 +75,7 @@ describe SlackService::PushMessage do
 
   context 'removed branch' do
     before do
-      args[:after] = '000000'
+      args[:after] = Gitlab::Git::BLANK_SHA
     end
 
     it 'returns a message regarding a removed branch' do

From 76842aac754e2355c34e751002fcbb1e8187e344 Mon Sep 17 00:00:00 2001
From: Douwe Maan 
Date: Tue, 10 Mar 2015 14:06:15 +0100
Subject: [PATCH 117/143] Properly move over `issues_tracker_id` from old
 custom issue tracker URLs.

---
 app/models/project_services/issue_tracker_service.rb | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index 16876335b6..0c734a544d 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -60,9 +60,9 @@ class IssueTrackerService < Service
       if enabled_in_gitlab_config
         self.properties = {
           title: issues_tracker['title'],
-          project_url: set_project_url,
-          issues_url: issues_tracker['issues_url'],
-          new_issue_url: issues_tracker['new_issue_url']
+          project_url: add_issues_tracker_id(issues_tracker['project_url']),
+          issues_url: add_issues_tracker_id(issues_tracker['issues_url']),
+          new_issue_url: add_issues_tracker_id(issues_tracker['new_issue_url'])
         }
       else
         self.properties = {}
@@ -111,15 +111,15 @@ class IssueTrackerService < Service
     Gitlab.config.issues_tracker[to_param]
   end
 
-  def set_project_url
+  def add_issues_tracker_id(url)
     if self.project
       id = self.project.issues_tracker_id
 
       if id
-        issues_tracker['project_url'].gsub(":issues_tracker_id", id)
+        url = url.gsub(":issues_tracker_id", id)
       end
     end
 
-    issues_tracker['project_url']
+    url
   end
 end

From ee45fa89b62bd11b397f84e9ed42ee78dadabd20 Mon Sep 17 00:00:00 2001
From: Ben Carson 
Date: Mon, 9 Mar 2015 16:45:35 -0400
Subject: [PATCH 118/143] Added a link_to for the LinkedIn portion of the
 user's profile. It felt odd to me, having this section not being an active
 link like the rest of the entries on the page.

---
 app/views/users/_profile.html.haml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/views/users/_profile.html.haml b/app/views/users/_profile.html.haml
index 3b44959baa..0a70b73807 100644
--- a/app/views/users/_profile.html.haml
+++ b/app/views/users/_profile.html.haml
@@ -12,7 +12,7 @@
     - unless user.linkedin.blank?
       %li
         %span.light LinkedIn:
-        %strong= user.linkedin
+        %strong= link_to user.linkedin, "http://www.linkedin.com/in/#{user.linkedin}"
     - unless user.twitter.blank?
       %li
         %span.light Twitter:

From 4218a2bfcf7a3f864268c3eafe8ead28bb7808d8 Mon Sep 17 00:00:00 2001
From: Stan Hu 
Date: Fri, 27 Feb 2015 17:17:57 -0800
Subject: [PATCH 119/143] Fix code preview theme setting for comments, issues,
 merge requests, and snippets. Also preserve code preview color scheme in
 events dashboard.

Assign default colors to all code blocks shown as 

Closes #1139
---
 CHANGELOG                                            |  1 +
 app/assets/stylesheets/highlight/dark.scss           |  4 ++++
 app/assets/stylesheets/highlight/monokai.scss        |  4 ++++
 app/assets/stylesheets/highlight/solarized_dark.scss |  4 ++++
 .../stylesheets/highlight/solarized_light.scss       |  4 ++++
 app/assets/stylesheets/highlight/white.scss          |  4 ++++
 app/helpers/events_helper.rb                         |  2 +-
 app/helpers/gitlab_markdown_helper.rb                |  4 +++-
 lib/redcarpet/render/gitlab_html.rb                  |  5 +++--
 spec/helpers/events_helper_spec.rb                   | 12 ++++++++++++
 10 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 81468d4013..0ffdbc8391 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,7 @@ v 7.9.0 (unreleased)
   - Add issue and merge request events to HipChat and Slack services (Stan Hu)
   - Fix merge request URL passed to Webhooks. (Stan Hu)
   - Fix bug that caused a server error when editing a comment to "+1" or "-1" (Stan Hu)
+  - Fix code preview theme setting for comments, issues, merge requests, and snippets (Stan Hu)
   - Move labels/milestones tabs to sidebar
   - Upgrade Rails gem to version 4.1.9.
   - Improve error messages for file edit failures
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index fcd4d47bac..01e12323c7 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -1,6 +1,10 @@
 /* https://github.com/MozMorris/tomorrow-pygments */
+pre.code.highlight.dark,
 .code.dark {
 
+  background-color: #1d1f21;
+  color: #c5c8c6;
+
   pre.code,
   .line-numbers,
   .line-numbers a {
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index bcd2e71665..e7d62a7ca1 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -1,6 +1,10 @@
 /* https://github.com/richleland/pygments-css/blob/master/monokai.css */
+pre.code.monokai,
 .code.monokai {
 
+  background: #272822;
+  color: #f8f8f2;
+
   pre.highlight,
   .line-numbers,
   .line-numbers a {
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index 4a6b759bd2..de2676e39c 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -1,6 +1,10 @@
 /* https://gist.github.com/qguv/7936275 */
+pre.code.highlight.solarized-dark,
 .code.solarized-dark {
 
+  background-color: #002b36;
+  color: #93a1a1;
+
   pre.code,
   .line-numbers,
   .line-numbers a {
diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss
index 7254f4d7ac..784e768914 100644
--- a/app/assets/stylesheets/highlight/solarized_light.scss
+++ b/app/assets/stylesheets/highlight/solarized_light.scss
@@ -1,6 +1,10 @@
 /* https://gist.github.com/qguv/7936275 */
+pre.code.highlight.solarized-light,
 .code.solarized-light {
 
+  background-color: #fdf6e3;
+  color: #586e75;
+
   pre.code,
   .line-numbers,
   .line-numbers a {
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index 4d6f5dfd91..9b9b0a6bd6 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -1,6 +1,10 @@
 /* https://github.com/aahan/pygments-github-style */
+pre.code.highlight.white,
 .code.white {
 
+  background-color: #fff;
+  color: #333;
+
   pre.highlight,
   .line-numbers,
   .line-numbers a {
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index d38b546e1b..779cebc013 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -166,7 +166,7 @@ module EventsHelper
 
   def event_note(text)
     text = first_line_in_markdown(text, 150)
-    sanitize(text, tags: %w(a img b pre code p))
+    sanitize(text, tags: %w(a img b pre code p span))
   end
 
   def event_commit_title(message)
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index ab30f498c0..daaefe90f1 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -31,7 +31,9 @@ module GitlabMarkdownHelper
   def markdown(text, options={})
     unless (@markdown and options == @options)
       @options = options
-      gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self, {
+      gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self,
+                                                          user_color_scheme_class,
+                                                          {
                             # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
                             filter_html: true,
                             with_toc_data: true,
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
index 714261f815..713d7c39a1 100644
--- a/lib/redcarpet/render/gitlab_html.rb
+++ b/lib/redcarpet/render/gitlab_html.rb
@@ -3,8 +3,9 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
   attr_reader :template
   alias_method :h, :template
 
-  def initialize(template, options = {})
+  def initialize(template, color_scheme, options = {})
     @template = template
+    @color_scheme = color_scheme
     @project = @template.instance_variable_get("@project")
     @options = options.dup
     super options
@@ -34,7 +35,7 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
     end
 
     formatter = Rugments::Formatters::HTML.new(
-      cssclass: "code highlight white #{lexer.tag}"
+      cssclass: "code highlight #{@color_scheme} #{lexer.tag}"
     )
     formatter.format(lexer.lex(code))
   end
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index c4a192ac1a..b392371deb 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -4,6 +4,8 @@ describe EventsHelper do
   include ApplicationHelper
   include GitlabMarkdownHelper
 
+  let(:current_user) { create(:user, email: "current@email.com") }
+
   it 'should display one line of plain text without alteration' do
     input = 'A short, plain note'
     expect(event_note(input)).to match(input)
@@ -50,4 +52,14 @@ describe EventsHelper do
     expect(event_note(input)).to match(link_url)
     expect(event_note(input)).to match(expected_link_text)
   end
+
+  it 'should preserve code color scheme' do
+    input = "```ruby\ndef test\n  'hello world'\nend\n```"
+    expected = '
' \
+      "def test\n" \
+      "  \'hello world\'\n" \
+      "end\n" \
+      '
' + expect(event_note(input)).to eq(expected) + end end From 1fec4eff361fed0fecd2928ef83d928fab5e1976 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 10 Mar 2015 16:06:58 +0000 Subject: [PATCH 120/143] Upgrade Docker image to GitLab v7.8.3 --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 3584a754c6..4eb280f955 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -11,7 +11,7 @@ RUN apt-get update -q \ # If the Omnibus package version below is outdated please contribute a merge request to update it. # If you run GitLab Enterprise Edition point it to a location where you have downloaded it. RUN TMP_FILE=$(mktemp); \ - wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.8.1-omnibus-1_amd64.deb \ + wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.8.3-omnibus-1_amd64.deb \ && dpkg -i $TMP_FILE \ && rm -f $TMP_FILE From f5e42f602f8a4eb85a7087bc0f407f9510df0ea8 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 10 Mar 2015 14:50:42 +0100 Subject: [PATCH 121/143] Reject access to group/project avatar if the user doesn't have access. --- CHANGELOG | 1 + app/controllers/uploads_controller.rb | 48 ++-- spec/controllers/uploads_controller_spec.rb | 296 ++++++++++++++++++++ 3 files changed, 329 insertions(+), 16 deletions(-) create mode 100644 spec/controllers/uploads_controller_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 81468d4013..03fd68e299 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -35,6 +35,7 @@ v 7.9.0 (unreleased) - Move groups page from profile to dashboard - Starred projects page at dashboard - Blocking user does not remove him/her from project/groups but show blocked label + - Reject access to group/project avatar if the user doesn't have access. v 7.8.2 - Fix service migration issue when upgrading from versions prior to 7.3 diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index 810ac9f34b..c5f3da54ea 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -1,24 +1,15 @@ class UploadsController < ApplicationController - skip_before_filter :authenticate_user!, :reject_blocked! - before_filter :authorize_access + skip_before_filter :authenticate_user! + before_filter :find_model, :authorize_access! def show - unless upload_model && upload_mount - return not_found! - end - - model = upload_model.find(params[:id]) - uploader = model.send(upload_mount) - - if model.respond_to?(:project) && !can?(current_user, :read_project, model.project) - return not_found! - end + uploader = @model.send(upload_mount) unless uploader.file_storage? return redirect_to uploader.url end - unless uploader.file.exists? + unless uploader.file && uploader.file.exists? return not_found! end @@ -28,9 +19,34 @@ class UploadsController < ApplicationController private - def authorize_access - unless params[:mounted_as] == 'avatar' - authenticate_user! && reject_blocked! + def find_model + unless upload_model && upload_mount + return not_found! + end + + @model = upload_model.find(params[:id]) + end + + def authorize_access! + authorized = + case @model + when Project + can?(current_user, :read_project, @model) + when Group + can?(current_user, :read_group, @model) + when Note + can?(current_user, :read_project, @model.project) + else + # No authentication required for user avatars. + true + end + + return if authorized + + if current_user + not_found! + else + authenticate_user! end end diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb new file mode 100644 index 0000000000..0f9780356b --- /dev/null +++ b/spec/controllers/uploads_controller_spec.rb @@ -0,0 +1,296 @@ +require 'spec_helper' + +describe UploadsController do + let!(:user) { create(:user, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } + + describe "GET show" do + context "when viewing a user avatar" do + context "when signed in" do + before do + sign_in(user) + end + + context "when the user is blocked" do + before do + user.block + end + + it "redirects to the sign in page" do + get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "image.png" + + expect(response).to redirect_to(new_user_session_path) + end + end + + context "when the user isn't blocked" do + it "responds with status 200" do + get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "image.png" + + expect(response.status).to eq(200) + end + end + end + + context "when not signed in" do + it "responds with status 200" do + get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "image.png" + + expect(response.status).to eq(200) + end + end + end + + context "when viewing a project avatar" do + let!(:project) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } + + context "when the project is public" do + before do + project.update_attribute(:visibility_level, Project::PUBLIC) + end + + context "when not signed in" do + it "responds with status 200" do + get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png" + + expect(response.status).to eq(200) + end + end + + context "when signed in" do + before do + sign_in(user) + end + + it "responds with status 200" do + get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png" + + expect(response.status).to eq(200) + end + end + end + + context "when the project is private" do + before do + project.update_attribute(:visibility_level, Project::PRIVATE) + end + + context "when not signed in" do + it "redirects to the sign in page" do + get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png" + + expect(response).to redirect_to(new_user_session_path) + end + end + + context "when signed in" do + before do + sign_in(user) + end + + context "when the user has access to the project" do + before do + project.team << [user, :master] + end + + context "when the user is blocked" do + before do + user.block + project.team << [user, :master] + end + + it "redirects to the sign in page" do + get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png" + + expect(response).to redirect_to(new_user_session_path) + end + end + + context "when the user isn't blocked" do + it "responds with status 200" do + get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png" + + expect(response.status).to eq(200) + end + end + end + + context "when the user doesn't have access to the project" do + it "responds with status 404" do + get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png" + + expect(response.status).to eq(404) + end + end + end + end + end + + context "when viewing a group avatar" do + let!(:group) { create(:group, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } + let!(:project) { create(:project, namespace: group) } + + context "when the group has public projects" do + before do + project.update_attribute(:visibility_level, Project::PUBLIC) + end + + context "when not signed in" do + it "responds with status 200" do + get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png" + + expect(response.status).to eq(200) + end + end + + context "when signed in" do + before do + sign_in(user) + end + + it "responds with status 200" do + get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png" + + expect(response.status).to eq(200) + end + end + end + + context "when the project doesn't have public projects" do + context "when not signed in" do + it "redirects to the sign in page" do + get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png" + + expect(response).to redirect_to(new_user_session_path) + end + end + + context "when signed in" do + before do + sign_in(user) + end + + context "when the user has access to the project" do + before do + project.team << [user, :master] + end + + context "when the user is blocked" do + before do + user.block + project.team << [user, :master] + end + + it "redirects to the sign in page" do + get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png" + + expect(response).to redirect_to(new_user_session_path) + end + end + + context "when the user isn't blocked" do + it "responds with status 200" do + get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png" + + expect(response.status).to eq(200) + end + end + end + + context "when the user doesn't have access to the project" do + it "responds with status 404" do + get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png" + + expect(response.status).to eq(404) + end + end + end + end + end + + context "when viewing a note attachment" do + let!(:note) { create(:note, :with_attachment) } + let(:project) { note.project } + + context "when the project is public" do + before do + project.update_attribute(:visibility_level, Project::PUBLIC) + end + + context "when not signed in" do + it "responds with status 200" do + get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png" + + expect(response.status).to eq(200) + end + end + + context "when signed in" do + before do + sign_in(user) + end + + it "responds with status 200" do + get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png" + + expect(response.status).to eq(200) + end + end + end + + context "when the project is private" do + before do + project.update_attribute(:visibility_level, Project::PRIVATE) + end + + context "when not signed in" do + it "redirects to the sign in page" do + get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png" + + expect(response).to redirect_to(new_user_session_path) + end + end + + context "when signed in" do + before do + sign_in(user) + end + + context "when the user has access to the project" do + before do + project.team << [user, :master] + end + + context "when the user is blocked" do + before do + user.block + project.team << [user, :master] + end + + it "redirects to the sign in page" do + get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png" + + expect(response).to redirect_to(new_user_session_path) + end + end + + context "when the user isn't blocked" do + it "responds with status 200" do + get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png" + + expect(response.status).to eq(200) + end + end + end + + context "when the user doesn't have access to the project" do + it "responds with status 404" do + get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png" + + expect(response.status).to eq(404) + end + end + end + end + end + end +end From cadf76562a7fc7d4f341c440ce3d5e301f4c87d1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 10:30:07 -0700 Subject: [PATCH 122/143] Fix highlight of selected lines --- CHANGELOG | 1 + app/assets/stylesheets/highlight/dark.scss | 4 ++-- app/assets/stylesheets/highlight/monokai.scss | 2 +- app/assets/stylesheets/highlight/solarized_dark.scss | 4 ++-- app/assets/stylesheets/highlight/solarized_light.scss | 4 ++-- app/assets/stylesheets/highlight/white.scss | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9b9e583255..635546e245 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -44,6 +44,7 @@ v 7.9.0 (unreleased) - Wrap commit message in EmailsOnPush email. - Send EmailsOnPush emails when deleting commits using force push. - Fix EmailsOnPush email comparison link to include first commit. + - Fix highliht of selected lines in file v 7.8.2 - Fix service migration issue when upgrading from versions prior to 7.3 diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss index fcd4d47bac..df95625716 100644 --- a/app/assets/stylesheets/highlight/dark.scss +++ b/app/assets/stylesheets/highlight/dark.scss @@ -13,8 +13,8 @@ } // highlight line via anchor - pre.hll { - background-color: #fff !important; + pre .hll { + background-color: #557 !important; } .hll { background-color: #373b41 } diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss index bcd2e71665..8f6b9edc7f 100644 --- a/app/assets/stylesheets/highlight/monokai.scss +++ b/app/assets/stylesheets/highlight/monokai.scss @@ -13,7 +13,7 @@ } // highlight line via anchor - pre.hll { + pre .hll { background-color: #49483e !important; } diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss index 4a6b759bd2..97926f906e 100644 --- a/app/assets/stylesheets/highlight/solarized_dark.scss +++ b/app/assets/stylesheets/highlight/solarized_dark.scss @@ -13,8 +13,8 @@ } // highlight line via anchor - pre.hll { - background-color: #073642 !important; + pre .hll { + background-color: #174652 !important; } /* Solarized Dark diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss index 7254f4d7ac..9398067781 100644 --- a/app/assets/stylesheets/highlight/solarized_light.scss +++ b/app/assets/stylesheets/highlight/solarized_light.scss @@ -13,8 +13,8 @@ } // highlight line via anchor - pre.hll { - background-color: #eee8d5 !important; + pre .hll { + background-color: #ddd8c5 !important; } /* Solarized Light diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss index 4d6f5dfd91..c8217d3e6b 100644 --- a/app/assets/stylesheets/highlight/white.scss +++ b/app/assets/stylesheets/highlight/white.scss @@ -13,7 +13,7 @@ } // highlight line via anchor - pre.hll { + pre .hll { background-color: #f8eec7 !important; } From 1178dacdb60e80d25700f984099dc6ce8dbf7efb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 10:50:53 -0700 Subject: [PATCH 123/143] Fix line highlight being hidden by header --- app/assets/javascripts/blob/blob.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/blob/blob.js.coffee b/app/assets/javascripts/blob/blob.js.coffee index a5f15f80c5..37a175fdbc 100644 --- a/app/assets/javascripts/blob/blob.js.coffee +++ b/app/assets/javascripts/blob/blob.js.coffee @@ -26,7 +26,7 @@ class @BlobView unless isNaN first_line $("#tree-content-holder .highlight .line").removeClass("hll") $("#LC#{line}").addClass("hll") for line in [first_line..last_line] - $.scrollTo("#L#{first_line}") unless e? + $.scrollTo("#L#{first_line}", offset: -50) unless e? # parse selected lines from hash # always return first and last line (initialized to NaN) From 02ed61c4db6fd6c20e3a23e525ccc3aef174a874 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Fri, 6 Mar 2015 21:09:14 +0200 Subject: [PATCH 124/143] remove duplication --- ...0150306023106_fix_namespace_duplication.rb | 21 +++++++++++++++++++ ...306023112_add_unique_index_to_namespace.rb | 4 ++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20150306023106_fix_namespace_duplication.rb diff --git a/db/migrate/20150306023106_fix_namespace_duplication.rb b/db/migrate/20150306023106_fix_namespace_duplication.rb new file mode 100644 index 0000000000..334e557455 --- /dev/null +++ b/db/migrate/20150306023106_fix_namespace_duplication.rb @@ -0,0 +1,21 @@ +class FixNamespaceDuplication < ActiveRecord::Migration + def up + #fixes path duplication + select_all('SELECT MAX(id) max, COUNT(id) cnt, path FROM namespaces GROUP BY path HAVING COUNT(id) > 1').each do |nms| + bad_nms_ids = select_all("SELECT id FROM namespaces WHERE path = '#{nms['path']}' AND id <> #{nms['max']}").map{|x| x["id"]} + execute("UPDATE projects SET namespace_id = #{nms["max"]} WHERE namespace_id IN(#{bad_nms_ids.join(', ')})") + execute("DELETE FROM namespaces WHERE id IN(#{bad_nms_ids.join(', ')})") + end + + #fixes name duplication + select_all('SELECT MAX(id) max, COUNT(id) cnt, name FROM namespaces GROUP BY name HAVING COUNT(id) > 1').each do |nms| + bad_nms_ids = select_all("SELECT id FROM namespaces WHERE name = '#{nms['name']}' AND id <> #{nms['max']}").map{|x| x["id"]} + execute("UPDATE projects SET namespace_id = #{nms["max"]} WHERE namespace_id IN(#{bad_nms_ids.join(', ')})") + execute("DELETE FROM namespaces WHERE id IN(#{bad_nms_ids.join(', ')})") + end + end + + def down + # not implemented + end +end diff --git a/db/migrate/20150306023112_add_unique_index_to_namespace.rb b/db/migrate/20150306023112_add_unique_index_to_namespace.rb index b1f7822b4d..6472138e3e 100644 --- a/db/migrate/20150306023112_add_unique_index_to_namespace.rb +++ b/db/migrate/20150306023112_add_unique_index_to_namespace.rb @@ -1,7 +1,7 @@ class AddUniqueIndexToNamespace < ActiveRecord::Migration def change - remove_index :namespaces, :name - remove_index :namespaces, :path + remove_index :namespaces, column: :name if index_exists?(:namespaces, :name) + remove_index :namespaces, column: :path if index_exists?(:namespaces, :path) add_index :namespaces, :name, unique: true add_index :namespaces, :path, unique: true From ae7e3806324fbe1ab63e68da823472fcbe31d652 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 12:03:04 -0700 Subject: [PATCH 125/143] Add active users to gitlab:check --- lib/tasks/gitlab/check.rake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 43115915de..976c4b5f22 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -29,6 +29,7 @@ namespace :gitlab do check_redis_version check_ruby_version check_git_version + check_active_users finished_checking "GitLab" end @@ -781,6 +782,10 @@ namespace :gitlab do end end + def check_active_users + puts "Active users: #{User.active.count}" + end + def omnibus_gitlab? Dir.pwd == '/opt/gitlab/embedded/service/gitlab-rails' end From 0d4328fd00617bd23cd91f212e964b86c70792f7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 12:03:35 -0700 Subject: [PATCH 126/143] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 9b9e583255..8428739a17 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -44,6 +44,7 @@ v 7.9.0 (unreleased) - Wrap commit message in EmailsOnPush email. - Send EmailsOnPush emails when deleting commits using force push. - Fix EmailsOnPush email comparison link to include first commit. + - Add GitLab active users count to rake gitlab:check v 7.8.2 - Fix service migration issue when upgrading from versions prior to 7.3 From c572bdb587bada094af867839a60a26a1fc1423e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 12:10:26 -0700 Subject: [PATCH 127/143] Add CHANGELOG item about db migration --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index a7b274eb1d..b1152a4038 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -46,6 +46,7 @@ v 7.9.0 (unreleased) - Fix EmailsOnPush email comparison link to include first commit. - Fix highliht of selected lines in file - Reject access to group/project avatar if the user doesn't have access. + - Add database migration to clean group duplicates with same path and name (Make sure you have a backup before update) v 7.8.2 - Fix service migration issue when upgrading from versions prior to 7.3 From ea7478d6b5a464d888a1aa7743a0076470f8bd3d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 12:59:39 -0700 Subject: [PATCH 128/143] Fix features checkboxes at admin settings page --- .../application_settings/_form.html.haml | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index ac64d26f9a..520f327f4e 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -8,22 +8,30 @@ %fieldset %legend Features .form-group - = f.label :signup_enabled, class: 'control-label col-sm-2' - .col-sm-10 - = f.check_box :signup_enabled, class: 'checkbox form-control' + .col-sm-offset-2.col-sm-10 + .checkbox + = f.label :signup_enabled do + = f.check_box :signup_enabled + Signin enabled .form-group - = f.label :signin_enabled, class: 'control-label col-sm-2' - .col-sm-10 - = f.check_box :signin_enabled, class: 'checkbox form-control' + .col-sm-offset-2.col-sm-10 + .checkbox + = f.label :signin_enabled do + = f.check_box :signin_enabled + Signup enabled .form-group - = f.label :gravatar_enabled, class: 'control-label col-sm-2' - .col-sm-10 - = f.check_box :gravatar_enabled, class: 'checkbox form-control' + .col-sm-offset-2.col-sm-10 + .checkbox + = f.label :gravatar_enabled do + = f.check_box :gravatar_enabled + Gravatar enabled .form-group - = f.label :twitter_sharing_enabled, "Twitter enabled", class: 'control-label col-sm-2' - .col-sm-10 - = f.check_box :twitter_sharing_enabled, class: 'checkbox form-control', :'aria-describedby' => 'twitter_help_block' - %span.help-block#twitter_help_block Show users a button to share their newly created public or internal projects on twitter + .col-sm-offset-2.col-sm-10 + .checkbox + = f.label :twitter_sharing_enabled do + = f.check_box :twitter_sharing_enabled, :'aria-describedby' => 'twitter_help_block' + %strong Twitter enabled + %span.help-block#twitter_help_block Show users a button to share their newly created public or internal projects on twitter %fieldset %legend Misc .form-group From 7fd4dc1e11e772095123008c79796202b5b7c80d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 13:17:16 -0700 Subject: [PATCH 129/143] Remove group rendering from dashboard page --- app/controllers/dashboard_controller.rb | 6 ------ app/views/dashboard/_groups.html.haml | 21 ------------------- app/views/dashboard/_sidebar.html.haml | 17 +-------------- .../_zero_authorized_projects.html.haml | 5 +++-- app/views/dashboard/groups/index.html.haml | 1 + app/views/dashboard/show.html.haml | 2 +- 6 files changed, 6 insertions(+), 46 deletions(-) delete mode 100644 app/views/dashboard/_groups.html.haml diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 8f06a67358..2822d510e5 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -5,15 +5,9 @@ class DashboardController < ApplicationController before_filter :event_filter, only: :show def show - @projects_limit = 20 - @groups = current_user.authorized_groups.order_name_asc - @has_authorized_projects = @projects.count > 0 - @projects_count = @projects.count @projects = @projects.includes(:namespace) @last_push = current_user.recent_push - @publicish_project_count = Project.publicish(current_user).count - respond_to do |format| format.html diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml deleted file mode 100644 index e3df43d889..0000000000 --- a/app/views/dashboard/_groups.html.haml +++ /dev/null @@ -1,21 +0,0 @@ -.panel.panel-default - .panel-heading.clearfix - .input-group - = search_field_tag :filter_group, nil, placeholder: 'Filter by name', class: 'dash-filter form-control' - - if current_user.can_create_group? - .input-group-addon.dash-new-group - = link_to new_group_path, class: "" do - %strong New group - %ul.well-list.dash-list - - groups.each do |group| - %li.group-row - = link_to group_path(id: group.path), class: dom_class(group) do - .dash-project-avatar - = image_tag group_icon(group.path), class: "avatar s40" - %span.group-name.filter-title - = truncate(group.name, length: 35) - %span.arrow - %i.fa.fa-angle-right - - if groups.blank? - %li - .nothing-here-block You have no groups yet. diff --git a/app/views/dashboard/_sidebar.html.haml b/app/views/dashboard/_sidebar.html.haml index 983da4aba0..78f695be91 100644 --- a/app/views/dashboard/_sidebar.html.haml +++ b/app/views/dashboard/_sidebar.html.haml @@ -1,18 +1,3 @@ -%ul.nav.nav-tabs.dash-sidebar-tabs - %li.active - = link_to '#projects', 'data-toggle' => 'tab', id: 'sidebar-projects-tab' do - Projects - %span.badge= @projects_count - %li - = link_to '#groups', 'data-toggle' => 'tab', id: 'sidebar-groups-tab' do - Groups - %span.badge= @groups.count - -.tab-content - .tab-pane.active#projects - = render "dashboard/projects", projects: @projects - .tab-pane#groups - = render "dashboard/groups", groups: @groups - += render "dashboard/projects", projects: @projects .prepend-top-20 = render 'shared/promo' diff --git a/app/views/dashboard/_zero_authorized_projects.html.haml b/app/views/dashboard/_zero_authorized_projects.html.haml index 6e76f95b34..4e7d663972 100644 --- a/app/views/dashboard/_zero_authorized_projects.html.haml +++ b/app/views/dashboard/_zero_authorized_projects.html.haml @@ -1,3 +1,4 @@ +- publicish_project_count = Project.publicish(current_user).count %h3.page-title Welcome to GitLab! %p.light Self hosted Git management application. %hr @@ -35,7 +36,7 @@ %i.fa.fa-plus New Group --if @publicish_project_count > 0 +-if publicish_project_count > 0 %hr %div .dashboard-intro-icon @@ -43,7 +44,7 @@ .dashboard-intro-text %p.slead There are - %strong= @publicish_project_count + %strong= publicish_project_count public projects on this server. %br Public projects are an easy way to allow everyone to have read-only access. diff --git a/app/views/dashboard/groups/index.html.haml b/app/views/dashboard/groups/index.html.haml index fd7bbb5500..50e90b1c17 100644 --- a/app/views/dashboard/groups/index.html.haml +++ b/app/views/dashboard/groups/index.html.haml @@ -27,6 +27,7 @@ %i.fa.fa-sign-out Leave + = image_tag group_icon(group.path), class: "avatar s40 avatar-tile" = link_to group, class: 'group-name' do %strong= group.name diff --git a/app/views/dashboard/show.html.haml b/app/views/dashboard/show.html.haml index f973f4829a..fa8946011b 100644 --- a/app/views/dashboard/show.html.haml +++ b/app/views/dashboard/show.html.haml @@ -1,4 +1,4 @@ -- if @has_authorized_projects +- if @projects.any? .dashboard.row %section.activities.col-md-8 = render 'activities' From 04c674e6792ad638dfb505f06f4cf9e980bb4a74 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 13:27:58 -0700 Subject: [PATCH 130/143] Cleanup after removing group tab from dashboard aside --- app/assets/javascripts/dashboard.js.coffee | 12 --------- app/assets/stylesheets/pages/dashboard.scss | 28 --------------------- 2 files changed, 40 deletions(-) diff --git a/app/assets/javascripts/dashboard.js.coffee b/app/assets/javascripts/dashboard.js.coffee index 3bdb9469d0..00ee503ff1 100644 --- a/app/assets/javascripts/dashboard.js.coffee +++ b/app/assets/javascripts/dashboard.js.coffee @@ -1,15 +1,3 @@ class @Dashboard constructor: -> - @initSidebarTab() new ProjectsList() - - initSidebarTab: -> - key = "dashboard_sidebar_filter" - - # store selection in cookie - $('.dash-sidebar-tabs a').on 'click', (e) -> - $.cookie(key, $(e.target).attr('id')) - - # show tab from cookie - sidebar_filter = $.cookie(key) - $("#" + sidebar_filter).tab('show') if sidebar_filter diff --git a/app/assets/stylesheets/pages/dashboard.scss b/app/assets/stylesheets/pages/dashboard.scss index 96f84b7122..5a543a852c 100644 --- a/app/assets/stylesheets/pages/dashboard.scss +++ b/app/assets/stylesheets/pages/dashboard.scss @@ -23,25 +23,6 @@ } } -.dash-sidebar-tabs { - margin-bottom: 2px; - border: none; - margin: 0 !important; - - li { - &.active { - a { - background-color: whitesmoke !important; - border-bottom: 1px solid whitesmoke !important; - } - } - - a { - border-color: #DDD !important; - } - } -} - .project-row, .group-row { padding: 0 !important; font-size: 14px; @@ -116,15 +97,6 @@ } } -.dash-new-group { - background: $gl-success; - border: 1px solid $gl-success; - - a { - color: #FFF; - } -} - .dash-list .str-truncated { max-width: 72%; } From 8527e8d5996bb5543cb5a13e857b864b466a31f2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 15:19:28 -0700 Subject: [PATCH 131/143] Fix test for creating group from dashboard --- features/dashboard/group.feature | 8 ++++++++ features/groups.feature | 8 -------- features/steps/dashboard/group.rb | 19 +++++++++++++++++++ features/steps/groups.rb | 19 ------------------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/features/dashboard/group.feature b/features/dashboard/group.feature index 92c1379ba7..cf4b8d7283 100644 --- a/features/dashboard/group.feature +++ b/features/dashboard/group.feature @@ -46,3 +46,11 @@ Feature: Dashboard Group When I visit dashboard groups page Then I should see group "Owned" in group list Then I should not see group "Guest" in group list + + Scenario: Create a group from dasboard + And I visit dashboard groups page + And I click new group link + And submit form with new group "Samurai" info + Then I should be redirected to group "Samurai" page + And I should see newly created group "Samurai" + diff --git a/features/groups.feature b/features/groups.feature index b5ff03db84..05546e0d6e 100644 --- a/features/groups.feature +++ b/features/groups.feature @@ -10,14 +10,6 @@ Feature: Groups Then I should see group "Owned" projects list And I should see projects activity feed - Scenario: Create a group from dasboard - When I visit group "Owned" page - And I visit dashboard page - And I click new group link - And submit form with new group "Samurai" info - Then I should be redirected to group "Samurai" page - And I should see newly created group "Samurai" - Scenario: I should see group "Owned" issues list Given project from group "Owned" has issues assigned to me When I visit group "Owned" issues page diff --git a/features/steps/dashboard/group.rb b/features/steps/dashboard/group.rb index 09d7717b67..8384df2fb5 100644 --- a/features/steps/dashboard/group.rb +++ b/features/steps/dashboard/group.rb @@ -41,4 +41,23 @@ class Spinach::Features::DashboardGroup < Spinach::FeatureSteps step 'I should not see group "Guest" in group list' do page.should_not have_content("Guest") end + + step 'I click new group link' do + click_link "New Group" + end + + step 'submit form with new group "Samurai" info' do + fill_in 'group_path', with: 'Samurai' + fill_in 'group_description', with: 'Tokugawa Shogunate' + click_button "Create group" + end + + step 'I should be redirected to group "Samurai" page' do + current_path.should == group_path(Group.find_by(name: 'Samurai')) + end + + step 'I should see newly created group "Samurai"' do + page.should have_content "Samurai" + page.should have_content "Tokugawa Shogunate" + end end diff --git a/features/steps/groups.rb b/features/steps/groups.rb index c3c34070e2..91921f5e21 100644 --- a/features/steps/groups.rb +++ b/features/steps/groups.rb @@ -72,25 +72,6 @@ class Spinach::Features::Groups < Spinach::FeatureSteps author: current_user end - When 'I click new group link' do - click_link "New group" - end - - step 'submit form with new group "Samurai" info' do - fill_in 'group_path', with: 'Samurai' - fill_in 'group_description', with: 'Tokugawa Shogunate' - click_button "Create group" - end - - step 'I should be redirected to group "Samurai" page' do - current_path.should == group_path(Group.find_by(name: 'Samurai')) - end - - step 'I should see newly created group "Samurai"' do - page.should have_content "Samurai" - page.should have_content "Tokugawa Shogunate" - end - step 'I change group "Owned" name to "new-name"' do fill_in 'group_name', with: 'new-name' fill_in 'group_path', with: 'new-name' From 83f7e98d9a672158d5c754307ab471fd50c5b2a3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 15:59:14 -0700 Subject: [PATCH 132/143] Add project filter by visibility and tag to explore page --- app/controllers/dashboard_controller.rb | 1 - .../explore/projects_controller.rb | 3 + app/helpers/dashboard_helper.rb | 16 --- app/helpers/explore_helper.rb | 17 +++ .../dashboard/_projects_filter.html.haml | 100 ------------------ app/views/explore/projects/_filter.html.haml | 67 ++++++++++++ app/views/explore/projects/index.html.haml | 27 +---- app/views/layouts/nav/_dashboard.html.haml | 1 - 8 files changed, 88 insertions(+), 144 deletions(-) create mode 100644 app/helpers/explore_helper.rb delete mode 100644 app/views/dashboard/_projects_filter.html.haml create mode 100644 app/views/explore/projects/_filter.html.haml diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 2822d510e5..b6e300e84b 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -36,7 +36,6 @@ class DashboardController < ApplicationController end @projects = @projects.where(namespace_id: Group.find_by(name: params[:group])) if params[:group].present? - @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present? @projects = @projects.includes(:namespace, :forked_from_project, :tags) @projects = @projects.tagged_with(params[:tag]) if params[:tag].present? @projects = @projects.sort(@sort = params[:sort]) diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb index 0e5891ae80..d664624fa6 100644 --- a/app/controllers/explore/projects_controller.rb +++ b/app/controllers/explore/projects_controller.rb @@ -6,6 +6,9 @@ class Explore::ProjectsController < ApplicationController def index @projects = ProjectsFinder.new.execute(current_user) + @tags = @projects.tags_on(:tags) + @projects = @projects.tagged_with(params[:tag]) if params[:tag].present? + @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present? @projects = @projects.search(params[:search]) if params[:search].present? @projects = @projects.sort(@sort = params[:sort]) @projects = @projects.includes(:namespace).page(params[:page]).per(20) diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb index 4dae96644c..c25b54eadc 100644 --- a/app/helpers/dashboard_helper.rb +++ b/app/helpers/dashboard_helper.rb @@ -1,20 +1,4 @@ module DashboardHelper - def projects_dashboard_filter_path(options={}) - exist_opts = { - sort: params[:sort], - scope: params[:scope], - group: params[:group], - tag: params[:tag], - visibility_level: params[:visibility_level], - } - - options = exist_opts.merge(options) - - path = request.path - path << "?#{options.to_param}" - path - end - def assigned_issues_dashboard_path issues_dashboard_path(assignee_id: current_user.id) end diff --git a/app/helpers/explore_helper.rb b/app/helpers/explore_helper.rb new file mode 100644 index 0000000000..7616fe6bad --- /dev/null +++ b/app/helpers/explore_helper.rb @@ -0,0 +1,17 @@ +module ExploreHelper + def explore_projects_filter_path(options={}) + exist_opts = { + sort: params[:sort], + scope: params[:scope], + group: params[:group], + tag: params[:tag], + visibility_level: params[:visibility_level], + } + + options = exist_opts.merge(options) + + path = request.path + path << "?#{options.to_param}" + path + end +end diff --git a/app/views/dashboard/_projects_filter.html.haml b/app/views/dashboard/_projects_filter.html.haml deleted file mode 100644 index d87ca861ae..0000000000 --- a/app/views/dashboard/_projects_filter.html.haml +++ /dev/null @@ -1,100 +0,0 @@ -.dash-projects-filters.append-bottom-20 - .append-right-20 - %ul.nav.nav-tabs - = nav_tab :scope, nil do - = link_to projects_dashboard_filter_path(scope: nil) do - All - = nav_tab :scope, 'personal' do - = link_to projects_dashboard_filter_path(scope: 'personal') do - Personal - = nav_tab :scope, 'joined' do - = link_to projects_dashboard_filter_path(scope: 'joined') do - Joined - = nav_tab :scope, 'owned' do - = link_to projects_dashboard_filter_path(scope: 'owned') do - Owned - - .dropdown.inline.append-right-10 - %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %i.fa.fa-globe - %span.light Visibility: - - if params[:visibility_level].present? - = visibility_level_label(params[:visibility_level].to_i) - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to projects_dashboard_filter_path(visibility_level: nil) do - Any - - Gitlab::VisibilityLevel.values.each do |level| - %li{ class: (level.to_s == params[:visibility_level]) ? 'active' : 'light' } - = link_to projects_dashboard_filter_path(visibility_level: level) do - = visibility_level_icon(level) - = visibility_level_label(level) - - - if @groups.present? - .dropdown.inline.append-right-10 - %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %i.fa.fa-group - %span.light Group: - - if params[:group].present? - = Group.find_by(name: params[:group]).name - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to projects_dashboard_filter_path(group: nil) do - Any - - @groups.each do |group| - %li{ class: (group.name == params[:group]) ? 'active' : 'light' } - = link_to projects_dashboard_filter_path(group: group.name) do - = group.name - %small.pull-right - = group.projects.count - - - - - if @tags.present? - .dropdown.inline.append-right-10 - %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %i.fa.fa-tags - %span.light Tags: - - if params[:tag].present? - = params[:tag] - - else - Any - %b.caret - %ul.dropdown-menu - %li - = link_to projects_dashboard_filter_path(tag: nil) do - Any - - - @tags.each do |tag| - %li{ class: (tag.name == params[:tag]) ? 'active' : 'light' } - = link_to projects_dashboard_filter_path(tag: tag.name) do - %i.fa.fa-tag - = tag.name - - .pull-right - .dropdown.inline - %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %span.light sort: - - if @sort.present? - = sort_options_hash[@sort] - - else - = sort_title_recently_created - %b.caret - %ul.dropdown-menu - %li - = link_to projects_dashboard_filter_path(sort: sort_value_recently_created) do - = sort_title_recently_created - = link_to projects_dashboard_filter_path(sort: sort_value_oldest_created) do - = sort_title_oldest_created - = link_to projects_dashboard_filter_path(sort: sort_value_recently_updated) do - = sort_title_recently_updated - = link_to projects_dashboard_filter_path(sort: sort_value_oldest_updated) do - = sort_title_oldest_updated - = link_to projects_dashboard_filter_path(sort: sort_value_name) do - = sort_title_name diff --git a/app/views/explore/projects/_filter.html.haml b/app/views/explore/projects/_filter.html.haml new file mode 100644 index 0000000000..b3963a9d90 --- /dev/null +++ b/app/views/explore/projects/_filter.html.haml @@ -0,0 +1,67 @@ +.pull-left + = 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 input-mn-300", id: "projects_search" + .form-group + = button_tag 'Search', class: "btn btn-primary wide" + +.pull-right.hidden-sm.hidden-xs + - if current_user + .dropdown.inline.append-right-10 + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %i.fa.fa-globe + %span.light Visibility: + - if params[:visibility_level].present? + = visibility_level_label(params[:visibility_level].to_i) + - else + Any + %b.caret + %ul.dropdown-menu + %li + = link_to explore_projects_filter_path(visibility_level: nil) do + Any + - Gitlab::VisibilityLevel.values.each do |level| + %li{ class: (level.to_s == params[:visibility_level]) ? 'active' : 'light' } + = link_to explore_projects_filter_path(visibility_level: level) do + = visibility_level_icon(level) + = visibility_level_label(level) + + - if @tags.present? + .dropdown.inline.append-right-10 + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %i.fa.fa-tags + %span.light Tags: + - if params[:tag].present? + = params[:tag] + - else + Any + %b.caret + %ul.dropdown-menu + %li + = link_to explore_projects_filter_path(tag: nil) do + Any + + - @tags.each do |tag| + %li{ class: (tag.name == params[:tag]) ? 'active' : 'light' } + = link_to explore_projects_filter_path(tag: tag.name) do + %i.fa.fa-tag + = tag.name + + .dropdown.inline + %button.dropdown-toggle.btn{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 + %li + = 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 + = sort_title_oldest_created + = link_to explore_projects_filter_path(sort: sort_value_recently_updated) do + = sort_title_recently_updated + = link_to explore_projects_filter_path(sort: sort_value_oldest_updated) do + = sort_title_oldest_updated diff --git a/app/views/explore/projects/index.html.haml b/app/views/explore/projects/index.html.haml index cb93b300d6..5086b58cd0 100644 --- a/app/views/explore/projects/index.html.haml +++ b/app/views/explore/projects/index.html.haml @@ -1,30 +1,5 @@ .clearfix - .pull-left - = form_tag explore_projects_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 input-mn-300", id: "projects_search" - .form-group - = button_tag 'Search', class: "btn btn-primary wide" - - .pull-right - .dropdown.inline - %button.dropdown-toggle.btn{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 - %li - = link_to explore_projects_path(sort: sort_value_recently_created) do - = sort_title_recently_created - = link_to explore_projects_path(sort: sort_value_oldest_created) do - = sort_title_oldest_created - = link_to explore_projects_path(sort: sort_value_recently_updated) do - = sort_title_recently_updated - = link_to explore_projects_path(sort: sort_value_oldest_updated) do - = sort_title_oldest_updated + = render 'filter' %hr .public-projects diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index b21f25e87c..c24dd4efc3 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -41,4 +41,3 @@ %i.fa.fa-question-circle %span Help - From 0414b2ae98180f1a462aae5300ba0fde94614cb4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 16:03:37 -0700 Subject: [PATCH 133/143] Remove projects page from dashboard --- app/controllers/dashboard_controller.rb | 22 -------- app/views/dashboard/projects.html.haml | 60 ---------------------- app/views/layouts/nav/_dashboard.html.haml | 5 -- config/routes.rb | 1 - features/dashboard/projects.feature | 9 ---- features/steps/dashboard/projects.rb | 11 ---- 6 files changed, 108 deletions(-) delete mode 100644 app/views/dashboard/projects.html.haml delete mode 100644 features/dashboard/projects.feature delete mode 100644 features/steps/dashboard/projects.rb diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index b6e300e84b..0500619909 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -23,28 +23,6 @@ class DashboardController < ApplicationController end end - def projects - @projects = case params[:scope] - when 'personal' then - current_user.namespace.projects - when 'joined' then - current_user.authorized_projects.joined(current_user) - when 'owned' then - current_user.owned_projects - else - current_user.authorized_projects - end - - @projects = @projects.where(namespace_id: Group.find_by(name: params[:group])) if params[:group].present? - @projects = @projects.includes(:namespace, :forked_from_project, :tags) - @projects = @projects.tagged_with(params[:tag]) if params[:tag].present? - @projects = @projects.sort(@sort = params[:sort]) - @projects = @projects.page(params[:page]).per(30) - - @tags = current_user.authorized_projects.tags_on(:tags) - @groups = current_user.authorized_groups - end - def merge_requests @merge_requests = get_merge_requests_collection @merge_requests = @merge_requests.page(params[:page]).per(20) diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml deleted file mode 100644 index 03d4b3d8bb..0000000000 --- a/app/views/dashboard/projects.html.haml +++ /dev/null @@ -1,60 +0,0 @@ -%h3.page-title - My Projects - - = link_to new_project_path, class: "btn btn-new pull-right" do - %i.fa.fa-plus - New Project - -%p.light - All projects you have access to are listed here. Public projects are not included here unless you are a member -%hr -.side-filters - = render "projects_filter" -.dash-projects - %ul.bordered-list.my-projects.top-list - - @projects.each do |project| - %li.my-project-row - %h4.project-title - .pull-left - = project_icon(project, alt: '', class: 'avatar project-avatar s60') - .project-access-icon - = visibility_level_icon(project.visibility_level) - = link_to project_path(project), class: dom_class(project) do - %strong= project.name_with_namespace - - - if project.forked_from_project -   - %small - %i.fa.fa-code-fork - Forked from: - = link_to project.forked_from_project.name_with_namespace, namespace_project_path(project.namespace, project.forked_from_project) - - - if current_user.can_leave_project?(project) - .pull-right - = link_to leave_namespace_project_team_members_path(project.namespace, project), data: { confirm: "Leave project?"}, method: :delete, remote: true, class: "btn-tiny btn remove-row", title: 'Leave project' do - %i.fa.fa-sign-out - Leave - - .project-info - .pull-right - - if project.archived? - %span.label - %i.fa.fa-archive - Archived - - project.tags.each do |tag| - %span.label.label-info - %i.fa.fa-tag - = tag.name - - if project.description.present? - %p= truncate project.description, length: 100 - .last-activity - %span.light Last activity: - %span.date= project_last_activity(project) - - - - if @projects.blank? - %li - .nothing-here-block There are no projects here. - .bottom - = paginate @projects, theme: "gitlab" - diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index c24dd4efc3..73b68d08e9 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -2,11 +2,6 @@ = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do = link_to root_path, title: 'Home', class: 'shortcuts-activity' do %i.fa.fa-dashboard - %span - Activity - = nav_link(path: 'dashboard#projects') do - = link_to projects_dashboard_path, title: 'Projects', class: 'shortcuts-projects' do - %i.fa.fa-cube %span Projects = nav_link(path: 'projects#starred') do diff --git a/config/routes.rb b/config/routes.rb index 637b855e66..889995e92a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -208,7 +208,6 @@ Gitlab::Application.routes.draw do # resource :dashboard, controller: 'dashboard', only: [:show] do member do - get :projects get :issues get :merge_requests end diff --git a/features/dashboard/projects.feature b/features/dashboard/projects.feature deleted file mode 100644 index bb4e84f015..0000000000 --- a/features/dashboard/projects.feature +++ /dev/null @@ -1,9 +0,0 @@ -@dashboard -Feature: Dashboard Projects - Background: - Given I sign in as a user - And I own project "Shop" - And I visit dashboard projects page - - Scenario: I should see projects list - Then I should see projects list diff --git a/features/steps/dashboard/projects.rb b/features/steps/dashboard/projects.rb deleted file mode 100644 index 2a34816306..0000000000 --- a/features/steps/dashboard/projects.rb +++ /dev/null @@ -1,11 +0,0 @@ -class Spinach::Features::DashboardProjects < Spinach::FeatureSteps - include SharedAuthentication - include SharedPaths - include SharedProject - - step 'I should see projects list' do - @user.authorized_projects.all.each do |project| - page.should have_link project.name_with_namespace - end - end -end From 9839d106c46a2c035c19337cfce0a905e2e1fea3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 16:06:30 -0700 Subject: [PATCH 134/143] Rename dashboard landing page to Your projects --- app/views/layouts/nav/_dashboard.html.haml | 2 +- features/steps/shared/active_tab.rb | 2 +- spec/features/security/dashboard_access_spec.rb | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index 73b68d08e9..e4f630c6a1 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -3,7 +3,7 @@ = link_to root_path, title: 'Home', class: 'shortcuts-activity' do %i.fa.fa-dashboard %span - Projects + Your Projects = nav_link(path: 'projects#starred') do = link_to starred_dashboard_projects_path, title: 'Starred Projects' do %i.fa.fa-star diff --git a/features/steps/shared/active_tab.rb b/features/steps/shared/active_tab.rb index c229864bc8..9beb688bd1 100644 --- a/features/steps/shared/active_tab.rb +++ b/features/steps/shared/active_tab.rb @@ -26,7 +26,7 @@ module SharedActiveTab end step 'the active main tab should be Home' do - ensure_active_main_tab('Activity') + ensure_active_main_tab('Your Projects') end step 'the active main tab should be Projects' do diff --git a/spec/features/security/dashboard_access_spec.rb b/spec/features/security/dashboard_access_spec.rb index 3d2d8a3502..67238e3ab7 100644 --- a/spec/features/security/dashboard_access_spec.rb +++ b/spec/features/security/dashboard_access_spec.rb @@ -25,8 +25,8 @@ describe "Dashboard access", feature: true do it { is_expected.to be_denied_for :visitor } end - describe "GET /dashboard/projects" do - subject { projects_dashboard_path } + describe "GET /dashboard/projects/starred" do + subject { starred_dashboard_projects_path } it { is_expected.to be_allowed_for :admin } it { is_expected.to be_allowed_for :user } From 6d0ff0ade8c136e1093a7f3336a58b361abdfd51 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Tue, 10 Mar 2015 18:09:13 -0700 Subject: [PATCH 135/143] Remove placeholder methods to prevent calling methods rather than attributes. --- app/models/project_services/issue_tracker_service.rb | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb index 0c734a544d..8e90c44d10 100644 --- a/app/models/project_services/issue_tracker_service.rb +++ b/app/models/project_services/issue_tracker_service.rb @@ -30,18 +30,6 @@ class IssueTrackerService < Service false end - def project_url - # implement inside child - end - - def issues_url - # implement inside child - end - - def new_issue_url - # implement inside child - end - def issue_url(iid) self.issues_url.gsub(':id', iid.to_s) end From 61ed518781cfc78bf1710286d84d4e74521f48d4 Mon Sep 17 00:00:00 2001 From: Vyacheslav Slinko Date: Fri, 2 Jan 2015 15:47:22 +0300 Subject: [PATCH 136/143] Make email display name configurable --- CHANGELOG | 3 ++- app/mailers/notify.rb | 2 +- config/gitlab.yml.example | 1 + config/initializers/1_settings.rb | 1 + spec/mailers/notify_spec.rb | 3 ++- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b210a6b015..52997ee8c9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -33,7 +33,8 @@ v 7.9.0 (unreleased) - Send notifications and leave system comments when bulk updating issues. - Automatically link commit ranges to compare page: sha1...sha4 or sha1..sha4 (includes sha1 in comparison) - Move groups page from profile to dashboard - - Starred projects page at dashboard + - Starred projects page at dashboard + - Make email display name configurable v 7.8.2 - Fix service migration issue when upgrading from versions prior to 7.3 diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 65925b61e9..ee27879cf4 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -53,7 +53,7 @@ class Notify < ActionMailer::Base # The default email address to send emails from def default_sender_address address = Mail::Address.new(Gitlab.config.gitlab.email_from) - address.display_name = "GitLab" + address.display_name = Gitlab.config.gitlab.email_display_name address end diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 6dff07cf9d..75d9e65aef 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -43,6 +43,7 @@ production: &base # email_enabled: true # Email address used in the "From" field in mails sent by GitLab email_from: example@example.com + email_display_name: GitLab # Email server smtp settings are in config/initializers/smtp_settings.rb.sample diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 6a8bbb80b9..70af7a829c 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -102,6 +102,7 @@ Settings.gitlab['relative_url_root'] ||= ENV['RAILS_RELATIVE_URL_ROOT'] || '' Settings.gitlab['protocol'] ||= Settings.gitlab.https ? "https" : "http" Settings.gitlab['email_enabled'] ||= true if Settings.gitlab['email_enabled'].nil? Settings.gitlab['email_from'] ||= "gitlab@#{Settings.gitlab.host}" +Settings.gitlab['email_display_name'] ||= "GitLab" Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url) Settings.gitlab['user'] ||= 'git' Settings.gitlab['user_home'] ||= begin diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 4090fa4620..b3c507ccbe 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -5,6 +5,7 @@ describe Notify do include EmailSpec::Matchers include RepoHelpers + let(:gitlab_sender_display_name) { Gitlab.config.gitlab.email_display_name } let(:gitlab_sender) { Gitlab.config.gitlab.email_from } let(:recipient) { create(:user, email: 'recipient@example.com') } let(:project) { create(:project) } @@ -23,7 +24,7 @@ describe Notify do shared_examples 'an email sent from GitLab' do it 'is sent from GitLab' do sender = subject.header[:from].addrs[0] - expect(sender.display_name).to eq('GitLab') + expect(sender.display_name).to eq(gitlab_sender_display_name) expect(sender.address).to eq(gitlab_sender) end end From 4b1bb42bf77328e2f80e40933d53037a1144bf0a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 21:56:19 -0700 Subject: [PATCH 137/143] Fix tests for project removing --- app/controllers/projects_controller.rb | 2 +- features/dashboard/archived_projects.feature | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 82b8a1cc13..fad692c7a3 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -105,7 +105,7 @@ class ProjectsController < ApplicationController if request.referer.include?('/admin') redirect_to admin_namespaces_projects_path else - redirect_to projects_dashboard_path + redirect_to dashboard_path end end end diff --git a/features/dashboard/archived_projects.feature b/features/dashboard/archived_projects.feature index 3af93bc373..69b3a77644 100644 --- a/features/dashboard/archived_projects.feature +++ b/features/dashboard/archived_projects.feature @@ -10,8 +10,3 @@ Feature: Dashboard Archived Projects Scenario: I should see non-archived projects on dashboard Then I should see "Shop" project link And I should not see "Forum" project link - - Scenario: I should see all projects on projects page - And I visit dashboard projects page - Then I should see "Shop" project link - And I should see "Forum" project link From 9ed71f77fee46fc489af8a6150cf12c1c6c468c1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Mar 2015 23:34:18 -0700 Subject: [PATCH 138/143] Remove tests for un-existing page --- features/project/archived.feature | 9 --------- 1 file changed, 9 deletions(-) diff --git a/features/project/archived.feature b/features/project/archived.feature index 9aac29384b..ad466f4f30 100644 --- a/features/project/archived.feature +++ b/features/project/archived.feature @@ -14,15 +14,6 @@ Feature: Project Archived And I visit project "Forum" page Then I should see "Archived" - Scenario: I should not see archived on projects page with no archived projects - And I visit dashboard projects page - Then I should not see "Archived" - - Scenario: I should see archived on projects page with archived projects - And project "Forum" is archived - And I visit dashboard projects page - Then I should see "Archived" - Scenario: I archive project When project "Shop" has push event And I visit project "Shop" page From 536d4373737cf5c4710d949fb4819d99faf2cdd7 Mon Sep 17 00:00:00 2001 From: Job van der Voort Date: Wed, 11 Mar 2015 17:31:39 +0100 Subject: [PATCH 139/143] add AMI update step --- doc/release/monthly.md | 4 ++++ doc/release/patch.md | 1 + 2 files changed, 5 insertions(+) diff --git a/doc/release/monthly.md b/doc/release/monthly.md index dd44c1eb86..a7e5faf2a6 100644 --- a/doc/release/monthly.md +++ b/doc/release/monthly.md @@ -200,3 +200,7 @@ Consider creating a post on Hacker News. ## Update GitLab.com with the stable version - Deploy the package (should not need downtime because of the small difference with RC1) + +## Release new AMIs + +[Follow this guide](https://dev.gitlab.org/gitlab/AMI/blob/master/README.md) diff --git a/doc/release/patch.md b/doc/release/patch.md index 80afa19b6c..5397343e71 100644 --- a/doc/release/patch.md +++ b/doc/release/patch.md @@ -54,3 +54,4 @@ CE=false be rake release['x.x.x'] 1. Create and publish a blog post, see [patch release blog template](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/doc/patch_release_blog_template.md) 1. Send tweets about the release from `@gitlab`, tweet should include the most important feature that the release is addressing and link to the blog post 1. Note in the 'GitLab X.X regressions' issue that the patch was published (CE only) +1. [Create new AMIs](https://dev.gitlab.org/gitlab/AMI/blob/master/README.md) From 88e4aed9df812eee9af2f27a975eeac894580042 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Wed, 11 Mar 2015 13:02:49 -0700 Subject: [PATCH 140/143] Update changelog for 7.8.4. --- CHANGELOG | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 03e3fb303e..90ed686448 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -52,6 +52,12 @@ v 7.9.0 (unreleased) - Starred projects page at dashboard - Make email display name configurable - Improve json validation in hook data +v 7.8.4 + - Fix issue_tracker_id substitution in custom issue trackers + - Fix path and name duplication in namespaces + +v 7.8.3 + - Bump version of gitlab_git fixing annotated tags without message v 7.8.2 - Fix service migration issue when upgrading from versions prior to 7.3 From 5c4f567ea021a48fa53ef6c1b235775ec511fe09 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 11 Mar 2015 13:52:55 -0700 Subject: [PATCH 141/143] Bump gitlab_git to v7.1.0. It should fix a lot of encoding issues --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 462c932584..7748026248 100644 --- a/Gemfile +++ b/Gemfile @@ -39,7 +39,7 @@ gem "browser" # Extracting information from a git repository # Provide access to Gitlab::Git library -gem "gitlab_git", '7.0.1' +gem "gitlab_git", '7.1.0' # Ruby/Rack Git Smart-HTTP Server Handler gem 'gitlab-grack', '~> 2.0.0.rc2', require: 'grack' diff --git a/Gemfile.lock b/Gemfile.lock index cca8f59ac2..1332e09647 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -213,7 +213,7 @@ GEM mime-types (~> 1.19) gitlab_emoji (0.0.1.1) emoji (~> 1.0.1) - gitlab_git (7.0.1) + gitlab_git (7.1.0) activesupport (~> 4.0) charlock_holmes (~> 0.6) gitlab-linguist (~> 3.0) @@ -607,7 +607,7 @@ GEM eventmachine (>= 1.0.0) rack (>= 1.0.0) thor (0.19.1) - thread_safe (0.3.4) + thread_safe (0.3.5) tilt (1.4.1) timers (4.0.1) hitimes @@ -708,7 +708,7 @@ DEPENDENCIES gitlab-grack (~> 2.0.0.rc2) gitlab-linguist (~> 3.0.1) gitlab_emoji (~> 0.0.1.1) - gitlab_git (= 7.0.1) + gitlab_git (= 7.1.0) gitlab_meta (= 7.0) gitlab_omniauth-ldap (= 1.2.0) gollum-lib (~> 4.0.0) From 5f40253f7696e920614328246120805fbf79d97c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 11 Mar 2015 16:07:33 -0700 Subject: [PATCH 142/143] Remove annoying notice messages when create/update merge request --- app/controllers/projects/merge_requests_controller.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 848cf36749..57c017e799 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -78,10 +78,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request = MergeRequests::CreateService.new(project, current_user, merge_request_params).execute if @merge_request.valid? - redirect_to( - merge_request_path(@merge_request), - notice: 'Merge request was successfully created.' - ) + redirect_to(merge_request_path(@merge_request)) else @source_project = @merge_request.source_project @target_project = @merge_request.target_project @@ -97,8 +94,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController format.js format.html do redirect_to([@merge_request.target_project.namespace.becomes(Namespace), - @merge_request.target_project, @merge_request], - notice: 'Merge request was successfully updated.') + @merge_request.target_project, @merge_request]) end format.json do render json: { From 66384d7d4434f9185dbe8bfe22cb7db974763ed3 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Wed, 11 Mar 2015 17:50:02 -0700 Subject: [PATCH 143/143] Add a note about building AMI to security doc --- doc/release/security.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/release/security.md b/doc/release/security.md index 1575fcf270..6ed2526449 100644 --- a/doc/release/security.md +++ b/doc/release/security.md @@ -18,6 +18,7 @@ Please report suspected security vulnerabilities in private to